|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00053 define('TAG_RETURN_ARRAY', 0); 00054 define('TAG_RETURN_OBJECT', 1); 00055 define('TAG_RETURN_TEXT', 2); 00056 define('TAG_RETURN_HTML', 3); 00057 00058 define('TAG_CASE_LOWER', 0); 00059 define('TAG_CASE_ORIGINAL', 1); 00060 00061 define('TAG_RELATED_ALL', 0); 00062 define('TAG_RELATED_MANUAL', 1); 00063 define('TAG_RELATED_CORRELATED', 2); 00064 00067 00069 00083 function tag_set($record_type, $record_id, $tags) { 00084 00085 static $in_recursion_semaphore = false; // this is to prevent loops when tagging a tag 00086 if ( $record_type == 'tag' && !$in_recursion_semaphore) { 00087 $current_tagged_tag_name = tag_get_name($record_id); 00088 } 00089 00090 $tags_ids = tag_get_id($tags, TAG_RETURN_ARRAY); // force an array, even if we only have one tag. 00091 $cleaned_tags = tag_normalize($tags); 00092 //echo 'tags-in-tag_set'; var_dump($tags); var_dump($tags_ids); var_dump($cleaned_tags); 00093 00094 $current_ids = tag_get_tags_ids($record_type, $record_id); 00095 //var_dump($current_ids); 00096 00097 // for data coherence reasons, it's better to remove deleted tags 00098 // before adding new data: ordering could be duplicated. 00099 foreach($current_ids as $current_id) { 00100 if (!in_array($current_id, $tags_ids)) { 00101 tag_delete_instance($record_type, $record_id, $current_id); 00102 if ( $record_type == 'tag' && !$in_recursion_semaphore) { 00103 // if we are removing a tag-on-a-tag (manually related tag), 00104 // we need to remove the opposite relationship as well. 00105 tag_delete_instance('tag', $current_id, $record_id); 00106 } 00107 } 00108 } 00109 00110 if (empty($tags)) { 00111 return true; 00112 } 00113 00114 foreach($tags as $ordering => $tag) { 00115 $tag = trim($tag); 00116 if (!$tag) { 00117 continue; 00118 } 00119 00120 $clean_tag = $cleaned_tags[$tag]; 00121 $tag_current_id = $tags_ids[$clean_tag]; 00122 00123 if ( is_null($tag_current_id) ) { 00124 // create new tags 00125 //echo "call to add tag $tag\n"; 00126 $new_tag = tag_add($tag); 00127 $tag_current_id = $new_tag[$clean_tag]; 00128 } 00129 00130 tag_assign($record_type, $record_id, $tag_current_id, $ordering); 00131 00132 // if we are tagging a tag (adding a manually-assigned related tag), we 00133 // need to create the opposite relationship as well. 00134 if ( $record_type == 'tag' && !$in_recursion_semaphore) { 00135 $in_recursion_semaphore = true; 00136 tag_set_add('tag', $tag_current_id, $current_tagged_tag_name); 00137 $in_recursion_semaphore = false; 00138 } 00139 } 00140 } 00141 00151 function tag_set_add($record_type, $record_id, $tag) { 00152 00153 $new_tags = array(); 00154 foreach( tag_get_tags($record_type, $record_id) as $current_tag ) { 00155 $new_tags[] = $current_tag->rawname; 00156 } 00157 $new_tags[] = $tag; 00158 00159 return tag_set($record_type, $record_id, $new_tags); 00160 } 00161 00171 function tag_set_delete($record_type, $record_id, $tag) { 00172 00173 $new_tags = array(); 00174 foreach( tag_get_tags($record_type, $record_id) as $current_tag ) { 00175 if ($current_tag->name != $tag) { // Keep all tags but the one specified 00176 $new_tags[] = $current_tag->name; 00177 } 00178 } 00179 00180 return tag_set($record_type, $record_id, $new_tags); 00181 } 00182 00192 function tag_type_set($tagid, $type) { 00193 global $DB; 00194 00195 if ($tag = $DB->get_record('tag', array('id'=>$tagid), 'id')) { 00196 $tag->tagtype = $type; 00197 $tag->timemodified = time(); 00198 return $DB->update_record('tag', $tag); 00199 } 00200 return false; 00201 } 00202 00203 00212 function tag_description_set($tagid, $description, $descriptionformat) { 00213 global $DB; 00214 00215 if ($tag = $DB->get_record('tag', array('id'=>$tagid),'id')) { 00216 $tag->description = $description; 00217 $tag->descriptionformat = $descriptionformat; 00218 $tag->timemodified = time(); 00219 return $DB->update_record('tag', $tag); 00220 } 00221 return false; 00222 } 00223 00224 00225 00226 00227 00228 00230 00240 function tag_get($field, $value, $returnfields='id, name, rawname') { 00241 global $DB; 00242 00243 if ($field == 'name') { 00244 $value = moodle_strtolower($value); // To cope with input that might just be wrong case 00245 } 00246 return $DB->get_record('tag', array($field=>$value), $returnfields); 00247 } 00248 00249 00262 function tag_get_tags($record_type, $record_id, $type=null, $userid=0) { 00263 global $CFG, $DB; 00264 00265 $params = array(); 00266 00267 if ($type) { 00268 $sql_type = "AND tg.tagtype = :type"; 00269 $params['type'] = $type; 00270 } else { 00271 $sql_type = ''; 00272 } 00273 00274 $u = null; 00275 if ($userid) { 00276 $u = "AND ti.tiuserid = :userid "; 00277 $params['userid'] = $userid; 00278 } 00279 00280 $sql = "SELECT tg.id, tg.tagtype, tg.name, tg.rawname, tg.flag, ti.ordering 00281 FROM {tag_instance} ti 00282 JOIN {tag} tg ON tg.id = ti.tagid 00283 WHERE ti.itemtype = :recordtype AND ti.itemid = :recordid $u $sql_type 00284 ORDER BY ti.ordering ASC"; 00285 $params['recordtype'] = $record_type; 00286 $params['recordid'] = $record_id; 00287 00288 // if the fields in this query are changed, you need to do the same changes in tag_get_correlated_tags 00289 return $DB->get_records_sql($sql, $params); 00290 // This version of the query, reversing the ON clause, "correctly" returns 00291 // a row with NULL values for instances that are still in the DB even though 00292 // the tag has been deleted. This shouldn't happen, but if it did, using 00293 // this query could help "clean it up". This causes bugs at this time. 00294 //$tags = $DB->get_records_sql("SELECT ti.tagid, tg.tagtype, tg.name, tg.rawname, tg.flag, ti.ordering ". 00295 // "FROM {tag_instance} ti LEFT JOIN {tag} tg ON ti.tagid = tg.id ". 00296 // "WHERE ti.itemtype = '{$record_type}' AND ti.itemid = '{$record_id}' {$type} ". 00297 // "ORDER BY ti.ordering ASC"); 00298 } 00299 00309 function tag_get_tags_array($record_type, $record_id, $type=null) { 00310 $tags = array(); 00311 foreach(tag_get_tags($record_type, $record_id, $type) as $tag) { 00312 $tags[$tag->id] = tag_display_name($tag); 00313 } 00314 return $tags; 00315 } 00316 00329 function tag_get_tags_csv($record_type, $record_id, $html=TAG_RETURN_HTML, $type=null) { 00330 global $CFG; 00331 00332 $tags_names = array(); 00333 foreach(tag_get_tags($record_type, $record_id, $type) as $tag) { 00334 if ($html == TAG_RETURN_TEXT) { 00335 $tags_names[] = tag_display_name($tag, TAG_RETURN_TEXT); 00336 } else { // TAG_RETURN_HTML 00337 $tags_names[] = '<a href="'. $CFG->wwwroot .'/tag/index.php?tag='. rawurlencode($tag->name) .'">'. tag_display_name($tag) .'</a>'; 00338 } 00339 } 00340 return implode(', ', $tags_names); 00341 } 00342 00350 function tag_get_tags_ids($record_type, $record_id) { 00351 00352 $tag_ids = array(); 00353 foreach (tag_get_tags($record_type, $record_id) as $tag) { 00354 if ( array_key_exists($tag->ordering, $tag_ids) ) { 00355 // until we can add a unique constraint, in table tag_instance, 00356 // on (itemtype, itemid, ordering), this is needed to prevent a bug 00357 // TODO : modify database in 2.0 00358 $tag->ordering++; 00359 } 00360 $tag_ids[$tag->ordering] = $tag->id; 00361 } 00362 ksort($tag_ids); 00363 return $tag_ids; 00364 } 00365 00378 function tag_get_id($tags, $return_value=null) { 00379 global $CFG, $DB; 00380 00381 static $tag_id_cache = array(); 00382 00383 $return_an_int = false; 00384 if (!is_array($tags)) { 00385 if(is_null($return_value) || $return_value == TAG_RETURN_OBJECT) { 00386 $return_an_int = true; 00387 } 00388 $tags = array($tags); 00389 } 00390 00391 $result = array(); 00392 00393 //TODO: test this and see if it helps performance without breaking anything 00394 //foreach($tags as $key => $tag) { 00395 // $clean_tag = moodle_strtolower($tag); 00396 // if ( array_key_exists($clean_tag), $tag_id_cache) ) { 00397 // $result[$clean_tag] = $tag_id_cache[$clean_tag]; 00398 // $tags[$key] = ''; // prevent further processing for this one. 00399 // } 00400 //} 00401 00402 $tags = array_values(tag_normalize($tags)); 00403 foreach($tags as $key => $tag) { 00404 $tags[$key] = moodle_strtolower($tag); 00405 $result[moodle_strtolower($tag)] = null; // key must exists : no value for a key means the tag wasn't found. 00406 } 00407 00408 if (empty($tags)) { 00409 return array(); 00410 } 00411 00412 list($tag_string, $params) = $DB->get_in_or_equal($tags); 00413 00414 $rs = $DB->get_recordset_sql("SELECT * FROM {tag} WHERE name $tag_string ORDER BY name", $params); 00415 foreach ($rs as $record) { 00416 if ($return_value == TAG_RETURN_OBJECT) { 00417 $result[$record->name] = $record; 00418 } else { // TAG_RETURN_ARRAY 00419 $result[$record->name] = $record->id; 00420 } 00421 } 00422 $rs->close(); 00423 00424 if ($return_an_int) { 00425 return array_pop($result); 00426 } 00427 00428 return $result; 00429 } 00430 00431 00448 function tag_get_related_tags($tagid, $type=TAG_RELATED_ALL, $limitnum=10) { 00449 00450 $related_tags = array(); 00451 00452 if ( $type == TAG_RELATED_ALL || $type == TAG_RELATED_MANUAL) { 00453 //gets the manually added related tags 00454 $related_tags = tag_get_tags('tag', $tagid); 00455 } 00456 00457 if ( $type == TAG_RELATED_ALL || $type == TAG_RELATED_CORRELATED ) { 00458 //gets the correlated tags 00459 $automatic_related_tags = tag_get_correlated($tagid, $limitnum); 00460 if (is_array($automatic_related_tags)) { 00461 $related_tags = array_merge($related_tags, $automatic_related_tags); 00462 } 00463 } 00464 00465 return array_slice(object_array_unique($related_tags), 0 , $limitnum); 00466 } 00467 00475 function tag_get_related_tags_csv($related_tags, $html=TAG_RETURN_HTML) { 00476 global $CFG; 00477 00478 $tags_names = array(); 00479 foreach($related_tags as $tag) { 00480 if ( $html == TAG_RETURN_TEXT) { 00481 $tags_names[] = tag_display_name($tag, TAG_RETURN_TEXT); 00482 } else { 00483 // TAG_RETURN_HTML 00484 $tags_names[] = '<a href="'. $CFG->wwwroot .'/tag/index.php?tag='. rawurlencode($tag->name) .'">'. tag_display_name($tag) .'</a>'; 00485 } 00486 } 00487 00488 return implode(', ', $tags_names); 00489 } 00490 00498 function tag_rename($tagid, $newrawname) { 00499 global $DB; 00500 00501 if (! $newrawname_clean = array_shift(tag_normalize($newrawname, TAG_CASE_ORIGINAL)) ) { 00502 return false; 00503 } 00504 00505 if (! $newname_clean = moodle_strtolower($newrawname_clean)) { 00506 return false; 00507 } 00508 00509 // Prevent the rename if a tag with that name already exists 00510 if ($existing = tag_get('name', $newname_clean, 'id, name, rawname')) { 00511 if ($existing->id != $tagid) { // Another tag already exists with this name 00512 return false; 00513 } 00514 } 00515 00516 if ($tag = tag_get('id', $tagid, 'id, name, rawname')) { 00517 $tag->rawname = $newrawname_clean; 00518 $tag->name = $newname_clean; 00519 $tag->timemodified = time(); 00520 return $DB->update_record('tag', $tag); 00521 } 00522 return false; 00523 } 00524 00525 00532 function tag_delete($tagids) { 00533 global $DB; 00534 00535 if (!is_array($tagids)) { 00536 $tagids = array($tagids); 00537 } 00538 00539 $success = true; 00540 $context = get_context_instance(CONTEXT_SYSTEM); 00541 foreach ($tagids as $tagid) { 00542 if (is_null($tagid)) { // can happen if tag doesn't exists 00543 continue; 00544 } 00545 // only delete the main entry if there were no problems deleting all the 00546 // instances - that (and the fact we won't often delete lots of tags) 00547 // is the reason for not using $DB->delete_records_select() 00548 if ($DB->delete_records('tag_instance', array('tagid'=>$tagid)) && $DB->delete_records('tag_correlation', array('tagid' => $tagid))) { 00549 $success &= (bool) $DB->delete_records('tag', array('id'=>$tagid)); 00550 // Delete all files associated with this tag 00551 $fs = get_file_storage(); 00552 $files = $fs->get_area_files($context->id, 'tag', 'description', $tagid); 00553 foreach ($files as $file) { 00554 $file->delete(); 00555 } 00556 } 00557 } 00558 00559 return $success; 00560 } 00561 00571 function tag_delete_instance($record_type, $record_id, $tagid) { 00572 global $CFG, $DB; 00573 00574 if ($DB->delete_records('tag_instance', array('tagid'=>$tagid, 'itemtype'=>$record_type, 'itemid'=>$record_id))) { 00575 if (!$DB->record_exists_sql("SELECT * ". 00576 "FROM {tag} tg ". 00577 "WHERE tg.id = ? AND ( tg.tagtype = 'official' OR ". 00578 "EXISTS (SELECT 1 00579 FROM {tag_instance} ti 00580 WHERE ti.tagid = ?) )", 00581 array($tagid, $tagid))) { 00582 return tag_delete($tagid); 00583 } 00584 } else { 00585 return false; 00586 } 00587 00588 return true; 00589 } 00590 00591 00599 function tag_display_name($tagobject, $html=TAG_RETURN_HTML) { 00600 00601 global $CFG; 00602 00603 if (!isset($tagobject->name)) { 00604 return ''; 00605 } 00606 00607 if (empty($CFG->keeptagnamecase)) { 00608 //this is the normalized tag name 00609 $textlib = textlib_get_instance(); 00610 $tagname = $textlib->strtotitle($tagobject->name); 00611 } else { 00612 //original casing of the tag name 00613 $tagname = $tagobject->rawname; 00614 } 00615 00616 // clean up a bit just in case the rules change again 00617 $tagname = clean_param($tagname, PARAM_TAG); 00618 00619 if ($html == TAG_RETURN_TEXT) { 00620 return $tagname; 00621 } else { // TAG_RETURN_HTML 00622 return htmlspecialchars($tagname); 00623 } 00624 } 00625 00636 function tag_find_records($tag, $type, $limitfrom='', $limitnum='') { 00637 global $CFG, $DB; 00638 00639 if (!$tag || !$type) { 00640 return array(); 00641 } 00642 00643 $tagid = tag_get_id($tag); 00644 00645 $query = "SELECT it.* 00646 FROM {".$type."} it INNER JOIN {tag_instance} tt ON it.id = tt.itemid 00647 WHERE tt.itemtype = ? AND tt.tagid = ?"; 00648 $params = array($type, $tagid); 00649 00650 return $DB->get_records_sql($query, $params, $limitfrom, $limitnum); 00651 } 00652 00653 00654 00655 00658 00670 function tag_add($tags, $type="default") { 00671 global $USER, $DB; 00672 00673 if (!is_array($tags)) { 00674 $tags = array($tags); 00675 } 00676 00677 $tag_object = new StdClass; 00678 $tag_object->tagtype = $type; 00679 $tag_object->userid = $USER->id; 00680 $tag_object->timemodified = time(); 00681 00682 $clean_tags = tag_normalize($tags, TAG_CASE_ORIGINAL); 00683 00684 $tags_ids = array(); 00685 foreach($clean_tags as $tag) { 00686 $tag = trim($tag); 00687 if (!$tag) { 00688 $tags_ids[$tag] = false; 00689 } else { 00690 // note that the difference between rawname and name is only 00691 // capitalization : the rawname is NOT the same at the rawtag. 00692 $tag_object->rawname = $tag; 00693 $tag_name_lc = moodle_strtolower($tag); 00694 $tag_object->name = $tag_name_lc; 00695 //var_dump($tag_object); 00696 $tags_ids[$tag_name_lc] = $DB->insert_record('tag', $tag_object); 00697 } 00698 } 00699 00700 return $tags_ids; 00701 } 00702 00714 function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0) { 00715 global $DB; 00716 00717 if ( $tag_instance_object = $DB->get_record('tag_instance', array('tagid'=>$tagid, 'itemtype'=>$record_type, 'itemid'=>$record_id, 'tiuserid'=>$userid), 'id')) { 00718 $tag_instance_object->ordering = $ordering; 00719 $tag_instance_object->timemodified = time(); 00720 return $DB->update_record('tag_instance', $tag_instance_object); 00721 } else { 00722 $tag_instance_object = new StdClass; 00723 $tag_instance_object->tagid = $tagid; 00724 $tag_instance_object->itemid = $record_id; 00725 $tag_instance_object->itemtype = $record_type; 00726 $tag_instance_object->ordering = $ordering; 00727 $tag_instance_object->timemodified = time(); 00728 $tag_instance_object->tiuserid = $userid; 00729 return $DB->insert_record('tag_instance', $tag_instance_object); 00730 } 00731 } 00732 00739 function tag_autocomplete($text) { 00740 global $DB; 00741 return $DB->get_records_sql("SELECT tg.id, tg.name, tg.rawname 00742 FROM {tag} tg 00743 WHERE tg.name LIKE ?", array(moodle_strtolower($text)."%")); 00744 } 00745 00754 function tag_cleanup() { 00755 global $DB; 00756 00757 $instances = $DB->get_recordset('tag_instance'); 00758 00759 // cleanup tag instances 00760 foreach ($instances as $instance) { 00761 $delete = false; 00762 00763 if (!$DB->record_exists('tag', array('id'=>$instance->tagid))) { 00764 // if the tag has been removed, instance should be deleted. 00765 $delete = true; 00766 } else { 00767 switch ($instance->itemtype) { 00768 case 'user': // users are marked as deleted, but not actually deleted 00769 if ($DB->record_exists('user', array('id'=>$instance->itemid, 'deleted'=>1))) { 00770 $delete = true; 00771 } 00772 break; 00773 default: // anything else, if the instance is not there, delete. 00774 if (!$DB->record_exists($instance->itemtype, array('id'=>$instance->itemid))) { 00775 $delete = true; 00776 } 00777 break; 00778 } 00779 } 00780 if ($delete) { 00781 tag_delete_instance($instance->itemtype, $instance->itemid, $instance->tagid); 00782 //debugging('deleting tag_instance #'. $instance->id .', linked to tag id #'. $instance->tagid, DEBUG_DEVELOPER); 00783 } 00784 } 00785 $instances->close(); 00786 00787 // TODO: this will only clean tags of type 'default'. This is good as 00788 // it won't delete 'official' tags, but the day we get more than two 00789 // types, we need to fix this. 00790 $unused_tags = $DB->get_recordset_sql("SELECT tg.id 00791 FROM {tag} tg 00792 WHERE tg.tagtype = 'default' 00793 AND NOT EXISTS ( 00794 SELECT 'x' 00795 FROM {tag_instance} ti 00796 WHERE ti.tagid = tg.id 00797 )"); 00798 00799 // cleanup tags 00800 foreach ($unused_tags as $unused_tag) { 00801 tag_delete($unused_tag->id); 00802 //debugging('deleting unused tag #'. $unused_tag->id, DEBUG_DEVELOPER); 00803 } 00804 $unused_tags->close(); 00805 } 00806 00823 function tag_compute_correlations($mincorrelation = 2) { 00824 global $DB; 00825 00826 // This mighty one line query fetches a row from the database for every 00827 // individual tag correlation. We then need to process the rows collecting 00828 // the correlations for each tag id. 00829 // The fields used by this query are as follows: 00830 // tagid : This is the tag id, there should be at least $mincorrelation 00831 // rows for each tag id. 00832 // correlation : This is the tag id that correlates to the above tagid field. 00833 // correlationid : This is the id of the row in the tag_correlation table that 00834 // relates to the tagid field and will be NULL if there are no 00835 // existing correlations 00836 $sql = 'SELECT pairs.tagid, pairs.correlation, pairs.ocurrences, co.id AS correlationid 00837 FROM ( 00838 SELECT ta.tagid, tb.tagid AS correlation, COUNT(*) AS ocurrences 00839 FROM {tag_instance} ta 00840 JOIN {tag_instance} tb ON (ta.itemtype = tb.itemtype AND ta.itemid = tb.itemid AND ta.tagid <> tb.tagid) 00841 GROUP BY ta.tagid, tb.tagid 00842 HAVING COUNT(*) > :mincorrelation 00843 ) pairs 00844 LEFT JOIN {tag_correlation} co ON co.tagid = pairs.tagid 00845 ORDER BY pairs.tagid ASC, pairs.ocurrences DESC, pairs.correlation ASC'; 00846 $rs = $DB->get_recordset_sql($sql, array('mincorrelation' => $mincorrelation)); 00847 00848 // Set up an empty tag correlation object 00849 $tagcorrelation = new stdClass; 00850 $tagcorrelation->id = null; 00851 $tagcorrelation->tagid = null; 00852 $tagcorrelation->correlatedtags = array(); 00853 00854 // We store each correlation id in this array so we can remove any correlations 00855 // that no longer exist. 00856 $correlations = array(); 00857 00858 // Iterate each row of the result set and build them into tag correlations. 00859 // We add all of a tag's correlations to $tagcorrelation->correlatedtags[] 00860 // then save the $tagcorrelation object 00861 foreach ($rs as $row) { 00862 if ($row->tagid != $tagcorrelation->tagid) { 00863 // The tag id has changed so we have all of the correlations for this tag 00864 $tagcorrelationid = tag_process_computed_correlation($tagcorrelation); 00865 if ($tagcorrelationid) { 00866 $correlations[] = $tagcorrelationid; 00867 } 00868 // Now we reset the tag correlation object so we can reuse it and set it 00869 // up for the current record. 00870 $tagcorrelation = new stdClass; 00871 $tagcorrelation->id = $row->correlationid; 00872 $tagcorrelation->tagid = $row->tagid; 00873 $tagcorrelation->correlatedtags = array(); 00874 } 00875 //Save the correlation on the tag correlation object 00876 $tagcorrelation->correlatedtags[] = $row->correlation; 00877 } 00878 // Update the current correlation after the last record. 00879 $tagcorrelationid = tag_process_computed_correlation($tagcorrelation); 00880 if ($tagcorrelationid) { 00881 $correlations[] = $tagcorrelationid; 00882 } 00883 00884 00885 // Close the recordset 00886 $rs->close(); 00887 00888 // Remove any correlations that weren't just identified 00889 if (empty($correlations)) { 00890 //there are no tag correlations 00891 $DB->delete_records('tag_correlation'); 00892 } else { 00893 list($sql, $params) = $DB->get_in_or_equal($correlations, SQL_PARAMS_NAMED, 'param0000', false); 00894 $DB->delete_records_select('tag_correlation', 'id '.$sql, $params); 00895 } 00896 } 00897 00908 function tag_process_computed_correlation(stdClass $tagcorrelation) { 00909 global $DB; 00910 00911 // You must provide a tagid and correlatedtags must be set and be an array 00912 if (empty($tagcorrelation->tagid) || !isset($tagcorrelation->correlatedtags) || !is_array($tagcorrelation->correlatedtags)) { 00913 return false; 00914 } 00915 00916 $tagcorrelation->correlatedtags = join(',', $tagcorrelation->correlatedtags); 00917 if (!empty($tagcorrelation->id)) { 00918 // The tag correlation already exists so update it 00919 $DB->update_record('tag_correlation', $tagcorrelation); 00920 } else { 00921 // This is a new correlation to insert 00922 $tagcorrelation->id = $DB->insert_record('tag_correlation', $tagcorrelation); 00923 } 00924 return $tagcorrelation->id; 00925 } 00926 00930 function tag_cron() { 00931 tag_compute_correlations(); 00932 tag_cleanup(); 00933 } 00934 00944 function tag_find_tags($text, $ordered=true, $limitfrom='', $limitnum='') { 00945 global $DB; 00946 00947 $text = array_shift(tag_normalize($text, TAG_CASE_LOWER)); 00948 00949 if ($ordered) { 00950 $query = "SELECT tg.id, tg.name, tg.rawname, COUNT(ti.id) AS count 00951 FROM {tag} tg LEFT JOIN {tag_instance} ti ON tg.id = ti.tagid 00952 WHERE tg.name LIKE ? 00953 GROUP BY tg.id, tg.name, tg.rawname 00954 ORDER BY count DESC"; 00955 } else { 00956 $query = "SELECT tg.id, tg.name, tg.rawname 00957 FROM {tag} tg 00958 WHERE tg.name LIKE ?"; 00959 } 00960 $params = array("%{$text}%"); 00961 return $DB->get_records_sql($query, $params, $limitfrom , $limitnum); 00962 } 00963 00970 function tag_get_name($tagids) { 00971 global $DB; 00972 00973 if (!is_array($tagids)) { 00974 if ($tag = $DB->get_record('tag', array('id'=>$tagids))) { 00975 return $tag->name; 00976 } 00977 return false; 00978 } 00979 00980 $tag_names = array(); 00981 foreach($DB->get_records_list('tag', 'id', $tagids) as $tag) { 00982 $tag_names[$tag->id] = $tag->name; 00983 } 00984 00985 return $tag_names; 00986 } 00987 00996 function tag_get_correlated($tag_id, $limitnum=null) { 00997 global $DB; 00998 00999 $tag_correlation = $DB->get_record('tag_correlation', array('tagid'=>$tag_id)); 01000 01001 if (!$tag_correlation || empty($tag_correlation->correlatedtags)) { 01002 return array(); 01003 } 01004 01005 // this is (and has to) return the same fields as the query in tag_get_tags 01006 $sql = "SELECT DISTINCT tg.id, tg.tagtype, tg.name, tg.rawname, tg.flag, ti.ordering 01007 FROM {tag} tg 01008 INNER JOIN {tag_instance} ti ON tg.id = ti.tagid 01009 WHERE tg.id IN ({$tag_correlation->correlatedtags})"; 01010 $result = $DB->get_records_sql($sql); 01011 if (!$result) { 01012 return array(); 01013 } 01014 01015 return $result; 01016 } 01017 01027 function tag_normalize($rawtags, $case = TAG_CASE_LOWER) { 01028 01029 // cache normalized tags, to prevent costly repeated calls to clean_param 01030 static $cleaned_tags_lc = array(); // lower case - use for comparison 01031 static $cleaned_tags_mc = array(); // mixed case - use for saving to database 01032 01033 if ( !is_array($rawtags) ) { 01034 $rawtags = array($rawtags); 01035 } 01036 01037 $result = array(); 01038 foreach($rawtags as $rawtag) { 01039 $rawtag = trim($rawtag); 01040 if (!$rawtag) { 01041 continue; 01042 } 01043 if ( !array_key_exists($rawtag, $cleaned_tags_lc) ) { 01044 $cleaned_tags_lc[$rawtag] = moodle_strtolower( clean_param($rawtag, PARAM_TAG) ); 01045 $cleaned_tags_mc[$rawtag] = clean_param($rawtag, PARAM_TAG); 01046 } 01047 if ( $case == TAG_CASE_LOWER ) { 01048 $result[$rawtag] = $cleaned_tags_lc[$rawtag]; 01049 } else { // TAG_CASE_ORIGINAL 01050 $result[$rawtag] = $cleaned_tags_mc[$rawtag]; 01051 } 01052 } 01053 01054 return $result; 01055 } 01056 01064 function tag_record_count($record_type, $tagid) { 01065 global $DB; 01066 return $DB->count_records('tag_instance', array('itemtype'=>$record_type, 'tagid'=>$tagid)); 01067 } 01068 01077 function tag_record_tagged_with($record_type, $record_id, $tag) { 01078 global $DB; 01079 if ($tagid = tag_get_id($tag)) { 01080 return $DB->count_records('tag_instance', array('itemtype'=>$record_type, 'itemid'=>$record_id, 'tagid'=>$tagid)); 01081 } else { 01082 return 0; // tag doesn't exist 01083 } 01084 } 01085 01092 function tag_set_flag($tagids) { 01093 global $DB; 01094 01095 $tagids = (array)$tagids; 01096 foreach ($tagids as $tagid) { 01097 $tag = $DB->get_record('tag', array('id'=>$tagid), 'id, flag'); 01098 $tag->flag++; 01099 $tag->timemodified = time(); 01100 $DB->update_record('tag', $tag); 01101 } 01102 } 01103 01110 function tag_unset_flag($tagids) { 01111 global $DB; 01112 01113 if ( is_array($tagids) ) { 01114 $tagids = implode(',', $tagids); 01115 } 01116 $timemodified = time(); 01117 return $DB->execute("UPDATE {tag} SET flag = 0, timemodified = ? WHERE id IN ($tagids)", array($timemodified)); 01118 } 01119 01120 01127 function tag_page_type_list($pagetype, $parentcontext, $currentcontext) { 01128 return array( 01129 'tag-*'=>get_string('page-tag-x', 'tag'), 01130 'tag-index'=>get_string('page-tag-index', 'tag'), 01131 'tag-search'=>get_string('page-tag-search', 'tag'), 01132 'tag-manage'=>get_string('page-tag-manage', 'tag') 01133 ); 01134 }