lib/kolab_sync_data_notes.php lib/kolab_sync_data.php lib/kolab_sync_data_tasks.php

Aleksander Machniak machniak at kolabsys.com
Fri Aug 22 14:01:32 CEST 2014


 lib/kolab_sync_data.php       |  165 ++++++++++++++++++++++++++++++++++++++----
 lib/kolab_sync_data_notes.php |   10 ++
 lib/kolab_sync_data_tasks.php |    9 ++
 3 files changed, 169 insertions(+), 15 deletions(-)

New commits:
commit ce151cada2d0fe73c2cdf903d613028f06729a88
Author: Aleksander Machniak <alec at alec.pl>
Date:   Fri Aug 22 14:01:13 2014 +0200

    Implement tags based on Relation objects (#3473)

diff --git a/lib/kolab_sync_data.php b/lib/kolab_sync_data.php
index 7fdee71..55fe439 100644
--- a/lib/kolab_sync_data.php
+++ b/lib/kolab_sync_data.php
@@ -511,9 +511,9 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     /**
      * Search for existing entries
      *
-     * @param string $folderid
-     * @param array  $filter
-     * @param int    $result_type  Type of the result (see RESULT_* constants)
+     * @param string $folderid    Folder identifier
+     * @param array  $filter      Search filter
+     * @param int    $result_type Type of the result (see RESULT_* constants)
      *
      * @return array|int  Search result as count or array of uids/objects
      */
@@ -543,13 +543,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         foreach ($folders as $folderid) {
             $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
 
-            if ($foldername === null) {
-                continue;
-            }
-
-            $folder = $this->getFolderObject($foldername);
-
-            if (!$folder) {
+            if ($foldername === null || !($folder = $this->getFolderObject($foldername))) {
                 continue;
             }
 
@@ -589,10 +583,105 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
             throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR);
         }
 
+        // consider Tag object modifications if needed
+        if ($this->tag_categories) {
+            $this->searchEntriesByTagChanges($filter, $folders, $result_type, $result);
+        }
+
         return $result;
     }
 
     /**
+     * Checks if any Tags have been modified in specified time
+     * and returns UIDs (or count) of objects assigned to them
+     */
+    protected function searchEntriesByTagChanges($filter, $folders, $result_type, &$result)
+    {
+        $tag_filter = array();
+        $obj_filter = array();
+
+        // get period filter, create new objects filter
+        foreach ($filter as $f) {
+            if ($f[0] == 'changed') {
+                $tag_filter[] = $f;
+            }
+            else {
+                $obj_filter[] = $f;
+            }
+        }
+
+        // this is not search for changes, do nothing
+        if (empty($tag_filter)) {
+            return;
+        }
+
+        // we're detecting changes here, let's check if any tags have been modified
+        // we're covering here cases when tag name or tag assignment has been changed
+
+        $config  = kolab_storage_config::get_instance();
+        $members = array();
+        $default = true;
+        $filter  = array(
+            array('type', '=', 'relation'),
+            array('category', '=', 'tag')
+        );
+
+        $filter = array_merge($filter, $tag_filter);
+        $tags   = $config->get_objects($filter, $default, 100);
+
+        // get UIDs of tag members
+        foreach ($tags as $tag) {
+            foreach ((array)$tag['members'] as $url) {
+                if (strpos($url, 'urn:uuid:') === 0) {
+                    $members[] = substr($url, 9);
+                }
+            }
+        }
+
+        $members = array_unique($members);
+
+        // if we have UIDs in result already we can remove them here
+        // FIXME: if the result is an int we can end up
+        // with wrong result (some objects might be counted twice)
+        if ($result_type == self::RESULT_UID) {
+            $members = array_diff($members, $result);
+        }
+
+        if (empty($members)) {
+            return;
+        }
+
+        // search objects mathing current filter,
+        // tags/relations may contain members of many types, we need to
+        // search them by UID in all requested folders to get
+        // only these with requested type (and that really exist)
+        $obj_filter[] = array('uid', '=', $members);
+
+        foreach ($folders as $folderid) {
+            $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
+
+            if ($foldername === null || !($folder = $this->getFolderObject($foldername))) {
+                continue;
+            }
+
+            switch ($result_type) {
+            case self::RESULT_COUNT:
+                $count = $folder->count($obj_filter);
+                $result += (int) $count;
+                break;
+
+            case self::RESULT_UID:
+                $uids = $folder->get_uids($obj_filter);
+
+                if (is_array($uids)) {
+                    $result = array_merge($result, $uids);
+                }
+                break;
+            }
+        }
+    }
+
+    /**
      * Returns filter query array according to specified ActiveSync FilterType
      *
      * @param int $filter_type  Filter type
@@ -628,7 +717,7 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     }
 
     /**
-     * get count of entries changed between two dates
+     * Get count of entries changed between two dates
      *
      * @param string   $folderId
      * @param DateTime $start
@@ -774,10 +863,20 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
             $folderid = isset($default['realid']) ? $default['realid'] : $default['serverId'];
         }
 
+        // convert categories into tags, save them after creating an object
+        if ($this->tag_categories) {
+            $tags = $data['categories'];
+            unset($data['categories']);
+        }
+
         $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid);
         $folder     = $this->getFolderObject($foldername);
 
         if ($folder && $folder->save($data)) {
+            if (!empty($tags)) {
+                $this->setKolabTags($data['uid'], $tags);
+            }
+
             return $data;
         }
     }
@@ -792,7 +891,17 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
         if ($object) {
             $folder = $this->getFolderObject($object['_mailbox']);
 
+            // convert categories into tags, save them after updating an object
+            if ($this->tag_categories && array_key_exists('categories', $data)) {
+                $tags = (array) $data['categories'];
+                unset($data['categories']);
+            }
+
             if ($folder && $folder->save($data)) {
+                if (isset($tags)) {
+                    $this->setKolabTags($data['uid'], $tags);
+                }
+
                 return $data;
             }
         }
@@ -807,7 +916,16 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
 
         if ($object) {
             $folder = $this->getFolderObject($object['_mailbox']);
-            return $folder && $folder->delete($entryid);
+
+            if ($folder && $folder->delete($entryid)) {
+                if ($this->tag_categories) {
+                    $this->setKolabTags($object['uid'], null);
+                }
+
+                return true;
+            }
+
+            return false;
         }
 
         // object doesn't exist, confirm deletion
@@ -1515,6 +1633,29 @@ abstract class kolab_sync_data implements Syncroton_Data_IData
     }
 
     /**
+     * Returns list of tag names assigned to kolab object
+     */
+    protected function getKolabTags($uid)
+    {
+        $config = kolab_storage_config::get_instance();
+        $tags   = $config->get_tags($uid);
+        $tags   = array_filter(array_map(function($v) { return $v['name']; }, $tags));
+
+        return !empty($tags) ? $tags : null;
+    }
+
+    /**
+     * Set tags to kolab object
+     */
+    protected function setKolabTags($uid, $tags)
+    {
+        if (isset($data->categories)) {
+            $config = kolab_storage_config::get_instance();
+            $config->save_tags($uid, $tags);
+        }
+    }
+
+    /**
      * Converts string of days (TU,TH) to bitmask used by ActiveSync
      *
      * @param string $days
diff --git a/lib/kolab_sync_data_notes.php b/lib/kolab_sync_data_notes.php
index 2e442be..8c6ad92 100644
--- a/lib/kolab_sync_data_notes.php
+++ b/lib/kolab_sync_data_notes.php
@@ -39,8 +39,6 @@ class kolab_sync_data_notes extends kolab_sync_data
         'subject'          => 'title',
     );
 
-
-
     /**
      * Kolab object type
      *
@@ -69,6 +67,11 @@ class kolab_sync_data_notes extends kolab_sync_data
      */
     protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED;
 
