/** * Clean up the tag tables, making sure all tagged object still exists. * * This should normally not be necessary, but in case related tags are not deleted when the tagged record is removed, this should be * done once in a while, perhaps on an occasional cron run. On a site with lots of tags, this could become an expensive function to * call: don't run at peak time. * * @package core_tag * @access private * @todo MDL-31212 Update tag cleanup sql so that it supports multiple types of tags */ function tag_cleanup() { global $DB; // Get ids to delete from instances where the tag has been deleted. This should never happen apparently. $sql = "SELECT ti.id\n FROM {tag_instance} ti\n LEFT JOIN {tag} t ON t.id = ti.tagid\n WHERE t.id IS null"; $tagids = $DB->get_records_sql($sql); $tagarray = array(); foreach ($tagids as $tagid) { $tagarray[] = $tagid->id; } // Next get ids from instances that have an owner that has been deleted. $sql = "SELECT ti.id\n FROM {tag_instance} ti, {user} u\n WHERE ti.itemid = u.id\n AND ti.itemtype = 'user'\n AND u.deleted = 1"; $tagids = $DB->get_records_sql($sql); foreach ($tagids as $tagid) { $tagarray[] = $tagid->id; } // Get the other itemtypes. $sql = "SELECT itemtype\n FROM {tag_instance}\n WHERE itemtype <> 'user'\n GROUP BY itemtype"; $tagitemtypes = $DB->get_records_sql($sql); foreach ($tagitemtypes as $key => $notused) { $sql = 'SELECT ti.id FROM {tag_instance} ti LEFT JOIN {' . $key . '} it ON it.id = ti.itemid WHERE it.id IS null AND ti.itemtype = \'' . $key . '\''; $tagids = $DB->get_records_sql($sql); foreach ($tagids as $tagid) { $tagarray[] = $tagid->id; } } // Get instances for each of the ids to be deleted. if (count($tagarray) > 0) { list($sqlin, $params) = $DB->get_in_or_equal($tagarray); $sql = "SELECT ti.*, COALESCE(t.name, 'deleted') AS name, COALESCE(t.rawname, 'deleted') AS rawname\n FROM {tag_instance} ti\n LEFT JOIN {tag} t ON t.id = ti.tagid\n WHERE ti.id {$sqlin}"; $instances = $DB->get_records_sql($sql, $params); tag_bulk_delete_instances($instances); } // TODO MDL-31212 this will only clean tags of type 'default'. This is good as // it won't delete 'official' tags, but the day we get more than two // types, we need to fix this. $unused_tags = $DB->get_recordset_sql("SELECT tg.id\n FROM {tag} tg\n WHERE tg.tagtype = 'default'\n AND NOT EXISTS (\n SELECT 'x'\n FROM {tag_instance} ti\n WHERE ti.tagid = tg.id\n )"); // cleanup tags foreach ($unused_tags as $unused_tag) { tag_delete($unused_tag->id); //debugging('deleting unused tag #'. $unused_tag->id, DEBUG_DEVELOPER); } $unused_tags->close(); }
/** * Test deleting a group of tag instances. */ public function test_tag_bulk_delete_instances() { global $DB; // Setup. $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $context = context_course::instance($course->id); // Create some tag instances. for ($i = 0; $i < 10; $i++) { $tag = $this->getDataGenerator()->create_tag(array('userid' => $user->id)); tag_assign('course', $course->id, $tag->id, 0, 0, 'core', $context->id); } // Get tag instances. tag name and rawname are required for the event fired in this function. $sql = "SELECT ti.*, t.name, t.rawname\n FROM {tag_instance} ti\n JOIN {tag} t ON t.id = ti.tagid"; $taginstances = $DB->get_records_sql($sql); $this->assertCount(10, $taginstances); // Run the function. tag_bulk_delete_instances($taginstances); // Make sure they are gone. $instancecount = $DB->count_records('tag_instance'); $this->assertEquals(0, $instancecount); }