From 6f67441ec6ff3fe9abb2f0b9c160ccd7c3577dd0 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 1/8] Cleaned with php-cs. --- CollectionTreePlugin.php | 59 +++++++++---------- controllers/IndexController.php | 4 +- models/CollectionTree.php | 12 ++-- models/Table/CollectionTree.php | 21 +++---- .../collection-tree-parent-form.php | 10 +++- .../plugins/collection-tree-config-form.php | 28 ++++++--- views/helpers/CollectionTreeFullList.php | 2 +- 7 files changed, 76 insertions(+), 60 deletions(-) diff --git a/CollectionTreePlugin.php b/CollectionTreePlugin.php index 8bcfe5c..7134e64 100644 --- a/CollectionTreePlugin.php +++ b/CollectionTreePlugin.php @@ -1,14 +1,14 @@ _db->CollectionTree}` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `parent_collection_id` int(10) unsigned NOT NULL, @@ -90,7 +90,7 @@ public function hookInstall() $collectionTree->save(); } } - + /** * Uninstall the plugin. */ @@ -101,7 +101,7 @@ public function hookUninstall() $this->_uninstallOptions(); } - + /** * Initialize the plugin. */ @@ -110,22 +110,22 @@ public function hookInitialize() // Add translation. add_translation_source(dirname(__FILE__) . '/languages'); } - + /** * Upgrade from earlier versions. */ public function hookUpgrade($args) { - // Prior to Omeka 2.0, collection names were stored in the collections - // table; now they are stored as Dublin Core Title. This upgrade - // compensates for this by moving the collection names to the + // Prior to Omeka 2.0, collection names were stored in the collections + // table; now they are stored as Dublin Core Title. This upgrade + // compensates for this by moving the collection names to the // collection_trees table. if (version_compare($args['old_version'], '2.0', '<')) { - + // Add the name column to the collection_trees table. $sql = "ALTER TABLE {$this->_db->CollectionTree} ADD `name` TEXT NULL"; $this->_db->query($sql); - + // Assign names to their corresponding collection_tree rows. $collectionTreeTable = $this->_db->getTable('CollectionTree'); $collectionTable = $this->_db->getTable('Collection'); @@ -182,7 +182,7 @@ public function hookBeforeSaveCollection($args) } } } - + /** * Save the parent/child relationship. */ @@ -196,18 +196,18 @@ public function hookAfterSaveCollection($args) $collectionTree->collection_id = $collection->id; $collectionTree->parent_collection_id = 0; } - + // Only save the relationship during a form submission. if (isset($args['post']['collection_tree_parent_collection_id'])) { $collectionTree->parent_collection_id = $args['post']['collection_tree_parent_collection_id']; } - + $collectionTree->name = metadata($args['record'], array('Dublin Core', 'Title')); - + // Fail silently if the record does not validate. $collectionTree->save(); } - + /** * Handle collection deletions. * @@ -220,13 +220,13 @@ public function hookAfterDeleteCollection($args) { $collection = $args['record']; $collectionTreeTable = $this->_db->getTable('CollectionTree'); - + // Delete the relationship with the parent collection. $collectionTree = $collectionTreeTable->findByCollectionId($collection->id); if ($collectionTree) { $collectionTree->delete(); } - + // Move child collections to root level by deleting their relationships. $collectionTrees = $collectionTreeTable->findByParentCollectionId($collection->id); foreach ($collectionTrees as $collectionTree) { @@ -273,7 +273,7 @@ public function hookItemsBrowseSql($args) // Collection can be an object when not called from search form. ? $params['descendant_or_self']->id // Else this should be an integer. - : (integer) $params['descendant_or_self']; + : (int) $params['descendant_or_self']; if (empty($collection)) { return; @@ -288,7 +288,8 @@ public function hookItemsBrowseSql($args) $select->joinInner( array('collection_tree_collections' => $this->_db->Collection), 'items.collection_id = collection_tree_collections.id', - array()); + array() + ); // There are descendants. if (count($collections) > 1) { @@ -352,16 +353,16 @@ public function hookPublicCollectionsShow($args) { $this->_appendToCollectionsShow($args['collection']); } - + protected function _appendToCollectionsShow($collection) { $collectionTree = $this->_db->getTable('CollectionTree')->getCollectionTree($collection->id); echo get_view()->partial( - 'collections/collection-tree-list.php', + 'collections/collection-tree-list.php', array('collection_tree' => $collectionTree) ); } - + /** * Add the collection tree page to the admin navigation. */ @@ -370,7 +371,7 @@ public function filterAdminNavigationMain($nav) $nav[] = array('label' => __('Collection Tree'), 'uri' => url('collection-tree')); return $nav; } - + /** * Add the collection tree page to the public navigation. */ @@ -379,7 +380,7 @@ public function filterPublicNavigationMain($nav) $nav[] = array('label' => __('Collection Tree'), 'uri' => url('collection-tree')); return $nav; } - + /** * Display the parent collection form. */ @@ -387,7 +388,7 @@ public function filterAdminCollectionsFormTabs($tabs, $args) { $collection = $args['collection']; $collectionTreeTable = $this->_db->getTable('CollectionTree'); - + $options = $collectionTreeTable->findPairsForSelectForm(); $options = array('0' => __('No parent collection')) + $options; @@ -398,13 +399,12 @@ public function filterAdminCollectionsFormTabs($tabs, $args) $parentCollectionId = 0; } $tabs['Parent Collection'] = get_view()->partial( - 'collections/collection-tree-parent-form.php', + 'collections/collection-tree-parent-form.php', array('options' => $options, 'parent_collection_id' => $parentCollectionId) ); return $tabs; } - /** * Filter items browse params to broaden the search to subcollections. * @@ -418,7 +418,7 @@ public function filterItemsBrowseParams($params) && !isset($params['subcollections']) && get_option('collection_tree_show_subcollections') ) { - $params['subcollections'] = 1; + $params['subcollections'] = 1; } if (!empty($params['subcollections'])) { @@ -439,7 +439,6 @@ public function filterItemsBrowseParams($params) return $params; } - /** * Manage search options for collections. * diff --git a/controllers/IndexController.php b/controllers/IndexController.php index 4fedef7..8521a9f 100644 --- a/controllers/IndexController.php +++ b/controllers/IndexController.php @@ -1,14 +1,14 @@ collection_id == $this->parent_collection_id) { $this->addError( - __('Parent Collection'), + __('Parent Collection'), __('A collection cannot be a parent to itself.') ); } - + $unassignableCollectionIds = $this->getTable()->getUnassignableCollectionIds($this->collection_id); if (in_array($this->parent_collection_id, $unassignableCollectionIds)) { $this->addError( - __('Parent Collection'), + __('Parent Collection'), __('A collection cannot be assigned to a collection in its descendant tree.') ); } diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index 08f6540..989de4a 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -1,14 +1,14 @@ joinLeft( array($alias => $this->getTableName()), "$aliasCollection.id = $alias.collection_id", - array('name')); + array('name') + ); $select->where("$aliasCollection.id != ?", $collectionId); // If not a new collection, cache descendant collection IDs and exclude @@ -133,7 +134,6 @@ public function findPairsForSelectForm(array $options = array(), $padding = '-') $options = array(); foreach ($this->getRootCollections() as $rootCollectionId => $rootCollection) { - $options[$rootCollectionId] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); $this->_resetCache(); @@ -228,7 +228,6 @@ public function getDescendantTree($collectionId, $cacheDescendantInfo = false, $ // Iterate the child collections. $descendantTree = array_values($this->getChildCollections($collectionId)); for ($i = 0; $i < count($descendantTree); $i++) { - if ($cacheDescendantInfo) { $this->_cache[$descendantTree[$i]['id']] = $collectionDepth; } @@ -237,7 +236,8 @@ public function getDescendantTree($collectionId, $cacheDescendantInfo = false, $ $children = $this->getDescendantTree( $descendantTree[$i]['id'], $cacheDescendantInfo, - $collectionDepth); + $collectionDepth + ); // Assign the child collections to the descendant tree. if ($children) { @@ -321,10 +321,10 @@ public function getRootCollections() /** * Get all collection IDs to which the passed collection cannot be assigned. - * - * A collection cannot be assigned to a collection in its descendant tree, + * + * A collection cannot be assigned to a collection in its descendant tree, * including itself. - * + * * @param int $collectionId * @return array */ @@ -352,7 +352,8 @@ protected function _getCollections() $select->joinLeft( array($alias => $this->getTableName()), "$aliasCollection.id = $alias.collection_id", - array('parent_collection_id', 'name')); + array('parent_collection_id', 'name') + ); // Order alphabetically if configured to do so. if (get_option('collection_tree_alpha_order')) { diff --git a/views/admin/collections/collection-tree-parent-form.php b/views/admin/collections/collection-tree-parent-form.php index 9e01ee8..1e9a8cc 100644 --- a/views/admin/collections/collection-tree-parent-form.php +++ b/views/admin/collections/collection-tree-parent-form.php @@ -3,9 +3,13 @@
-

- formSelect('collection_tree_parent_collection_id', - $parent_collection_id, null, $options); ?> + formSelect( + 'collection_tree_parent_collection_id', + $parent_collection_id, + null, + $options + ); ?>
diff --git a/views/admin/plugins/collection-tree-config-form.php b/views/admin/plugins/collection-tree-config-form.php index 6798c10..869652d 100644 --- a/views/admin/plugins/collection-tree-config-form.php +++ b/views/admin/plugins/collection-tree-config-form.php @@ -7,8 +7,11 @@ echo __('Order the collection tree alphabetically?'); echo __('This does not affect the order of the collections browse page.'); ?>

- formCheckbox('collection_tree_alpha_order', null, - array('checked' => (bool) get_option('collection_tree_alpha_order'))); ?> + formCheckbox( + 'collection_tree_alpha_order', + null, + array('checked' => (bool) get_option('collection_tree_alpha_order')) + ); ?>
@@ -19,8 +22,11 @@

- formCheckbox('collection_tree_browse_only_root', null, - array('checked' => (bool) get_option('collection_tree_browse_only_root'))); ?> + formCheckbox( + 'collection_tree_browse_only_root', + null, + array('checked' => (bool) get_option('collection_tree_browse_only_root')) + ); ?>
@@ -31,8 +37,11 @@

- formCheckbox('collection_tree_show_subcollections', null, - array('checked' => (bool) get_option('collection_tree_show_subcollections'))); ?> + formCheckbox( + 'collection_tree_show_subcollections', + null, + array('checked' => (bool) get_option('collection_tree_show_subcollections')) + ); ?>
@@ -43,7 +52,10 @@

- formCheckbox('collection_tree_search_descendant', null, - array('checked' => (bool) get_option('collection_tree_search_descendant'))); ?> + formCheckbox( + 'collection_tree_search_descendant', + null, + array('checked' => (bool) get_option('collection_tree_search_descendant')) + ); ?>
diff --git a/views/helpers/CollectionTreeFullList.php b/views/helpers/CollectionTreeFullList.php index 5835a4f..9acaebb 100644 --- a/views/helpers/CollectionTreeFullList.php +++ b/views/helpers/CollectionTreeFullList.php @@ -1,7 +1,7 @@ Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 2/8] Added an argument to include the current collection in method getAncestorTree(). --- models/Table/CollectionTree.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index 989de4a..03371f7 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -167,12 +167,17 @@ public function getCollectionTree($collectionId) * @param int $collectionId * @param bool $getCollectionTree Include the passed collection, its * ancestor tree, and its descendant tree. + * @param bool $includeSelf Include the passed collection. Always true when + * the option $getCollectionTree is set. * @return array */ - public function getAncestorTree($collectionId, $getCollectionTree = false) + public function getAncestorTree($collectionId, $getCollectionTree = false, $includeSelf = false) { $tree = array(); + // Self is always included in the whole collection tree. + $includeSelf = $getCollectionTree || $includeSelf; + // Distinguish between the passed collection and its descendants. $parentCollectionId = $collectionId; @@ -183,16 +188,18 @@ public function getAncestorTree($collectionId, $getCollectionTree = false) $parentCollectionId = $collection['parent_collection_id']; // Don't include the passed collection when not building the entire - // collection tree. - if (!$getCollectionTree && $collectionId == $collection['id']) { + // collection tree, unless specified. + if (!$includeSelf && $collectionId == $collection['id']) { continue; } // If set to return the entire collection tree, add the descendant // tree to the passed collection and flag it as current. - if ($getCollectionTree && $collectionId == $collection['id']) { - $collection['children'] = $this->getDescendantTree($collection['id']); + if ($includeSelf && $collectionId == $collection['id']) { $collection['current'] = true; + if ($getCollectionTree) { + $collection['children'] = $this->getDescendantTree($collection['id']); + } } // Prepend the parent collection to the collection tree, pushing the From 6e39602e719461607efd85fbdb550f22a62b1f1d Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 3/8] Added an argument to link to the current collection in the collection tree list. --- views/helpers/CollectionTreeList.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/views/helpers/CollectionTreeList.php b/views/helpers/CollectionTreeList.php index 729f993..c723c02 100644 --- a/views/helpers/CollectionTreeList.php +++ b/views/helpers/CollectionTreeList.php @@ -20,31 +20,34 @@ class CollectionTree_View_Helper_CollectionTreeList extends Zend_View_Helper_Abs * @see CollectionTreeTable::getDescendantTree() * @param array $collectionTree * @param bool $linkToCollectionShow + * @param bool $linkToCurrentCollectionShow Require option $linkToCollectionShow. * @return string */ - public function collectionTreeList($collectionTree, $linkToCollectionShow = true) + public function collectionTreeList($collectionTree, $linkToCollectionShow = true, $linkToCurrentCollection = false) { if (!$collectionTree) { return; } + $linkToCurrentCollection = $linkToCollectionShow && $linkToCurrentCollection; + $collectionTable = get_db()->getTable('Collection'); $html = ''; From 5cfa09f1d56daed3a40d8e1fbb6bddeef388bbf0 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 4/8] Added a method to get the ancestors as a flat array. --- models/Table/CollectionTree.php | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index 03371f7..920fb67 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -218,6 +218,41 @@ public function getAncestorTree($collectionId, $getCollectionTree = false, $incl return $tree; } + /** + * Get the ancestors of the specified collection as a flat array. + * + * @param int $collectionId + * @param bool $includeSelf Include the passed collection. + * @return array + */ + public function getAncestors($collectionId, $includeSelf = false) + { + $list = array(); + + // Distinguish between the passed collection and its descendants. + $parentCollectionId = $collectionId; + + // Iterate the parent collections, starting with the passed collection + // and stopping at the root collection. + do { + $collection = $this->getCollection($parentCollectionId); + $parentCollectionId = $collection['parent_collection_id']; + + // Don't include the passed collection when not building the entire + // collection tree, unless specified. + if (!$includeSelf && $collectionId == $collection['id']) { + continue; + } + + // Append the parent collection to the collection list, pushing the + // descendant tree to the second element. + $list[] = $collection; + + } while ($collection['parent_collection_id']); + + return array_reverse($list); + } + /** * Recursively get the descendant tree of the specified collection. * From b20bed8058c2747dc19889ff8e4672652ac42d3e Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 5/8] Renamed some variables. --- models/Table/CollectionTree.php | 10 +++++----- views/helpers/CollectionTreeFullList.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index 920fb67..dbef91b 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -131,22 +131,22 @@ public function findPairsForSelectForm(array $options = array(), $padding = '-') $padding = '-'; } - $options = array(); + $pairs = array(); foreach ($this->getRootCollections() as $rootCollectionId => $rootCollection) { - $options[$rootCollectionId] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); + $pairs[$rootCollectionId] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); $this->_resetCache(); $this->getDescendantTree($rootCollectionId, true); foreach ($this->_cache as $collectionId => $collectionDepth) { $collection = $this->getCollection($collectionId); - $options[$collectionId] = str_repeat($padding, $collectionDepth) . ' '; - $options[$collectionId] .= $collection['name'] ? $collection['name'] : __('[Untitled]'); + $pairs[$collectionId] = str_repeat($padding, $collectionDepth) . ' '; + $pairs[$collectionId] .= $collection && $collection['name'] ? $collection['name'] : __('[Untitled]'); } } $this->_resetCache(); - return $options; + return $pairs; } /** diff --git a/views/helpers/CollectionTreeFullList.php b/views/helpers/CollectionTreeFullList.php index 9acaebb..b24a342 100644 --- a/views/helpers/CollectionTreeFullList.php +++ b/views/helpers/CollectionTreeFullList.php @@ -34,8 +34,8 @@ public function collectionTreeFullList($linkToCollectionShow = true) } else { $html .= $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); } - $collectionTree = get_db()->getTable('CollectionTree')->getDescendantTree($rootCollection['id']); - $html .= $this->view->collectionTreeList($collectionTree, $linkToCollectionShow); + $descendantTree = get_db()->getTable('CollectionTree')->getDescendantTree($rootCollection['id']); + $html .= $this->view->collectionTreeList($descendantTree, $linkToCollectionShow); $html .= ''; } $html .= ''; From b8a28b3bfb29881f577d3ae49cc1a545f93c30df Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 6/8] Added an option to order collections according to an order list. --- models/Table/CollectionTree.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index dbef91b..7966bef 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -118,8 +118,12 @@ public function findByParentCollectionId($parentCollectionId) /** * Return the collection tree hierarchy as a one-dimensional array. * - * @param array $options (unused) Set of parameters for searching/ - * filtering results. No options are currently available for this method. + * @param array $options Set of parameters for searching/filtering results. + * Managed options: + * - order (array): assoiative array with collection ids as key and integers + * as value for priority, that allows to order collections at each level + * (see plugin ColSort). The priority is a positive integer. The collections + * without priority are appended after the ordered ones. * @param string $padding The string representation of the collection depth. * @return array */ @@ -131,13 +135,24 @@ public function findPairsForSelectForm(array $options = array(), $padding = '-') $padding = '-'; } + $order = isset($options['order']) ? array_filter($options['order']) : array(); + $pairs = array(); - foreach ($this->getRootCollections() as $rootCollectionId => $rootCollection) { + $rootCollections = $this->getRootCollections(); + $rootCollections = array_replace( + array_intersect_key($order, $rootCollections), + $rootCollections + ); + foreach ($rootCollections as $rootCollectionId => $rootCollection) { $pairs[$rootCollectionId] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); $this->_resetCache(); $this->getDescendantTree($rootCollectionId, true); + $this->_cache = array_replace( + array_intersect_key($order, $this->_cache), + $this->_cache + ); foreach ($this->_cache as $collectionId => $collectionDepth) { $collection = $this->getCollection($collectionId); $pairs[$collectionId] = str_repeat($padding, $collectionDepth) . ' '; From 6f349b578c2bb97d1d55faf8b9d2e36fa3de8b7d Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 7/8] Added a method to get a flat list of all collections with children. --- models/Table/CollectionTree.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php index 7966bef..d837dc2 100644 --- a/models/Table/CollectionTree.php +++ b/models/Table/CollectionTree.php @@ -164,6 +164,37 @@ public function findPairsForSelectForm(array $options = array(), $padding = '-') return $pairs; } + /** + * Return the collection tree as a one-dimensional array, with children. + * + * @return array + */ + public function getCollectionList() + { + $result = array(); + + foreach ($this->getRootCollections() as $rootCollectionId => $rootCollection) { + $this->_resetCache(); + $this->getDescendantTree($rootCollectionId, true); + $result[$rootCollectionId]['id'] = $rootCollectionId; + $result[$rootCollectionId]['name'] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]'); + $result[$rootCollectionId]['depth'] = 0; + $result[$rootCollectionId]['parent'] = null; + $result[$rootCollectionId]['children'] = array_keys($this->_cache); + foreach ($this->_cache as $collectionId => $collectionDepth) { + $collection = $this->getCollection($collectionId); + $result[$collectionId]['id'] = $collectionId; + $result[$collectionId]['name'] = $collection && $collection['name'] ? $collection['name'] : __('[Untitled]'); + $result[$collectionId]['depth'] = $collectionDepth; + $result[$collectionId]['parent'] = $collection && $collection['parent_collection_id'] ? $collection['parent_collection_id'] : null ; + $result[$collectionId]['children'] = array_keys($this->getChildCollections($collectionId)); + } + } + $this->_resetCache(); + + return $result; + } + /** * Get the entire collection tree of the specified collection. * From 27685326fe81b95ac4a787a14d759b68f1229c4a Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 13 Apr 2020 00:00:00 +0200 Subject: [PATCH 8/8] Released version 2.2.0. --- plugin.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.ini b/plugin.ini index 3407091..cd6e57d 100644 --- a/plugin.ini +++ b/plugin.ini @@ -5,7 +5,7 @@ description="Gives administrators the ability to create a hierarchical tree of t license="GPLv3" link="https://omeka.org/codex/Plugins/CollectionTree_2.0" support_link="https://omeka.org/forums/forum/plugins" -version="2.1" +version="2.2.0" omeka_minimum_version="2.0" -omeka_target_version="2.0" +omeka_target_version="2.7" tags="tree,collections,subcollections"