+    /**
+     * Enable mapping Activesync categories into Kolab tags (relations)
+     */
+    protected $tag_categories = true;
+
 
     /**
      * Appends note data to xml element
@@ -108,6 +111,9 @@ class kolab_sync_data_notes extends kolab_sync_data
 
         $result['messageClass'] = 'IPM.StickyNote';
 
+        // convert kolab tags into categories
+        $result['categories'] = $this->getKolabTags($note['uid']);
+
         return $as_array ? $result : new Syncroton_Model_Note($result);
     }
 
diff --git a/lib/kolab_sync_data_tasks.php b/lib/kolab_sync_data_tasks.php
index e524c00..5e20178 100644
--- a/lib/kolab_sync_data_tasks.php
+++ b/lib/kolab_sync_data_tasks.php
@@ -67,7 +67,6 @@ class kolab_sync_data_tasks extends kolab_sync_data
         'confidential' => self::SENSITIVITY_CONFIDENTIAL,
     );
 
-
     /**
      * Kolab object type
      *
@@ -96,6 +95,11 @@ class kolab_sync_data_tasks extends kolab_sync_data
      */
     protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_TASK_USER_CREATED;
 
+    /**
+     * Enable mapping Activesync categories into Kolab tags (relations)
+     */
+    protected $tag_categories = true;
+
 
     /**
      * Appends contact data to xml element
@@ -151,6 +155,9 @@ class kolab_sync_data_tasks extends kolab_sync_data
             $result[$key] = $value;
         }
 
+        // convert kolab tags into categories
+        $result['categories'] = $this->getKolabTags($task['uid']);
+
         // Recurrence
         $this->recurrence_from_kolab($collection, $task, $result, 'Task');
 




More information about the commits mailing list