MDL-61135 core_tag: add function get_tags_by_area_in_contexts

Add a function to allow for searching tags by an area (component and
itemtype) in a given set of contexts.
This commit is contained in:
Ryan Wyllie
2018-02-05 06:59:13 +00:00
parent 99df051805
commit 4c72d4bec1
2 changed files with 153 additions and 0 deletions
+34
View File
@@ -1604,4 +1604,38 @@ class core_tag_tag {
// Finally delete all tags that we combined into the current one.
self::delete_tags($ids);
}
/**
* Retrieve a list of tags that have been used to tag the given $component
* and $itemtype in the provided $contexts.
*
* @param string $component The tag instance component
* @param string $itemtype The tag instance item type
* @param context[] $contexts The list of contexts to look for tag instances in
* @return core_tag_tag[]
*/
public static function get_tags_by_area_in_contexts($component, $itemtype, array $contexts) {
global $DB;
$params = [$component, $itemtype];
$contextids = array_map(function($context) {
return $context->id;
}, $contexts);
list($contextsql, $contextsqlparams) = $DB->get_in_or_equal($contextids);
$params = array_merge($params, $contextsqlparams);
$subsql = "SELECT tagid
FROM {tag_instance}
WHERE component = ?
AND itemtype = ?
AND contextid {$contextsql}
GROUP BY tagid";
$sql = "SELECT *
FROM {tag}
WHERE id IN ({$subsql})";
return array_map(function($record) {
return new core_tag_tag($record);
}, $DB->get_records_sql($sql, $params));
}
}
+119
View File
@@ -1053,6 +1053,125 @@ class core_tag_taglib_testcase extends advanced_testcase {
$this->assertEquals(['dogs', 'hippo'], $correlatedtags);
}
/**
* get_tags_by_area_in_contexts should return an empty array if there
* are no tag instances for the area in the given context.
*/
public function test_get_tags_by_area_in_contexts_empty() {
$tagnames = ['foo'];
$collid = core_tag_collection::get_default();
$tags = core_tag_tag::create_if_missing($collid, $tagnames);
$user = $this->getDataGenerator()->create_user();
$context = context_user::instance($user->id);
$component = 'core';
$itemtype = 'user';
$result = core_tag_tag::get_tags_by_area_in_contexts($component, $itemtype, [$context]);
$this->assertEmpty($result);
}
/**
* get_tags_by_area_in_contexts should return an array of tags that
* have instances in the given context even when there is only a single
* instance.
*/
public function test_get_tags_by_area_in_contexts_single_tag_one_context() {
$tagnames = ['foo'];
$collid = core_tag_collection::get_default();
$tags = core_tag_tag::create_if_missing($collid, $tagnames);
$user = $this->getDataGenerator()->create_user();
$context = context_user::instance($user->id);
$component = 'core';
$itemtype = 'user';
core_tag_tag::set_item_tags($component, $itemtype, $user->id, $context, $tagnames);
$result = core_tag_tag::get_tags_by_area_in_contexts($component, $itemtype, [$context]);
$expected = array_map(function($t) {
return $t->id;
}, $tags);
$actual = array_map(function($t) {
return $t->id;
}, $result);
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
}
/**
* get_tags_by_area_in_contexts should return all tags in an array
* that have tag instances in for the area in the given context and
* should ignore all tags that don't have an instance.
*/
public function test_get_tags_by_area_in_contexts_multiple_tags_one_context() {
$tagnames = ['foo', 'bar', 'baz'];
$collid = core_tag_collection::get_default();
$tags = core_tag_tag::create_if_missing($collid, $tagnames);
$user = $this->getDataGenerator()->create_user();
$context = context_user::instance($user->id);
$component = 'core';
$itemtype = 'user';
core_tag_tag::set_item_tags($component, $itemtype, $user->id, $context, array_slice($tagnames, 0, 2));
$result = core_tag_tag::get_tags_by_area_in_contexts($component, $itemtype, [$context]);
$expected = ['foo', 'bar'];
$actual = array_map(function($t) {
return $t->name;
}, $result);
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
}
/**
* get_tags_by_area_in_contexts should return the unique set of
* tags for a area in the given contexts. Multiple tag instances of
* the same tag don't result in duplicates in the result set.
*
* Tags with tag instances in the same area with in difference contexts
* should be ignored.
*/
public function test_get_tags_by_area_in_contexts_multiple_tags_multiple_contexts() {
$tagnames = ['foo', 'bar', 'baz', 'bop', 'bam', 'bip'];
$collid = core_tag_collection::get_default();
$tags = core_tag_tag::create_if_missing($collid, $tagnames);
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$context1 = context_user::instance($user1->id);
$context2 = context_user::instance($user2->id);
$context3 = context_user::instance($user3->id);
$component = 'core';
$itemtype = 'user';
// User 1 tags: 'foo', 'bar'.
core_tag_tag::set_item_tags($component, $itemtype, $user1->id, $context1, array_slice($tagnames, 0, 2));
// User 2 tags: 'bar', 'baz'.
core_tag_tag::set_item_tags($component, $itemtype, $user2->id, $context2, array_slice($tagnames, 1, 2));
// User 3 tags: 'bop', 'bam'.
core_tag_tag::set_item_tags($component, $itemtype, $user3->id, $context3, array_slice($tagnames, 3, 2));
$result = core_tag_tag::get_tags_by_area_in_contexts($component, $itemtype, [$context1, $context2]);
// Both User 1 and 2 have tagged using 'bar' but we don't
// expect duplicate tags in the result since they are the same
// tag.
//
// User 3 has tagged 'bop' and 'bam' but we aren't searching in
// that context so they shouldn't be in the results.
$expected = ['foo', 'bar', 'baz'];
$actual = array_map(function($t) {
return $t->name;
}, $result);
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
}
/**
* Help method to return sorted array of names of correlated tags to use for assertions
* @param core_tag $tag