* @return void
*/
function tag_set($record_type, $record_id, $tags) {
- global $db;
- $record = array('type' => $record_type, 'id' => $record_id);
+ static $in_recursion_semaphore = false; // this is to prevent loops when tagging a tag
+ if ( $record_type == 'tag' && !$in_recursion_semaphore) {
+ $current_tagged_tag_name = tag_get_name($record_id);
+ }
$tags_ids = tag_get_id($tags, TAG_RETURN_ARRAY); // force an array, even if we only have one tag.
$cleaned_tags = tag_normalize($tags);
//echo 'tags-in-tag_set'; var_dump($tags); var_dump($tags_ids); var_dump($cleaned_tags);
- $current_ids = tag_get_tags_ids($record['type'], $record['id']);
- //var_dump($current_ids);
- $tags_to_assign = array();
+ $current_ids = tag_get_tags_ids($record_type, $record_id);
+ //var_dump($current_ids);
// for data coherence reasons, it's better to remove deleted tags
// before adding new data: ordering could be duplicated.
foreach($current_ids as $current_id) {
if (!in_array($current_id, $tags_ids)) {
- tag_delete_instance($record, $current_id);
+ tag_delete_instance($record_type, $record_id, $current_id);
+ if ( $record_type == 'tag' && !$in_recursion_semaphore) {
+ // if we are removing a tag-on-a-tag (manually related tag),
+ // we need to remove the opposite relationship as well.
+ tag_delete_instance('tag', $current_id, $record_id);
+ }
}
}
// create new tags
//echo "call to add tag $tag\n";
$new_tag = tag_add($tag);
- tag_assign($record, $new_tag[$clean_tag], $ordering);
- }
- elseif ( empty($current_ids) || !in_array($tag_current_id, $current_ids) ) {
- // assign existing tags
- tag_assign($record, $tag_current_id, $ordering);
- }
- elseif ( isset($current_ids[$ordering]) && $current_ids[$ordering] != $tag_current_id ) {
- // this actually checks if the ordering number points to the same tag
- //recompute ordering, if necessary
- //echo 'ordering changed for ', $tag, ':', $ordering, "\n";
- tag_assign($record, $tag_current_id, $ordering);
+ $tag_current_id = $new_tag[$clean_tag];
+ }
+
+ tag_assign($record_type, $record_id, $tag_current_id, $ordering);
+
+ // if we are tagging a tag (adding a manually-assigned related tag), we
+ // need to create the opposite relationship as well.
+ if ( $record_type == 'tag' && !$in_recursion_semaphore) {
+ $in_recursion_semaphore = true;
+ tag_set_add('tag', $tag_current_id, $current_tagged_tag_name);
+ $in_recursion_semaphore = false;
}
}
}
$new_tags[] = $current_tag->name;
}
}
-
+
return tag_set($record_type, $record_id, $new_tags);
}
**/
function tag_get($field, $value, $returnfields='id, name, rawname') {
if ($field == 'name') {
- $value = moodle_strtolower($value); // To cope with input that might just be wrong case
+ $value = addslashes(moodle_strtolower($value)); // To cope with input that might just be wrong case
}
return get_record('tag', $field, $value, '', '', '', '', $returnfields);
}
/**
* Get an array of tag ids associated to a record.
*
- * @param string $record the record type for which we want to get the tags
+ * @param string $record_type the record type for which we want to get the tags
* @param int $record_id the record id for which we want to get the tags
* @return array of tag ids, indexed and sorted by 'ordering'
*/
$tag_ids = array();
foreach (tag_get_tags($record_type, $record_id) as $tag) {
+ if ( array_key_exists($tag->ordering, $tag_ids) ) {
+ // until we can add a unique constraint, in table tag_instance,
+ // on (itemtype, itemid, ordering), this is needed to prevent a bug
+ // TODO : modify database in 2.0
+ $tag->ordering++;
+ }
$tag_ids[$tag->ordering] = $tag->id;
}
ksort($tag_ids);
* Delete one instance of a tag. If the last instance was deleted, it will
* also delete the tag, unless it's type is 'official'.
*
- * @param array $record the record for which to remove the instance
+ * @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
* @return bool true on success, false otherwise
*/
-function tag_delete_instance($record, $tagid) {
+function tag_delete_instance($record_type, $record_id, $tagid) {
global $CFG;
- if ( delete_records('tag_instance', 'tagid', $tagid, 'itemtype', $record['type'], 'itemid', $record['id']) ) {
+ if ( delete_records('tag_instance', 'tagid', $tagid, 'itemtype', $record_type, 'itemid', $record_id) ) {
if ( !record_exists_sql("SELECT * FROM {$CFG->prefix}tag tg, {$CFG->prefix}tag_instance ti ".
"WHERE (tg.id = ti.tagid AND ti.tagid = {$tagid} ) OR ".
"(tg.id = {$tagid} AND tg.tagtype = 'official')") ) {
* Assigns a tag to a record: if the record already exists, the time and
* ordering will be updated.
*
- * @param array $record the record that will be tagged
+ * @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
* @return bool true on success, false otherwise
*/
-function tag_assign($record, $tagid, $ordering) {
+function tag_assign($record_type, $record_id, $tagid, $ordering) {
require_capability('moodle/tag:create', get_context_instance(CONTEXT_SYSTEM));
- if ( $tag_instance_object = get_record('tag_instance', 'tagid', $tagid, 'itemtype', $record['type'], 'itemid', $record['id'], 'tagid') ) {
+ if ( $tag_instance_object = get_record('tag_instance', 'tagid', $tagid, 'itemtype', $record_type, 'itemid', $record_id, 'id') ) {
$tag_instance_object->ordering = $ordering;
$tag_instance_object->timemodified = time();
return update_record('tag_instance', $tag_instance_object);
} else {
$tag_instance_object = new StdClass;
$tag_instance_object->tagid = $tagid;
- $tag_instance_object->itemid = $record['id'];
- $tag_instance_object->itemtype = $record['type'];
+ $tag_instance_object->itemid = $record_id;
+ $tag_instance_object->itemtype = $record_type;
$tag_instance_object->ordering = $ordering;
$tag_instance_object->timemodified = time();
return insert_record('tag_instance', $tag_instance_object);