diff --git a/tag/classes/area.php b/tag/classes/area.php index 23a95edb60f00..7debad9a38178 100644 --- a/tag/classes/area.php +++ b/tag/classes/area.php @@ -412,14 +412,21 @@ public static function move_tags($component, $itemtype, $tagcollid) { LEFT JOIN {tag} tt ON tt.name = t.name AND tt.tagcollid = :tagcollid2 WHERE ti.itemtype = :itemtype2 AND ti.component = :component2 AND tt.id IS NULL)"; - $todelete = array(); + $movedtags = array(); // Keep track of moved tags so we don't hit DB index violation. $result = $DB->get_records_sql($sql, $params); foreach ($result as $tag) { $originaltagid = $tag->id; - unset($tag->id); - $tag->tagcollid = $tagcollid; - $tag->id = $DB->insert_record('tag', $tag); - \core\event\tag_created::create_from_tag($tag); + if (array_key_exists($tag->name, $movedtags)) { + // Case of corrupted data when the same tag was in several collections. + $tag->id = $movedtags[$tag->name]; + } else { + // Copy the tag into the new collection. + unset($tag->id); + $tag->tagcollid = $tagcollid; + $tag->id = $DB->insert_record('tag', $tag); + \core\event\tag_created::create_from_tag($tag); + $movedtags[$tag->name] = $tag->id; + } $DB->execute("UPDATE {tag_instance} SET tagid = ? WHERE tagid = ? AND itemtype = ? AND component = ?", array($tag->id, $originaltagid, $itemtype, $component)); } diff --git a/tag/tests/taglib_test.php b/tag/tests/taglib_test.php index 85add32029c6b..9eb2efbfdaaa0 100644 --- a/tag/tests/taglib_test.php +++ b/tag/tests/taglib_test.php @@ -813,6 +813,39 @@ public function test_move_tags_with_related() { $this->assertEquals('Tag2, Tag4', join(', ', $related21)); } + public function test_move_tags_corrupted() { + global $DB; + list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags(); + $collid3 = core_tag_collection::create(array('name' => 'weirdcoll'))->id; + + // We already have Tag1 in coll1, now let's create it in coll3. + $extratag1 = $this->getDataGenerator()->create_tag(array('rawname' => 'Tag1', + 'tagcollid' => $collid3, 'tagtype' => 'official')); + + // Artificially add 'Tag1' from coll3 to user2. + $DB->insert_record('tag_instance', array('tagid' => $extratag1->id, 'itemtype' => 'user', + 'component' => 'core', 'itemid' => $user2->id, 'ordering' => 3)); + + // Now we have corrupted data: both users are tagged with 'Tag1', however these are two tags in different collections. + $user1tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user1->id)); + $user2tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user2->id)); + $this->assertEquals('Tag1', $user1tags[0]->rawname); + $this->assertEquals('Tag1', $user2tags[2]->rawname); + $this->assertNotEquals($user1tags[0]->tagcollid, $user2tags[2]->tagcollid); + + // Move user interests tag area into coll2. + $tagarea = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core')); + core_tag_area::update($tagarea, array('tagcollid' => $collid2)); + + // Now all tags are correctly moved to the new collection and both tags 'Tag1' were merged. + $user1tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user1->id)); + $user2tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user2->id)); + $this->assertEquals('Tag1', $user1tags[0]->rawname); + $this->assertEquals('Tag1', $user2tags[2]->rawname); + $this->assertEquals($collid2, $user1tags[0]->tagcollid); + $this->assertEquals($collid2, $user2tags[2]->tagcollid); + } + public function test_normalize() { $tagset = array('Cat', ' Dog ', '', 'mouse', 'Dog');