';
+ return $html;
+ }
+
/**
* Display the collection's parent collection and child collections.
*/
@@ -227,13 +349,13 @@ public function hookAdminCollectionsShow($args)
{
$this->_appendToCollectionsShow($args['collection']);
}
-
+
/**
* Display the collection's parent collection and child collections.
*/
- public function hookPublicCollectionsShow()
+ public function hookPublicCollectionsShow($args)
{
- $this->_appendToCollectionsShow(get_current_record('collection'));
+ $this->_appendToCollectionsShow($args['collection']);
}
protected function _appendToCollectionsShow($collection)
@@ -268,12 +390,13 @@ public function filterPublicNavigationMain($nav)
*/
public function filterAdminCollectionsFormTabs($tabs, $args)
{
+ $collection = $args['collection'];
$collectionTreeTable = $this->_db->getTable('CollectionTree');
$options = $collectionTreeTable->findPairsForSelectForm();
$options = array('0' => __('No parent collection')) + $options;
-
- $collectionTree = $collectionTreeTable->findByCollectionId($args['collection']->id);
+
+ $collectionTree = $collectionTreeTable->findByCollectionId($collection->id);
if ($collectionTree) {
$parentCollectionId = $collectionTree->parent_collection_id;
} else {
@@ -285,4 +408,53 @@ public function filterAdminCollectionsFormTabs($tabs, $args)
);
return $tabs;
}
+
+
+ /**
+ * Filter items browse params to broaden the search to subcollections.
+ *
+ * @param array $params
+ * @return array
+ */
+ public function filterItemsBrowseParams($params)
+ {
+ // Check if this is a direct query (not from advanced search).
+ if (!is_admin_theme()
+ && !isset($params['subcollections'])
+ && get_option('collection_tree_show_subcollections')
+ ) {
+ $params['subcollections'] = 1;
+ }
+
+ if (!empty($params['subcollections'])) {
+ $collection = 0;
+ if (!empty($params['collection_id'])) {
+ $collection = $params['collection_id'];
+ $params['collection_id'] = '';
+ }
+ if (!empty($params['collection'])) {
+ $collection = $params['collection'];
+ $params['collection'] = '';
+ }
+ if ($collection) {
+ $params['descendant_or_self'] = $collection;
+ }
+ }
+
+ return $params;
+ }
+
+
+ /**
+ * Manage search options for collections.
+ *
+ * @param array Search options for collections.
+ * @return array Filtered search options for collections.
+ */
+ public function filterCollectionsSelectOptions($options)
+ {
+ $treeOptions = $this->_db->getTable('CollectionTree')->findPairsForSelectForm();
+ // Keep only chosen collections, in case another filter removed some.
+ return array_intersect_key($treeOptions, $options);
+ }
}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1db8f1a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,74 @@
+Collection Tree (plugin for Omeka)
+==================================
+
+
+Summary
+-------
+
+This plugin for [Omeka] gives administrators the ability to create a
+hierarchical tree of their collections.
+
+
+Installation
+------------
+
+Uncompress files and rename plugin folder "CollectionTree".
+
+Then install it like any other Omeka plugin and follow the config instructions.
+
+
+Warning
+-------
+
+Use it at your own risk.
+
+It's always recommended to backup your files and database so you can roll back
+if needed.
+
+
+Troubleshooting
+---------------
+
+See online issues on [Collection Tree issues] page on GitHub.
+
+
+License
+-------
+
+This plugin is published under [GNU/GPL].
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU 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 General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+Contact
+-------
+
+Current maintainers:
+
+* Roy Rosenzweig Center for History and New Media
+
+
+Copyright
+---------
+
+* Copyright Roy Rosenzweig Center for History and New Media, 2007-2013
+* Copyright Daniel Berthereau, 2014 (improvements)
+
+
+[Omeka]: https://omeka.org
+[Collection Tree]: https://github.com/Omeka/plugin-CollectionTree
+[Collection Tree issues]: https://github.com/Omeka/plugin-CollectionTree/issues
+[GNU/GPL]: https://www.gnu.org/licenses/gpl-3.0.html "GNU/GPL v3"
+[Daniel-KM]: https://github.com/Daniel-KM "Daniel Berthereau"
diff --git a/models/Table/CollectionTree.php b/models/Table/CollectionTree.php
index 862c8d4..f52624f 100644
--- a/models/Table/CollectionTree.php
+++ b/models/Table/CollectionTree.php
@@ -44,33 +44,36 @@ class Table_CollectionTree extends Omeka_Db_Table
*/
public function fetchAssignableParentCollections($collectionId)
{
- $db = $this->getDb();
-
// Must cast null collection ID to 0 to properly bind.
$collectionId = (int) $collectionId;
- $sql = "
- SELECT c.*, ct.name
- FROM {$db->Collection} c
- LEFT JOIN {$db->CollectionTree} ct
- ON c.id = ct.collection_id
- WHERE c.id != ?";
+ $table = $this->_db->getTable('Collection');
+ $alias = $this->getTableAlias();
+ $aliasCollection = $table->getTableAlias();
+
+ // Access rights to collections are automatically managed.
+ $select = $table->getSelect();
+ $select->joinLeft(
+ array($alias => $this->getTableName()),
+ "$aliasCollection.id = $alias.collection_id",
+ array('name'));
+ $select->where("$aliasCollection.id != ?", $collectionId);
// If not a new collection, cache descendant collection IDs and exclude
// those collections from the result.
if ($collectionId) {
$unassignableCollectionIds = $this->getUnassignableCollectionIds();
if ($unassignableCollectionIds) {
- $sql .= " AND c.id NOT IN (" . implode(', ', $unassignableCollectionIds) . ")";
+ $select->where("$aliasCollection.id NOT IN (?)", $unassignableCollectionIds);
}
}
// Order alphabetically if configured to do so.
if (get_option('collection_tree_alpha_order')) {
- $sql .= ' ORDER BY ct.name';
+ $select->order("$alias.name ASC");
}
- return $db->fetchAll($sql, array((int) $collectionId));
+ return $this->fetchAssoc($select);
}
/**
@@ -81,15 +84,16 @@ public function fetchAssignableParentCollections($collectionId)
*/
public function findByCollectionId($collectionId)
{
- $db = $this->getDb();
-
- $sql = "
- SELECT *
- FROM {$db->CollectionTree}
- WHERE collection_id = ?";
+ // Cast to integer to prevent SQL injection.
+ $collectionId = (int) $collectionId;
+ $alias = $this->getTableAlias();
+ $select = $this->getSelect();
+ $select->where("$alias.collection_id = ?", $collectionId);
+ $select->limit(1);
+ $select->reset(Zend_Db_Select::ORDER);
// Child collection IDs are unique, so only fetch one row.
- return $this->fetchObject($sql, array($collectionId));
+ return $this->fetchObject($select);
}
/**
@@ -100,59 +104,40 @@ public function findByCollectionId($collectionId)
*/
public function findByParentCollectionId($parentCollectionId)
{
- $db = $this->getDb();
-
- $sql = "
- SELECT *
- FROM {$db->CollectionTree}
- WHERE parent_collection_id = ?";
-
- return $this->fetchObjects($sql, array($parentCollectionId));
- }
-
- /**
- * Cache collection data.
- */
- public function cacheCollections()
- {
- $db = $this->getDb();
- $sql = "
- SELECT c.*, ct.parent_collection_id, ct.name
- FROM {$db->Collection} c
- LEFT JOIN {$db->CollectionTree} ct
- ON c.id = ct.collection_id";
-
- // check whether the acl exists -- it doesn't within a background process
- $acl = get_acl();
- // Cache only those collections to which the current user has access.
- if ($acl && ! $acl->isAllowed(current_user(), 'Collections', 'showNotPublic')) {
- $sql .= ' WHERE c.public = 1';
- }
-
- // Order alphabetically if configured to do so.
- if (get_option('collection_tree_alpha_order')) {
- $sql .= ' ORDER BY ct.name';
- }
-
- $this->_collections = $db->fetchAll($sql);
+ // Cast to integer to prevent SQL injection.
+ $parentCollectionId = (int) $parentCollectionId;
+
+ $alias = $this->getTableAlias();
+ $select = $this->getSelect();
+ $select->where("$alias.parent_collection_id = ?", $parentCollectionId);
+ $select->reset(Zend_Db_Select::ORDER);
+ return $this->fetchObjects($select);
}
/**
* Return the collection tree hierarchy as a one-dimensional array.
*
+ * @param array $options (optional) Set of parameters for searching/
+ * filtering results.
* @param string $padding The string representation of the collection depth.
* @return array
*/
- public function findPairsForSelectForm($padding = '-')
+ public function findPairsForSelectForm(array $options = array(), $padding = '-')
{
+ if (isset($params['padding'])) {
+ $padding = $params['padding'];
+ } else {
+ $padding = '-';
+ }
+
$options = array();
- foreach ($this->getRootCollections() as $rootCollection) {
+ foreach ($this->getRootCollections() as $rootCollectionId => $rootCollection) {
- $options[$rootCollection['id']] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]');
+ $options[$rootCollectionId] = $rootCollection['name'] ? $rootCollection['name'] : __('[Untitled]');
$this->_resetCache();
- $this->getDescendantTree($rootCollection['id'], true);
+ $this->getDescendantTree($rootCollectionId, true);
foreach ($this->_cache as $collectionId => $collectionDepth) {
$collection = $this->getCollection($collectionId);
$options[$collectionId] = str_repeat($padding, $collectionDepth) . ' ';
@@ -241,7 +226,7 @@ public function getDescendantTree($collectionId, $cacheDescendantInfo = false, $
$collectionDepth++;
// Iterate the child collections.
- $descendantTree = $this->getChildCollections($collectionId);
+ $descendantTree = array_values($this->getChildCollections($collectionId));
for ($i = 0; $i < count($descendantTree); $i++) {
if ($cacheDescendantInfo) {
@@ -249,9 +234,10 @@ public function getDescendantTree($collectionId, $cacheDescendantInfo = false, $
}
// Recurse the child collections, getting their children.
- $children = $this->getDescendantTree($descendantTree[$i]['id'],
- $cacheDescendantInfo,
- $collectionDepth);
+ $children = $this->getDescendantTree(
+ $descendantTree[$i]['id'],
+ $cacheDescendantInfo,
+ $collectionDepth);
// Assign the child collections to the descendant tree.
if ($children) {
@@ -272,57 +258,62 @@ public function getDescendantTree($collectionId, $cacheDescendantInfo = false, $
*/
public function getCollection($collectionId)
{
- // Cache collections in not already.
- if (!$this->_collections) {
- $this->cacheCollections();
- }
-
- foreach ($this->_collections as $collection) {
- if ($collectionId == $collection['id']) {
- return $collection;
- }
- }
- return false;
+ $collections = $this->_getCollections();
+ return isset($collections[$collectionId]) ? $collections[$collectionId] : false;
}
/**
* Get the child collections of the specified collection.
*
* @param int $collectionId
- * @return array
+ * @return array Associative array of collections, by id.
*/
public function getChildCollections($collectionId)
{
- // Cache collections if not already.
- if (!$this->_collections) {
- $this->cacheCollections();
- }
-
$childCollections = array();
- foreach ($this->_collections as $collection) {
+ $collections = $this->_getCollections();
+ foreach ($collections as $collection) {
if ($collectionId == $collection['parent_collection_id']) {
- $childCollections[] = $collection;
+ $childCollections[$collection['id']] = $collection;
}
}
return $childCollections;
}
/**
- * Get all root collections, i.e. those without parent collections.
+ * Get the list of descendant collections and the selected one.
*
- * @return array
+ * @param int $collectionId
+ * @return array Associative array of collections.
*/
- public function getRootCollections()
+ public function getDescendantOrSelfCollections($collectionId)
{
- // Cache collections if not already.
- if (!$this->_collections) {
- $this->cacheCollections();
+ $collections = array();
+
+ $rootCollection = $this->getCollection($collectionId);
+ if ($rootCollection) {
+ $this->_resetCache();
+ $this->getDescendantTree($collectionId, true);
+ $collections[$collectionId] = $rootCollection;
+ $collections += array_intersect_key($this->_getCollections(), $this->_cache);
+ $this->_resetCache();
}
+ return $collections;
+ }
+
+ /**
+ * Get all root collections, i.e. those without parent collections.
+ *
+ * @return array Associative array of root collections, by id.
+ */
+ public function getRootCollections()
+ {
$rootCollections = array();
- foreach ($this->_collections as $collection) {
+ $collections = $this->_getCollections();
+ foreach ($collections as $collection) {
if (!$collection['parent_collection_id']) {
- $rootCollections[] = $collection;
+ $rootCollections[$collection['id']] = $collection;
}
}
return $rootCollections;
@@ -346,6 +337,34 @@ public function getUnassignableCollectionIds($collectionId)
return $unassignableCollections;
}
+ /**
+ * Cache collection data with name and parent id in an associative array.
+ */
+ protected function _getCollections()
+ {
+ if (is_null($this->_collections)) {
+ $table = $this->_db->getTable('Collection');
+ $alias = $this->getTableAlias();
+ $aliasCollection = $table->getTableAlias();
+
+ // Access rights to collections are automatically managed.
+ $select = $table->getSelect();
+ $select->joinLeft(
+ array($alias => $this->getTableName()),
+ "$aliasCollection.id = $alias.collection_id",
+ array('parent_collection_id', 'name'));
+
+ // Order alphabetically if configured to do so.
+ if (get_option('collection_tree_alpha_order')) {
+ $select->order("$alias.name ASC");
+ }
+
+ $this->_collections = $this->fetchAssoc($select);
+ }
+
+ return $this->_collections;
+ }
+
/**
* Reset the cache property.
*/
diff --git a/plugin.ini b/plugin.ini
index 270a54b..a45ec7b 100644
--- a/plugin.ini
+++ b/plugin.ini
@@ -3,8 +3,8 @@ name="Collection Tree"
author="Roy Rosenzweig Center for History and New Media"
description="Gives administrators the ability to create a hierarchical tree of their collections."
license="GPLv3"
-link="http://omeka.org/codex/Plugins/CollectionTree_2.0"
-support_link="http://omeka.org/forums/forum/plugins"
+link="https://omeka.org/codex/Plugins/CollectionTree_2.0"
+support_link="https://omeka.org/forums/forum/plugins"
version="2.0.2"
omeka_minimum_version="2.0"
omeka_target_version="2.0"
diff --git a/views/admin/plugins/collection-tree-config-form.php b/views/admin/plugins/collection-tree-config-form.php
index 772c4bc..710f24e 100644
--- a/views/admin/plugins/collection-tree-config-form.php
+++ b/views/admin/plugins/collection-tree-config-form.php
@@ -1,11 +1,50 @@