Merge branch 'MDL-41728-m24' of git://github.com/sammarshallou/moodle into MOODLE_24_...
[moodle.git] / tag / coursetagslib.php
blob97c27333e631d7198244636452470c5236f4b2d4
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * coursetagslib.php
21 * @package core_tag
22 * @copyright 2007 j.beedell@open.ac.uk
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 require_once $CFG->dirroot.'/tag/lib.php';
27 require_once $CFG->dirroot.'/tag/locallib.php';
29 /**
30 * Returns an ordered array of tags associated with visible courses
31 * (boosted replacement of get_all_tags() allowing association with user and tagtype).
33 * @package core_tag
34 * @category tag
35 * @param int $courseid A course id. Passing 0 will return all distinct tags for all visible courses
36 * @param int $userid (optional) the user id, a default of 0 will return all users tags for the course
37 * @param string $tagtype (optional) The type of tag, empty string returns all types. Currently (Moodle 2.2) there are two
38 * types of tags which are used within Moodle, they are 'official' and 'default'.
39 * @param int $numtags (optional) number of tags to display, default of 80 is set in the block, 0 returns all
40 * @param string $sort (optional) selected sorting, default is alpha sort (name) also timemodified or popularity
41 * @return array
43 function coursetag_get_tags($courseid, $userid=0, $tagtype='', $numtags=0, $sort='name') {
45 global $CFG, $DB;
47 // get visible course ids
48 $courselist = array();
49 if ($courseid === 0) {
50 if ($courses = $DB->get_records_select('course', 'visible=1 AND category>0', null, '', 'id')) {
51 foreach ($courses as $key => $value) {
52 $courselist[] = $key;
57 // get tags from the db ordered by highest count first
58 $params = array();
59 $sql = "SELECT id as tkey, name, id, tagtype, rawname, f.timemodified, flag, count
60 FROM {tag} t,
61 (SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count
62 FROM {tag_instance}
63 WHERE itemtype = 'course' ";
65 if ($courseid > 0) {
66 $sql .= " AND itemid = :courseid ";
67 $params['courseid'] = $courseid;
68 } else {
69 if (!empty($courselist)) {
70 list($usql, $uparams) = $DB->get_in_or_equal($courselist, SQL_PARAMS_NAMED);
71 $sql .= "AND itemid $usql ";
72 $params = $params + $uparams;
76 if ($userid > 0) {
77 $sql .= " AND tiuserid = :userid ";
78 $params['userid'] = $userid;
81 $sql .= " GROUP BY tagid) f
82 WHERE t.id = f.tagid ";
83 if ($tagtype != '') {
84 $sql .= "AND tagtype = :tagtype ";
85 $params['tagtype'] = $tagtype;
87 $sql .= "ORDER BY count DESC, name ASC";
89 // limit the number of tags for output
90 if ($numtags == 0) {
91 $tags = $DB->get_records_sql($sql, $params);
92 } else {
93 $tags = $DB->get_records_sql($sql, $params, 0, $numtags);
96 // prepare the return
97 $return = array();
98 if ($tags) {
99 // sort the tag display order
100 if ($sort != 'popularity') {
101 $CFG->tagsort = $sort;
102 usort($tags, "coursetag_sort");
104 // avoid print_tag_cloud()'s ksort upsetting ordering by setting the key here
105 foreach ($tags as $value) {
106 $return[] = $value;
110 return $return;
115 * Returns an ordered array of tags
116 * (replaces popular_tags_count() allowing sorting).
118 * @package core_tag
119 * @category tag
120 * @param string $sort (optional) selected sorting, default is alpha sort (name) also timemodified or popularity
121 * @param int $numtags (optional) number of tags to display, default of 20 is set in the block, 0 returns all
122 * @return array
124 function coursetag_get_all_tags($sort='name', $numtags=0) {
126 global $CFG, $DB;
128 // note that this selects all tags except for courses that are not visible
129 $sql = "SELECT id, name, tagtype, rawname, f.timemodified, flag, count
130 FROM {tag} t,
131 (SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count
132 FROM {tag_instance} WHERE tagid NOT IN
133 (SELECT tagid FROM {tag_instance} ti, {course} c
134 WHERE c.visible = 0
135 AND ti.itemtype = 'course'
136 AND ti.itemid = c.id)
137 GROUP BY tagid) f
138 WHERE t.id = f.tagid
139 ORDER BY count DESC, name ASC";
140 if ($numtags == 0) {
141 $tags = $DB->get_records_sql($sql);
142 } else {
143 $tags = $DB->get_records_sql($sql, null, 0, $numtags);
146 $return = array();
147 if ($tags) {
148 if ($sort != 'popularity') {
149 $CFG->tagsort = $sort;
150 usort($tags, "coursetag_sort");
152 foreach ($tags as $value) {
153 $return[] = $value;
157 return $return;
161 * Sorting callback function for coursetag_get_tags() and coursetag_get_all_tags() only
163 * This function does a comparision on a field withing two variables, $a and $b. The field used is specified by
164 * $CFG->tagsort or we just use the 'name' field if $CFG->tagsort is empty. The comparison works as follows:
165 * If $a->$tagsort is greater than $b->$tagsort, 1 is returned.
166 * If $a->$tagsort is equal to $b->$tagsort, 0 is returned.
167 * If $a->$tagsort is less than $b->$tagsort, -1 is returned.
169 * Also if $a->$tagsort is not numeric or a string, 0 is returned.
171 * @package core_tag
172 * @access private
173 * @param int|string|mixed $a Variable to compare against $b
174 * @param int|string|mixed $b Variable to compare against $a
175 * @return int The result of the comparison/validation 1, 0 or -1
177 function coursetag_sort($a, $b) {
178 // originally from block_blog_tags
179 global $CFG;
181 // set up the variable $tagsort as either 'name' or 'timemodified' only, 'popularity' does not need sorting
182 if (empty($CFG->tagsort)) {
183 $tagsort = 'name';
184 } else {
185 $tagsort = $CFG->tagsort;
188 if (is_numeric($a->$tagsort)) {
189 return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1;
190 } else if (is_string($a->$tagsort)) {
191 return strcmp($a->$tagsort, $b->$tagsort);
192 } else {
193 return 0;
198 * Returns javascript for use in tags block and supporting pages
200 * @package core_tag
201 * @category tag
202 * @return null
204 function coursetag_get_jscript() {
205 global $CFG, $DB, $PAGE;
207 $PAGE->requires->js('/tag/tag.js');
208 $PAGE->requires->strings_for_js(array('jserror1', 'jserror2'), 'block_tags');
210 if ($coursetags = $DB->get_records('tag', null, 'name ASC', 'name, id')) {
211 foreach ($coursetags as $key => $value) {
212 $PAGE->requires->js_function_call('set_course_tag', array($key));
216 $PAGE->requires->js('/blocks/tags/coursetags.js');
218 return '';
222 * Returns javascript to create the links in the tag block footer.
224 * @package core_tag
225 * @category tag
226 * @param string $elementid the element to attach the footer to
227 * @param array $coursetagslinks links arrays each consisting of 'title', 'onclick' and 'text' elements
228 * @return string always returns a blank string
230 function coursetag_get_jscript_links($elementid, $coursetagslinks) {
231 global $PAGE;
233 if (!empty($coursetagslinks)) {
234 foreach ($coursetagslinks as $a) {
235 $PAGE->requires->js_function_call('add_tag_footer_link', array($elementid, $a['title'], $a['onclick'], $a['text']), true);
239 return '';
243 * Returns all tags created by a user for a course
245 * @package core_tag
246 * @category tag
247 * @param int $courseid tags are returned for the course that has this courseid
248 * @param int $userid return tags which were created by this user
250 function coursetag_get_records($courseid, $userid) {
251 global $CFG, $DB;
253 $sql = "SELECT t.id, name, rawname
254 FROM {tag} t, {tag_instance} ti
255 WHERE t.id = ti.tagid
256 AND ti.tiuserid = :userid
257 AND ti.itemid = :courseid
258 ORDER BY name ASC";
260 return $DB->get_records_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid));
264 * Stores a tag for a course for a user
266 * @package core_tag
267 * @category tag
268 * @param array $tags simple array of keywords to be stored
269 * @param int $courseid the id of the course we wish to store a tag for
270 * @param int $userid the id of the user we wish to store a tag for
271 * @param string $tagtype official or default only
272 * @param string $myurl (optional) for logging creation of course tags
274 function coursetag_store_keywords($tags, $courseid, $userid=0, $tagtype='official', $myurl='') {
276 global $CFG;
278 if (is_array($tags) and !empty($tags)) {
279 foreach ($tags as $tag) {
280 $tag = trim($tag);
281 if (strlen($tag) > 0) {
282 //tag_set_add('course', $courseid, $tag, $userid); //deletes official tags
284 //add tag if does not exist
285 if (!$tagid = tag_get_id($tag)) {
286 $tag_id_array = tag_add(array($tag), $tagtype);
287 $tagid = $tag_id_array[textlib::strtolower($tag)];
289 //ordering
290 $ordering = 0;
291 if ($current_ids = tag_get_tags_ids('course', $courseid)) {
292 end($current_ids);
293 $ordering = key($current_ids) + 1;
295 //set type
296 tag_type_set($tagid, $tagtype);
298 //tag_instance entry
299 tag_assign('course', $courseid, $tagid, $ordering, $userid);
301 //logging - note only for user added tags
302 if ($tagtype == 'default' and $myurl != '') {
303 $url = $myurl.'?query='.urlencode($tag);
304 add_to_log($courseid, 'coursetags', 'add', $url, 'Course tagged');
313 * Deletes a personal tag for a user for a course.
315 * @package core_tag
316 * @category tag
317 * @param int $tagid the tag we wish to delete
318 * @param int $userid the user that the tag is associated with
319 * @param int $courseid the course that the tag is associated with
321 function coursetag_delete_keyword($tagid, $userid, $courseid) {
323 global $CFG, $DB;
325 $sql = "SELECT COUNT(*)
326 FROM {tag_instance}
327 WHERE tagid = $tagid
328 AND tiuserid = $userid
329 AND itemtype = 'course'
330 AND itemid = $courseid";
331 if ($DB->count_records_sql($sql) == 1) {
332 $sql = "tagid = $tagid
333 AND tiuserid = $userid
334 AND itemtype = 'course'
335 AND itemid = $courseid";
336 $DB->delete_records_select('tag_instance', $sql);
337 // if there are no other instances of the tag then consider deleting the tag as well
338 if (!$DB->record_exists('tag_instance', array('tagid' => $tagid))) {
339 // if the tag is a personal tag then delete it - don't do official tags
340 if ($DB->record_exists('tag', array('id' => $tagid, 'tagtype' => 'default'))) {
341 $DB->delete_records('tag', array('id' => $tagid, 'tagtype' => 'default'));
344 } else {
345 print_error("errordeleting", 'tag', '', $tagid);
351 * Get courses tagged with a tag
353 * @global moodle_database $DB
354 * @package core_tag
355 * @category tag
356 * @param int $tagid
357 * @return array of course objects
359 function coursetag_get_tagged_courses($tagid) {
360 global $DB;
362 $courses = array();
364 $ctxselect = context_helper::get_preload_record_columns_sql('ctx');
366 $sql = "SELECT c.*, $ctxselect
367 FROM {course} c
368 JOIN {tag_instance} t ON t.itemid = c.id
369 JOIN {context} ctx ON ctx.instanceid = c.id
370 WHERE t.tagid = :tagid AND
371 t.itemtype = 'course' AND
372 ctx.contextlevel = :contextlevel
373 ORDER BY c.sortorder ASC";
374 $params = array('tagid' => $tagid, 'contextlevel' => CONTEXT_COURSE);
375 $rs = $DB->get_recordset_sql($sql, $params);
376 foreach ($rs as $course) {
377 context_helper::preload_from_record($course);
378 if ($course->visible == 1 || has_capability('moodle/course:viewhiddencourses', context_course::instance($course->id))) {
379 $courses[$course->id] = $course;
382 return $courses;
386 * Course tagging function used only during the deletion of a course (called by lib/moodlelib.php) to clean up associated tags
388 * @package core_tag
389 * @param int $courseid the course we wish to delete tag instances from
390 * @param bool $showfeedback if we should output a notification of the delete to the end user
392 function coursetag_delete_course_tags($courseid, $showfeedback=false) {
393 global $DB, $OUTPUT;
395 if ($tags = $DB->get_records_select('tag_instance', "itemtype='course' AND itemid=:courseid", array('courseid'=>$courseid))) {
396 foreach ($tags as $tag) {
397 //delete the course tag instance record
398 $DB->delete_records('tag_instance', array('tagid'=>$tag->tagid, 'itemtype'=>'course', 'itemid'=> $courseid));
399 // delete tag if there are no other tag_instance entries now
400 if (!($DB->record_exists('tag_instance', array('tagid'=>$tag->tagid)))) {
401 $DB->delete_records('tag', array('id'=>$tag->tagid));
402 // Delete files
403 $fs = get_file_storage();
404 $fs->delete_area_files(get_system_context()->id, 'tag', 'description', $tag->tagid);
409 if ($showfeedback) {
410 echo $OUTPUT->notification(get_string('deletedcoursetags', 'tag'), 'notifysuccess');