Page MenuHomePhorge

No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/kolab_sync_backend_common.php b/lib/kolab_sync_backend_common.php
index d72c908..ead546e 100644
--- a/lib/kolab_sync_backend_common.php
+++ b/lib/kolab_sync_backend_common.php
@@ -1,228 +1,235 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* Parent backend class for kolab backends
*/
class kolab_sync_backend_common implements Syncroton_Backend_IBackend
{
/**
* Table name
*
* @var string
*/
protected $table_name;
/**
* Model interface name
*
* @var string
*/
protected $interface_name;
/**
* Backend interface name
*
* @var string
*/
protected $class_name;
/**
* SQL Database engine
*
* @var rcube_db
*/
protected $db;
+ /**
+ * Internal cache (in-memory)
+ *
+ * @var array
+ */
+ protected $cache = array();
+
/**
* Constructor
*/
function __construct()
{
$this->db = rcube::get_instance()->get_dbh();
if (empty($this->class_name)) {
$this->class_name = str_replace('Model_I', 'Model_', $this->interface_name);
}
}
/**
* Creates new Syncroton object in database
*
* @param Syncroton_Model_* $object Object
*
* @throws InvalidArgumentException
* @return Syncroton_Model_* Object
*/
public function create($object)
{
if (! $object instanceof $this->interface_name) {
throw new InvalidArgumentException('$object must be instanace of ' . $this->interface_name);
}
$data = $this->object_to_array($object);
$insert = array();
$data['id'] = $object->id = sha1(mt_rand(). microtime());
foreach ($data as $key => $value) {
$insert[$this->db->quote_identifier($key)] = $this->db->quote($value);
}
$this->db->query('INSERT INTO ' . $this->table_name
. ' (' . implode(', ', array_keys($insert)) . ')' . ' VALUES(' . implode(', ', $insert) . ')');
if (!$this->db->insert_id($this->table_name)) {
// @TODO: throw exception
}
return $object;
}
/**
* Returns Syncroton data object
*
* @param string $id
* @throws Syncroton_Exception_NotFound
* @return Syncroton_Model_*
*/
public function get($id)
{
$id = $id instanceof $this->interface_name ? $id->id : $id;
$select = $this->db->query('SELECT * FROM ' . $this->table_name . ' WHERE id = ?', array($id));
$data = $this->db->fetch_assoc($select);
if (empty($data)) {
throw new Syncroton_Exception_NotFound('Object not found');
}
return $this->get_object($data);
}
/**
* Deletes Syncroton data object
*
* @param string|Syncroton_Model_* $id Object or identifier
*
* @return bool True on success, False on failure
*/
public function delete($id)
{
$id = $id instanceof $this->interface_name ? $id->id : $id;
$result = $this->db->query('DELETE FROM ' . $this->table_name .' WHERE id = ?', array($id));
return (bool) $this->db->affected_rows($result);
}
/**
* Updates Syncroton data object
*
* @param Syncroton_Model_* $object
*
* @throws InvalidArgumentException
* @return Syncroton_Model_* Object
*/
public function update($object)
{
if (! $object instanceof $this->interface_name) {
throw new InvalidArgumentException('$object must be instanace of ' . $this->interface_name);
}
$data = $this->object_to_array($object);
$set = array();
foreach ($data as $key => $value) {
$set[] = $this->db->quote_identifier($key) . ' = ' . $this->db->quote($value);
}
$this->db->query('UPDATE ' . $this->table_name . ' SET ' . implode(', ', $set)
. ' WHERE ' . $this->db->quote_identifier('id') . ' = ' . $this->db->quote($object->id));
return $object;
}
/**
* Convert array into model object
*/
protected function get_object($data)
{
foreach ($data as $key => $value) {
unset($data[$key]);
if (!empty($value) && preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $value)) { // 2012-08-12 07:43:26
$value = new DateTime($value, new DateTimeZone('utc'));
}
$data[$this->to_camelcase($key, false)] = $value;
}
return new $this->class_name($data);
}
/**
* Converts model object into array
*/
protected function object_to_array($object)
{
$data = array();
foreach ($object as $key => $value) {
if ($value instanceof DateTime) {
$value = $value->format('Y-m-d H:i:s');
} elseif (is_object($value) && isset($value->id)) {
$value = $value->id;
}
$data[$this->from_camelcase($key)] = $value;
}
return $data;
}
/**
* Convert property name from camel-case to lower-case-with-underscore
*/
protected function from_camelcase($string)
{
$string = lcfirst($string);
return preg_replace_callback('/([A-Z])/', function ($string) { return '_' . strtolower($string[0]); }, $string);
}
/**
* Convert property name from lower-case-with-underscore to camel-case
*/
protected function to_camelcase($string, $ucFirst = true)
{
if ($ucFirst) {
$string = ucfirst($string);
}
return preg_replace_callback('/_([a-z])/', function ($string) { return strtoupper($string[1]); }, $string);
}
}
diff --git a/lib/kolab_sync_backend_content.php b/lib/kolab_sync_backend_content.php
index 72a673e..246dcba 100644
--- a/lib/kolab_sync_backend_content.php
+++ b/lib/kolab_sync_backend_content.php
@@ -1,118 +1,132 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* Kolab backend class for content storage
*/
class kolab_sync_backend_content extends kolab_sync_backend_common implements Syncroton_Backend_IContent
{
protected $table_name = 'syncroton_content';
protected $interface_name = 'Syncroton_Model_IContent';
/**
* mark state as deleted. The state gets removed finally,
* when the synckey gets validated during next sync.
*
* @param Syncroton_Model_IContent|string $id
*/
public function delete($id)
{
$id = $id instanceof Syncroton_Model_IContent ? $id->id : $id;
$result = $this->db->query('UPDATE ' . $this->table_name . ' SET is_deleted = 1 WHERE id = ?', array($id));
- return (bool) $this->db->affected_rows($result);
+ if ($result = (bool) $this->db->affected_rows($result)) {
+ unset($this->cache['content_folderstate']);
+ }
+
+ return $result;
}
/**
* @param Syncroton_Model_IDevice|string $_deviceId
* @param Syncroton_Model_IFolder|string $_folderId
* @param string $_contentId
* @return Syncroton_Model_IContent
*/
public function getContentState($_deviceId, $_folderId, $_contentId)
{
$deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
$folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
$where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
$where[] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
$where[] = $this->db->quote_identifier('contentid') . ' = ' . $this->db->quote($_contentId);
$where[] = $this->db->quote_identifier('is_deleted') . ' = 0';
$select = $this->db->query('SELECT * FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
$state = $this->db->fetch_assoc($select);
if (empty($state)) {
throw new Syncroton_Exception_NotFound('Content not found');
}
return $this->get_object($state);
}
/**
* get array of ids which got send to the client for a given class
*
* @param Syncroton_Model_IDevice|string $_deviceId
* @param Syncroton_Model_IFolder|string $_folderId
* @return array
*/
public function getFolderState($_deviceId, $_folderId)
{
$deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
$folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+ $cachekey = $deviceId . ':' . $folderId;
+
+ // in Sync request we call this function twice in case when
+ // folder state changed - use cache to skip at least one SELECT query
+ if (isset($this->cache['content_folderstate'][$cache_key])) {
+ return $this->cache['content_folderstate'][$cache_key];
+ }
$where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
$where[] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
$where[] = $this->db->quote_identifier('is_deleted') . ' = 0';
$select = $this->db->query('SELECT contentid FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
$result = array();
while ($state = $this->db->fetch_assoc($select)) {
$result[] = $state['contentid'];
}
- return $result;
+ return $this->cache['content_folderstate'][$cache_key] = $result;
}
/**
* reset list of stored id
*
* @param Syncroton_Model_IDevice|string $_deviceId
* @param Syncroton_Model_IFolder|string $_folderId
*/
public function resetState($_deviceId, $_folderId)
{
$deviceId = $_deviceId instanceof Syncroton_Model_IDevice ? $_deviceId->id : $_deviceId;
$folderId = $_folderId instanceof Syncroton_Model_IFolder ? $_folderId->id : $_folderId;
+ $cachekey = $deviceId . ':' . $folderId;
+
+ unset($this->cache['content_folderstate'][$cache_key]);
$where[] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($deviceId);
$where[] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folderId);
$this->db->query('DELETE FROM ' . $this->table_name .' WHERE ' . implode(' AND ', $where));
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Mar 19, 8:41 AM (20 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
456907
Default Alt Text
(13 KB)

Event Timeline