From 68b7e05fa35e6818b234334997cc8f7635530b5c Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Tue, 26 Aug 2014 12:12:03 +0200 Subject: [PATCH] Refactor tag handling in task list: don't migrate kolab objects on read but only when changed (#3395); let drivers provide the full list of available tags --- .../database/tasklist_database_driver.php | 15 ++++++ .../drivers/kolab/tasklist_kolab_driver.php | 51 +++++++++++++------ plugins/tasklist/drivers/tasklist_driver.php | 7 +++ plugins/tasklist/tasklist.php | 28 ++++------ 4 files changed, 68 insertions(+), 33 deletions(-) diff --git a/plugins/tasklist/drivers/database/tasklist_database_driver.php b/plugins/tasklist/drivers/database/tasklist_database_driver.php index bd6bd1bb..9ec930a2 100644 --- a/plugins/tasklist/drivers/database/tasklist_database_driver.php +++ b/plugins/tasklist/drivers/database/tasklist_database_driver.php @@ -34,6 +34,7 @@ class tasklist_database_driver extends tasklist_driver private $plugin; private $lists = array(); private $list_ids = ''; + private $tags = array(); private $db_tasks = 'tasks'; private $db_lists = 'tasklists'; @@ -213,6 +214,16 @@ class tasklist_database_driver extends tasklist_driver return array(); } + /** + * Get a list of tags to assign tasks to + * + * @return array List of tags + */ + public function get_tags() + { + return array_values(array_unique($this->tags, SORT_STRING)); + } + /** * Get number of tasks matching the given filter * @@ -518,6 +529,10 @@ class tasklist_database_driver extends tasklist_driver $rec['recurrence'] = $this->unserialize_recurrence($rec['recurrence']); } + if (!empty($rec['tags'])) { + $this->tags = array_merge($this->tags, (array)$rec['tags']); + } + unset($rec['task_id'], $rec['tasklist_id'], $rec['created']); return $rec; } diff --git a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php index 1c8a8c77..f340b429 100644 --- a/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php +++ b/plugins/tasklist/drivers/kolab/tasklist_kolab_driver.php @@ -36,6 +36,7 @@ class tasklist_kolab_driver extends tasklist_driver private $lists; private $folders = array(); private $tasks = array(); + private $tags = array(); /** @@ -440,6 +441,20 @@ class tasklist_kolab_driver extends tasklist_driver return $this->get_lists(); } + /** + * Get a list of tags to assign tasks to + * + * @return array List of tags + */ + public function get_tags() + { + $config = kolab_storage_config::get_instance(); + $tags = $config->get_tags(); + $backend_tags = array_map(function($v) { return $v['name']; }, $tags); + + return array_values(array_unique(array_merge($this->tags, $backend_tags))); + } + /** * Get number of tasks matching the given filter * @@ -530,11 +545,15 @@ class tasklist_kolab_driver extends tasklist_driver $query[] = array('changed', '>=', $filter['since']); } + // load all tags into memory first + kolab_storage_config::get_instance()->get_tags(); + foreach ($lists as $list_id) { if (!$folder = $this->get_folder($list_id)) { continue; } foreach ($folder->select($query) as $record) { + $this->load_tags($record); $task = $this->_to_rcube_task($record); $task['list'] = $list_id; @@ -567,17 +586,13 @@ class tasklist_kolab_driver extends tasklist_driver if (is_numeric($list_id) || !$folder) continue; if (!$this->tasks[$id] && ($object = $folder->get_object($id))) { + $this->load_tags($object); $this->tasks[$id] = $this->_to_rcube_task($object); $this->tasks[$id]['list'] = $list_id; break; } } - // assign tags - if ($this->tasks[$id]) { - $this->tasks[$id]['tags'] = $this->get_tags($this->tasks[$id]['uid']); - } - return $this->tasks[$id]; } @@ -767,13 +782,21 @@ class tasklist_kolab_driver extends tasklist_driver /** * Get task tags */ - private function get_tags($uid) + private function load_tags(&$object) { - $config = kolab_storage_config::get_instance(); - $tags = $config->get_tags($uid); - $tags = array_map(function($v) { return $v['name']; }, $tags); - - return $tags; + // this task hasn't been migrated yet + if (!empty($object['categories'])) { + // OPTIONAL: call kolab_storage_config::apply_tags() to migrate the object + $object['tags'] = (array)$object['categories']; + if (!empty($object['tags'])) { + $this->tags = array_merge($this->tags, $object['tags']); + } + } + else { + $config = kolab_storage_config::get_instance(); + $tags = $config->get_tags($object['uid']); + $object['tags'] = array_map(function($v) { return $v['name']; }, $tags); + } } /** @@ -804,11 +827,7 @@ class tasklist_kolab_driver extends tasklist_driver 'attendees' => $record['attendees'], 'organizer' => $record['organizer'], 'sequence' => $record['sequence'], - // old categories will be replaced by tags - 'categories' => $record['categories'], - // keep mailbox which is needed to convert - // categories to tags in kolab_storage_config::apply_tags() - '_mailbox' => $record['_mailbox'], + 'tags' => $record['tags'], ); // convert from DateTime to internal date format diff --git a/plugins/tasklist/drivers/tasklist_driver.php b/plugins/tasklist/drivers/tasklist_driver.php index dd2e415f..2775539f 100644 --- a/plugins/tasklist/drivers/tasklist_driver.php +++ b/plugins/tasklist/drivers/tasklist_driver.php @@ -156,6 +156,13 @@ abstract class tasklist_driver */ abstract function list_tasks($filter, $lists = null); + /** + * Get a list of tags to assign tasks to + * + * @return array List of tags + */ + abstract function get_tags(); + /** * Get a list of pending alarms to be displayed to the user * diff --git a/plugins/tasklist/tasklist.php b/plugins/tasklist/tasklist.php index 4004a9ba..fe8c5c36 100644 --- a/plugins/tasklist/tasklist.php +++ b/plugins/tasklist/tasklist.php @@ -63,7 +63,6 @@ class tasklist extends rcube_plugin private $collapsed_tasks = array(); private $itip; private $ical; - private $driver_name; /** @@ -189,8 +188,6 @@ class tasklist extends rcube_plugin break; } - $this->driver_name = $driver_name; - $this->rc->output->set_env('tasklist_driver', $driver_name); } @@ -942,21 +939,22 @@ class tasklist extends rcube_plugin } */ - $data = $this->tasks_data($this->driver->list_tasks($filter, $lists), $f, $tags); - $this->rc->output->command('plugin.data_ready', array('filter' => $f, 'lists' => $lists, 'search' => $search, 'data' => $data, 'tags' => array_values(array_unique($tags)))); + $data = $this->tasks_data($this->driver->list_tasks($filter, $lists), $f); + $this->rc->output->command('plugin.data_ready', array( + 'filter' => $f, + 'lists' => $lists, + 'search' => $search, + 'data' => $data, + 'tags' => $this->driver->get_tags(), + )); } /** * Prepare and sort the given task records to be sent to the client */ - private function tasks_data($records, $f, &$tags) + private function tasks_data($records, $f) { - $data = $tags = $this->task_tree = $this->task_titles = array(); - - if ($this->driver_name == 'kolab') { - $config = kolab_storage_config::get_instance(); - $tags = $config->apply_tags($records); - } + $data = $this->task_tree = $this->task_titles = array(); foreach ($records as $rec) { if ($rec['parent_id']) { @@ -965,10 +963,6 @@ class tasklist extends rcube_plugin $this->encode_task($rec); - if ($this->driver_name != 'kolab' && !empty($rec['tags'])) { - $tags = array_merge($tags, (array)$rec['tags']); - } - // apply filter; don't trust the driver on this :-) if ((!$f && !$this->driver->is_complete($rec)) || ($rec['mask'] & $f)) $data[] = $rec; @@ -1221,7 +1215,7 @@ class tasklist extends rcube_plugin $updates = $this->driver->list_tasks($filter, $lists); if (!empty($updates)) { - $this->rc->output->command('plugin.refresh_tasks', $this->tasks_data($updates, 255, $tags), true); + $this->rc->output->command('plugin.refresh_tasks', $this->tasks_data($updates, 255), true); // update counts $counts = $this->driver->count_tasks($lists);