/** * Delete one or more tag, and all their instances if there are any left. * * @param int|array $tagids one tagid (int), or one array of tagids to delete * @return bool true on success, false otherwise */ public static function delete_tags($tagids) { global $DB; if (!is_array($tagids)) { $tagids = array($tagids); } if (empty($tagids)) { return; } // Use the tagids to create a select statement to be used later. list($tagsql, $tagparams) = $DB->get_in_or_equal($tagids); // Store the tags and tag instances we are going to delete. $tags = $DB->get_records_select('tag', 'id ' . $tagsql, $tagparams); $taginstances = $DB->get_records_select('tag_instance', 'tagid ' . $tagsql, $tagparams); // Delete all the tag instances. $select = 'WHERE tagid ' . $tagsql; $sql = "DELETE FROM {tag_instance} {$select}"; $DB->execute($sql, $tagparams); // Delete all the tag correlations. $sql = "DELETE FROM {tag_correlation} {$select}"; $DB->execute($sql, $tagparams); // Delete all the tags. $select = 'WHERE id ' . $tagsql; $sql = "DELETE FROM {tag} {$select}"; $DB->execute($sql, $tagparams); // Fire an event that these items were untagged. if ($taginstances) { // Save the system context in case the 'contextid' column in the 'tag_instance' table is null. $syscontextid = context_system::instance()->id; // Loop through the tag instances and fire a 'tag_removed'' event. foreach ($taginstances as $taginstance) { // We can not fire an event with 'null' as the contextid. if (is_null($taginstance->contextid)) { $taginstance->contextid = $syscontextid; } // Trigger tag removed event. \core\event\tag_removed::create_from_tag_instance($taginstance, $tags[$taginstance->tagid]->name, $tags[$taginstance->tagid]->rawname, true)->trigger(); } } // Fire an event that these tags were deleted. if ($tags) { $context = context_system::instance(); foreach ($tags as $tag) { // Delete all files associated with this tag. $fs = get_file_storage(); $files = $fs->get_area_files($context->id, 'tag', 'description', $tag->id); foreach ($files as $file) { $file->delete(); } // Trigger an event for deleting this tag. $event = \core\event\tag_deleted::create(array('objectid' => $tag->id, 'relateduserid' => $tag->userid, 'context' => $context, 'other' => array('name' => $tag->name, 'rawname' => $tag->rawname))); $event->add_record_snapshot('tag', $tag); $event->trigger(); } } return true; }
/** * This function will delete numerous tag instances efficiently. * This removes tag instances only. It doesn't check to see if it is the last use of a tag. * * @param array $instances An array of tag instance objects with the addition of the tagname and tagrawname * (used for recording a delete event). */ function tag_bulk_delete_instances($instances) { global $DB; $instanceids = array(); foreach ($instances as $instance) { $instanceids[] = $instance->id; } // This is a multi db compatible method of creating the correct sql when using the 'IN' value. // $insql is the sql statement, $params are the id numbers. list($insql, $params) = $DB->get_in_or_equal($instanceids); $sql = 'id ' . $insql; $DB->delete_records_select('tag_instance', $sql, $params); // Now go through and record each tag individually with the event system. foreach ($instances as $instance) { // Trigger tag removed event (i.e. The tag instance has been removed). $event = \core\event\tag_removed::create(array('objectid' => $instance->id, 'contextid' => $instance->contextid, 'other' => array('tagid' => $instance->tagid, 'tagname' => $instance->name, 'tagrawname' => $instance->rawname, 'itemid' => $instance->itemid, 'itemtype' => $instance->itemtype))); unset($instance->name); unset($instance->rawname); $event->add_record_snapshot('tag_instance', $instance); $event->trigger(); } }
/** * This function will delete numerous tag instances efficiently. * This removes tag instances only. It doesn't check to see if it is the last use of a tag. * * @param array $instances An array of tag instance objects with the addition of the tagname and tagrawname * (used for recording a delete event). */ public function bulk_delete_instances($instances) { global $DB; $instanceids = array(); foreach ($instances as $instance) { $instanceids[] = $instance->id; } // This is a multi db compatible method of creating the correct sql when using the 'IN' value. // $insql is the sql statement, $params are the id numbers. list($insql, $params) = $DB->get_in_or_equal($instanceids); $sql = 'id ' . $insql; $DB->delete_records_select('tag_instance', $sql, $params); // Now go through and record each tag individually with the event system. foreach ($instances as $instance) { // Trigger tag removed event (i.e. The tag instance has been removed). \core\event\tag_removed::create_from_tag_instance($instance, $instance->name, $instance->rawname, true)->trigger(); } }
/** * Delete one instance of a tag. If the last instance was deleted, it will also delete the tag, unless its type is 'official'. * * @package core_tag * @category tag * @access public * @param string $record_type the type of the record for which to remove the instance * @param int $record_id the id of the record for which to remove the instance * @param int $tagid the tagid that needs to be removed * @param int $userid (optional) the userid * @return bool true on success, false otherwise */ function tag_delete_instance($record_type, $record_id, $tagid, $userid = null) { global $DB; if (is_null($userid)) { $taginstance = $DB->get_record('tag_instance', array('tagid' => $tagid, 'itemtype' => $record_type, 'itemid' => $record_id)); } else { $taginstance = $DB->get_record('tag_instance', array('tagid' => $tagid, 'itemtype' => $record_type, 'itemid' => $record_id, 'tiuserid' => $userid)); } if ($taginstance) { // Get the tag. $tag = $DB->get_record('tag', array('id' => $tagid)); $DB->delete_records('tag_instance', array('id' => $taginstance->id)); // We can not fire an event with 'null' as the contextid. if (is_null($taginstance->contextid)) { $taginstance->contextid = context_system::instance()->id; } // Trigger tag removed event. $event = \core\event\tag_removed::create(array('objectid' => $taginstance->id, 'contextid' => $taginstance->contextid, 'other' => array('tagid' => $tag->id, 'tagname' => $tag->name, 'tagrawname' => $tag->rawname, 'itemid' => $taginstance->itemid, 'itemtype' => $taginstance->itemtype))); $event->add_record_snapshot('tag_instance', $taginstance); $event->trigger(); // If there are no other instances of the tag then consider deleting the tag as well. if (!$DB->record_exists('tag_instance', array('tagid' => $tagid))) { // If the tag is a personal tag then delete it - don't delete official tags. if ($tag->tagtype == 'default') { tag_delete($tagid); } } } else { return false; } return true; }
/** * Combines several other tags into this one * * Combining rules: * - current tag becomes the "main" one, all instances * pointing to other tags are changed to point to it. * - if any of the tags is standard, the "main" tag becomes standard too * - all tags except for the current ("main") are deleted, even when they are standard * * @param core_tag_tag[] $tags tags to combine into this one */ public function combine_tags($tags) { global $DB; $this->ensure_fields_exist(array('id', 'tagcollid', 'isstandard', 'name', 'rawname'), 'combine_tags'); // Retrieve all tag objects, find if there are any standard tags in the set. $isstandard = false; $tagstocombine = array(); $ids = array(); $relatedtags = $this->get_manual_related_tags(); foreach ($tags as $tag) { $tag->ensure_fields_exist(array('id', 'tagcollid', 'isstandard', 'tagcollid', 'name', 'rawname'), 'combine_tags'); if ($tag && $tag->id != $this->id && $tag->tagcollid == $this->tagcollid) { $isstandard = $isstandard || $tag->isstandard; $tagstocombine[$tag->name] = $tag; $ids[] = $tag->id; $relatedtags = array_merge($relatedtags, $tag->get_manual_related_tags()); } } if (empty($tagstocombine)) { // Nothing to do. return; } // Combine all manually set related tags, exclude itself all the tags it is about to be combined with. if ($relatedtags) { $relatedtags = array_map(function ($t) { return $t->name; }, $relatedtags); array_unique($relatedtags); $relatedtags = array_diff($relatedtags, [$this->name], array_keys($tagstocombine)); } $this->set_related_tags($relatedtags); // Combine all correlated tags, exclude itself all the tags it is about to be combined with. $this->combine_correlated_tags($tagstocombine); // If any of the duplicate tags are standard, mark this one as standard too. if ($isstandard && !$this->isstandard) { $this->update(array('isstandard' => 1)); } // Go through all instances of each tag that needs to be combined and make them point to this tag instead. // We go though the list one by one because otherwise looking-for-duplicates logic would be too complicated. foreach ($tagstocombine as $tag) { $params = array('tagid' => $tag->id, 'mainid' => $this->id); $mainsql = 'SELECT ti.*, t.name, t.rawname, tim.id AS alreadyhasmaintag ' . 'FROM {tag_instance} ti ' . 'LEFT JOIN {tag} t ON t.id = ti.tagid ' . 'LEFT JOIN {tag_instance} tim ON ti.component = tim.component AND ' . ' ti.itemtype = tim.itemtype AND ti.itemid = tim.itemid AND ' . ' ti.tiuserid = tim.tiuserid AND tim.tagid = :mainid ' . 'WHERE ti.tagid = :tagid'; $records = $DB->get_records_sql($mainsql, $params); foreach ($records as $record) { if ($record->alreadyhasmaintag) { // Item is tagged with both main tag and the duplicate tag. // Remove instance pointing to the duplicate tag. $tag->delete_instance_as_record($record, false); $sql = "UPDATE {tag_instance} SET ordering = ordering - 1\n WHERE itemtype = :itemtype\n AND itemid = :itemid AND component = :component AND tiuserid = :tiuserid\n AND ordering > :ordering"; $DB->execute($sql, (array) $record); } else { // Item is tagged only with duplicate tag but not the main tag. // Replace tagid in the instance pointing to the duplicate tag with this tag. $DB->update_record('tag_instance', array('id' => $record->id, 'tagid' => $this->id)); \core\event\tag_removed::create_from_tag_instance($record, $record->name, $record->rawname)->trigger(); $record->tagid = $this->id; \core\event\tag_added::create_from_tag_instance($record, $this->name, $this->rawname)->trigger(); } } } // Finally delete all tags that we combined into the current one. self::delete_tags($ids); }