/** * Assigns a tag to a record; if the record already exists, the time and ordering will be updated. * * @package core_tag * @access private * @param string $record_type the type of the record that will be tagged * @param int $record_id the id of the record that will be tagged * @param string $tagid the tag id to set on the record. * @param int $ordering the order of the instance for this record * @param int $userid (optional) only required for course tagging * @param string|null $component the component that was tagged * @param int|null $contextid the context id of where this tag was assigned * @return bool true on success, false otherwise */ function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0, $component = null, $contextid = null) { global $DB; if ($component === null || $contextid === null) { debugging('You should specify the component and contextid of the item being tagged in your call to tag_assign.', DEBUG_DEVELOPER); } // Get the tag. $tag = $DB->get_record('tag', array('id' => $tagid), 'name, rawname', MUST_EXIST); if ($tag_instance_object = $DB->get_record('tag_instance', array('tagid' => $tagid, 'itemtype' => $record_type, 'itemid' => $record_id, 'tiuserid' => $userid), 'id')) { $tag_instance_object->ordering = $ordering; $tag_instance_object->timemodified = time(); $DB->update_record('tag_instance', $tag_instance_object); } else { $tag_instance_object = new StdClass(); $tag_instance_object->tagid = $tagid; $tag_instance_object->component = $component; $tag_instance_object->itemid = $record_id; $tag_instance_object->itemtype = $record_type; $tag_instance_object->contextid = $contextid; $tag_instance_object->ordering = $ordering; $tag_instance_object->timecreated = time(); $tag_instance_object->timemodified = $tag_instance_object->timecreated; $tag_instance_object->tiuserid = $userid; $tag_instance_object->id = $DB->insert_record('tag_instance', $tag_instance_object); } // We can not fire an event with 'null' as the contextid. if (is_null($contextid)) { $contextid = context_system::instance()->id; } // Trigger tag added event. $event = \core\event\tag_added::create(array('objectid' => $tag_instance_object->id, 'contextid' => $contextid, 'other' => array('tagid' => $tagid, 'tagname' => $tag->name, 'tagrawname' => $tag->rawname, 'itemid' => $record_id, 'itemtype' => $record_type))); $event->trigger(); return true; }
/** * Adds a tag instance * * @param string $component * @param string $itemtype * @param string $itemid * @param context $context * @param int $ordering * @param int $tiuserid tag instance user id, only needed for tag areas with user tagging (such as core/course) * @return int id of tag_instance */ protected function add_instance($component, $itemtype, $itemid, context $context, $ordering, $tiuserid = 0) { global $DB; $this->ensure_fields_exist(array('name', 'rawname'), 'add_instance'); $taginstance = new StdClass(); $taginstance->tagid = $this->id; $taginstance->component = $component ? $component : ''; $taginstance->itemid = $itemid; $taginstance->itemtype = $itemtype; $taginstance->contextid = $context->id; $taginstance->ordering = $ordering; $taginstance->timecreated = time(); $taginstance->timemodified = $taginstance->timecreated; $taginstance->tiuserid = $tiuserid; $taginstance->id = $DB->insert_record('tag_instance', $taginstance); // Trigger tag added event. \core\event\tag_added::create_from_tag_instance($taginstance, $this->name, $this->rawname, true)->trigger(); return $taginstance->id; }
/** * 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); }