Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for tagging collections. #963

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions admin/themes/default/collections/form-tabs.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
$tabs[$tabName] = $tabContent;
}

ob_start();
require 'tag-form.php';
$tabs['Tags'] = ob_get_contents();
ob_end_clean();

$tabs = apply_filters('admin_collections_form_tabs', $tabs, array('collection' => $collection));
?>

Expand Down
5 changes: 5 additions & 0 deletions admin/themes/default/collections/form.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
<?php echo js_tag('vendor/tinymce/tinymce.min'); ?>
<?php echo js_tag('elements'); ?>
<?php echo js_tag('tabs'); ?>
<?php echo js_tag('items'); ?>
<script type="text/javascript">
jQuery(document).ready(function () {
Omeka.Tabs.initialize();

Omeka.Items.tagDelimiter = <?php echo js_escape(get_option('tag_delimiter')); ?>;
Omeka.Items.enableTagRemoval();
Omeka.Items.tagChoices('#tags', <?php echo js_escape(url(array('controller'=>'tags', 'action'=>'autocomplete'), 'default', array(), true)); ?>);

Omeka.wysiwyg({
selector: false,
forced_root_block: false
Expand Down
9 changes: 9 additions & 0 deletions admin/themes/default/collections/show.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
<p><span class="label"><?php echo __('Featured'); ?>:</span> <?php echo ($collection->featured) ? __('Yes') : __('No'); ?></p>
</div>

<?php if (metadata('collection', 'has tags')): ?>
<div class="tags panel">
<h4><?php echo __('Tags'); ?></h4>
<div id="tag-cloud">
<?php echo common('tag-list', compact('collection'), 'collections'); ?>
</div>
</div>
<?php endif; ?>

<div class="total-items panel">
<h4><?php echo __('Total Number of Items'); ?></h4>
<p><?php echo link_to_items_in_collection(); ?></p>
Expand Down
31 changes: 31 additions & 0 deletions admin/themes/default/collections/tag-form.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div id="tag-form" class="field">
<?php
$tags = $collection->getTags();
?>
<input type="hidden" name="tags-to-add" id="tags-to-add" value="" />
<input type="hidden" name="tags-to-delete" id="tags-to-delete" value="" />
<div id="add-tags">
<label><?php echo __('Add Tags'); ?></label>
<input type="text" name="tags" size="20" id="tags" class="textinput" value="" />
<p id="add-tags-explanation" class="explanation"><?php echo __('Separate tags with %s', option('tag_delimiter')); ?></p>
<input type="submit" name="add-tags-button" id="add-tags-button" class="green button" value="<?php echo __('Add Tags'); ?>" />
</div>
<div id="all-tags">
<?php if ($tags): ?>
<h3><?php echo __('All Tags'); ?></h3>

<div class="tag-list">
<ul id="all-tags-list">
<?php foreach( $tags as $tag ): ?>
<li>
<?php echo '<span class="tag">' . html_escape($tag->name) . '</span>';
echo '<span class="undo-remove-tag"><a href="#">' . __('Undo') . '</a></span>';
echo '<span class="remove-tag"><a href="#">' . __('Remove') . '</a></span>'; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
</div>
<?php fire_plugin_hook('admin_collections_form_tags', array('collection' => $collection, 'view' => $this)); ?>
9 changes: 9 additions & 0 deletions admin/themes/default/collections/tag-list.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php if ($collection->Tags): ?>
<ul class="tags">
<?php foreach( $collection->Tags as $key => $tag ): ?>
<li class="tag">
<a href="<?php echo html_escape(url('collections/browse', array('tags' => $tag->name))); ?>"><?php echo html_escape($tag->name); ?></a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
11 changes: 11 additions & 0 deletions admin/themes/default/collections/tags.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
$pageTitle = __('Browse Collections by Tag');
echo head(array('title' => $pageTitle));
echo flash();
?>
<?php if (count($tags)): ?>
<?php echo tag_cloud($tags, 'collections/browse'); ?>
<?php else: ?>
<p><?php echo __('There are no tags to display. You must first tag some collections.'); ?></p>
<?php endif; ?>
<?php echo foot(); ?>
14 changes: 14 additions & 0 deletions application/controllers/CollectionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ public function editAction()
parent::editAction();
}

/**
* Finds all tags associated with collections (used for tag cloud)
*/
public function tagsAction()
{
$params = array_merge(
array('sort_field' => 'name'),
$this->_getAllParams(),
array('type' => 'Collection')
);
$tags = $this->_helper->db->getTable('Tag')->findBy($params);
$this->view->assign(compact('tags'));
}

protected function _getAddSuccessMessage($collection)
{
$collectionTitle = $this->_getElementMetadata($collection, 'Dublin Core', 'Title');
Expand Down
2 changes: 2 additions & 0 deletions application/models/Api/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function getRepresentation(Omeka_Record_AbstractRecord $record)
'url' => self::getResourceUrl("/items?collection={$record->id}"),
'resource' => 'items',
),
'tags' = $this->getTagRepresentations($record),
'element_texts' => $this->getElementTextRepresentations($record),
);

Expand All @@ -56,6 +57,7 @@ public function setPostData(Omeka_Record_AbstractRecord $record, $data)
if (isset($data->featured)) {
$record->featured = $data->featured;
}
$this->setTagData($record, $data);
$this->setElementTextData($record, $data);
}

Expand Down
12 changes: 12 additions & 0 deletions application/models/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Collection extends Omeka_Record_AbstractRecord implements Zend_Acl_Resourc
* @see Omeka_Record_AbstractRecord::__get
*/
protected $_related = array(
'Tags' => 'getTags',
'ElementTexts' => 'getAllElementTexts'
);

Expand All @@ -62,6 +63,7 @@ class Collection extends Omeka_Record_AbstractRecord implements Zend_Acl_Resourc
*/
protected function _initializeMixins()
{
$this->_mixins[] = new Mixin_Tag($this);
$this->_mixins[] = new Mixin_PublicFeatured($this);
$this->_mixins[] = new Mixin_Owner($this);
$this->_mixins[] = new Mixin_ElementText($this);
Expand Down Expand Up @@ -211,6 +213,16 @@ protected function afterSave($args)
if (!$this->public) {
$this->setSearchTextPrivate();
}

if ($args['post']) {
$post = $args['post'];

// Save/delete the tags.
if (isset($post['tags-to-add'])) {
$this->addTags($post['tags-to-add']);
$this->deleteTags($post['tags-to-delete']);
}
}
}

/**
Expand Down
85 changes: 85 additions & 0 deletions application/models/Table/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ public function applySearchFilters($select, $params)
case 'range':
$this->filterByRange($select, $value);
break;
case 'tag':
case 'tags':
$this->filterByTags($select, $value);
break;
case 'excludeTags':
$this->filterByExcludedTags($select, $value);
break;
}
}
}
Expand Down Expand Up @@ -134,4 +141,82 @@ public function applySorting($select, $sortField, $sortDir)
}
}
}

/**
* Query must look like the following in order to correctly retrieve collections
* that have all the tags provided (in this example, all collections that are
* tagged both 'foo' and 'bar'):
*
* SELECT i.id
* FROM omeka_collections i
* WHERE
* (
* i.id IN
* (SELECT tg.record_id as id
* FROM omeka_records_tags tg
* INNER JOIN omeka_tags t ON t.id = tg.tag_id
* WHERE t.name = 'foo' AND tg.record_type = 'Collection')
* AND i.id IN
* (SELECT tg.record_id as id
* FROM omeka_records_tags tg
* INNER JOIN omeka_tags t ON t.id = tg.tag_id
* WHERE t.name = 'bar' AND tg.record_type = 'Collection')
* )
* ...
*
*
* @param Omeka_Db_Select
* @param string|array A comma-delimited string or an array of tag names.
*/
public function filterByTags($select, $tags)
{
// Split the tags into an array if they aren't already
if (!is_array($tags)) {
$tags = explode(get_option('tag_delimiter'), $tags);
}

$db = $this->getDb();

// For each of the tags, create a SELECT subquery using Omeka_Db_Select.
// This subquery should only return collection IDs, so that the subquery can be
// appended to the main query by WHERE i.id IN (SUBQUERY).
foreach ($tags as $tagName) {
$subSelect = new Omeka_Db_Select;
$subSelect->from(array('records_tags' => $db->RecordsTags), array('collections.id' => 'records_tags.record_id'))
->joinInner(array('tags' => $db->Tag), 'tags.id = records_tags.tag_id', array())
->where('tags.name = ? AND records_tags.`record_type` = "Collection"', trim($tagName));

$select->where('collections.id IN (' . (string) $subSelect . ')');
}
}

/**
* Filter SELECT statement based on collections that are not tagged with a specific
* set of tags
*
* @param Zend_Db_Select
* @param array|string Set of tag names (either array or comma-delimited string)
*/
public function filterByExcludedTags($select, $tags)
{
$db = $this->getDb();

if (!is_array($tags)) {
$tags = explode(get_option('tag_delimiter'), $tags);
}
$subSelect = new Omeka_Db_Select;
$subSelect->from(array('collections' => $db->Collection), 'collections.id')
->joinInner(array('records_tags' => $db->RecordsTags),
'records_tags.record_id = collections.id AND records_tags.record_type = "Collection"',
array())
->joinInner(array('tags' => $db->Tag),
'records_tags.tag_id = tags.id',
array());

foreach ($tags as $key => $tag) {
$subSelect->where('tags.name LIKE ?', $tag);
}

$select->where('collections.id NOT IN ('.$subSelect->__toString().')');
}
}