forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
coursetagslib.php
658 lines (568 loc) · 23.3 KB
/
coursetagslib.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
<?php
/**
* coursetagslib.php
* @author [email protected] July07
*/
require_once $CFG->dirroot.'/tag/lib.php';
/**
* Returns an ordered array of tags associated with visible courses
* (boosted replacement of get_all_tags() allowing association with user and tagtype).
*
* @uses $CFG
* @param int $courseid, a 0 will return all distinct tags for visible courses
* @param int $userid optional the user id, a default of 0 will return all users tags for the course
* @param string $tagtype optional 'official' or 'default', empty returns both tag types
* @param int $numtags optional number of tags to display, default of 80 is set in the block, 0 returns all
* @param string $sort optional selected sorting, default is alpha sort (name) also timemodified or popularity
* @return array
*/
function coursetag_get_tags($courseid, $userid=0, $tagtype='', $numtags=0, $sort='name') {
global $CFG, $DB;
// get visible course ids
$courselist = array();
if ($courseid === 0) {
if ($courses = $DB->get_records_select('course', 'visible=1 AND category>0', null, '', 'id')) {
foreach ($courses as $key => $value) {
$courselist[] = $key;
}
}
}
// get tags from the db ordered by highest count first
$params = array();
$sql = "SELECT id as tkey, name, id, tagtype, rawname, f.timemodified, flag, count
FROM {tag} t,
(SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count
FROM {tag_instance}
WHERE itemtype = 'course' ";
if ($courseid > 0) {
$sql .= " AND itemid = :courseid ";
$params['courseid'] = $courseid;
} else {
if (!empty($courselist)) {
list($usql, $uparams) = $DB->get_in_or_equal($courselist, SQL_PARAMS_NAMED);
$sql .= "AND itemid $usql ";
$params = $params + $uparams;
}
}
if ($userid > 0) {
$sql .= " AND tiuserid = :userid ";
$params['userid'] = $userid;
}
$sql .= " GROUP BY tagid) f
WHERE t.id = f.tagid ";
if ($tagtype != '') {
$sql .= "AND tagtype = :tagtype ";
$params['tagtype'] = $tagtype;
}
$sql .= "ORDER BY count DESC, name ASC";
// limit the number of tags for output
if ($numtags == 0) {
$tags = $DB->get_records_sql($sql, $params);
} else {
$tags = $DB->get_records_sql($sql, $params, 0, $numtags);
}
// prepare the return
$return = array();
if ($tags) {
// sort the tag display order
if ($sort != 'popularity') {
$CFG->tagsort = $sort;
usort($tags, "coursetag_sort");
}
// avoid print_tag_cloud()'s ksort upsetting ordering by setting the key here
foreach ($tags as $value) {
$return[] = $value;
}
}
return $return;
}
/**
* Returns an ordered array of tags
* (replaces popular_tags_count() allowing sorting).
*
* @uses $CFG
* @param string $sort optional selected sorting, default is alpha sort (name) also timemodified or popularity
* @param int $numtags optional number of tags to display, default of 20 is set in the block, 0 returns all
* @return array
*/
function coursetag_get_all_tags($sort='name', $numtags=0) {
global $CFG, $DB;
// note that this selects all tags except for courses that are not visible
$sql = "SELECT id, name, id, tagtype, rawname, f.timemodified, flag, count
FROM {tag} t,
(SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count
FROM {tag_instance} WHERE tagid NOT IN
(SELECT tagid FROM {tag_instance} ti, {course} c
WHERE c.visible = 0
AND ti.itemtype = 'course'
AND ti.itemid = c.id)
GROUP BY tagid) f
WHERE t.id = f.tagid
ORDER BY count DESC, name ASC";
if ($numtags == 0) {
$tags = $DB->get_records_sql($sql);
} else {
$tags = $DB->get_records_sql($sql, null, 0, $numtags);
}
$return = array();
if ($tags) {
if ($sort != 'popularity') {
$CFG->tagsort = $sort;
usort($tags, "coursetag_sort");
}
foreach ($tags as $value) {
$return[] = $value;
}
}
return $return;
}
/**
* Callback function for coursetag_get_tags() and coursetag_get_all_tags() only
* @uses $CFG
*/
function coursetag_sort($a, $b) {
// originally from block_blog_tags
global $CFG;
// set up the variable $tagsort as either 'name' or 'timemodified' only, 'popularity' does not need sorting
if (empty($CFG->tagsort)) {
$tagsort = 'name';
} else {
$tagsort = $CFG->tagsort;
}
if (is_numeric($a->$tagsort)) {
return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1;
} elseif (is_string($a->$tagsort)) {
return strcmp($a->$tagsort, $b->$tagsort);
} else {
return 0;
}
}
/**
* Prints a tag cloud
*
* @param array $tagcloud array of tag objects (fields: id, name, rawname, count and flag)
* @param int $max_size maximum text size, in percentage
* @param int $min_size minimum text size, in percentage
* @param $return if true return html string
*/
function coursetag_print_cloud($tagcloud, $return=false, $max_size=180, $min_size=80) {
global $CFG;
if (empty($tagcloud)) {
return;
}
ksort($tagcloud);
$count = array();
foreach ($tagcloud as $key => $value) {
if(!empty($value->count)) {
$count[$key] = log10($value->count);
} else {
$count[$key] = 0;
}
}
$max = max($count);
$min = min($count);
$spread = $max - $min;
if (0 == $spread) { // we don't want to divide by zero
$spread = 1;
}
$step = ($max_size - $min_size)/($spread);
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
$can_manage_tags = has_capability('moodle/tag:manage', $systemcontext);
//prints the tag cloud
$output = '<ul class="tag-cloud inline-list">';
foreach ($tagcloud as $key => $tag) {
$size = $min_size + ((log10($tag->count) - $min) * $step);
$size = ceil($size);
$style = 'style="font-size: '.$size.'%"';
if ($tag->count > 1) {
$title = 'title="'.s(get_string('thingstaggedwith','tag', $tag)).'"';
} else {
$title = 'title="'.s(get_string('thingtaggedwith','tag', $tag)).'"';
}
$href = 'href="'.$CFG->wwwroot.'/tag/index.php?id='.$tag->id.'"';
//highlight tags that have been flagged as inappropriate for those who can manage them
$tagname = tag_display_name($tag);
if ($tag->flag > 0 && $can_manage_tags) {
$tagname = '<span class="flagged-tag">' . tag_display_name($tag) . '</span>';
}
$tag_link = '<li><a '.$href.' '.$title.' '. $style .'>'.$tagname.'</a></li> ';
$output .= $tag_link;
}
$output .= '</ul>'."\n";
if ($return) {
return $output;
} else {
echo $output;
}
}
/**
* Returns javascript for use in tags block and supporting pages
* @param string $coursetagdivs comma separated divs ids
* @uses $CFG
*/
function coursetag_get_jscript($coursetagdivs = '') {
global $CFG, $DB, $PAGE;
$PAGE->requires->js('tag/tag.js');
$PAGE->requires->strings_for_js(array('jserror1', 'jserror2'), 'block_tags');
if ($coursetagdivs) {
$PAGE->requires->js_function_call('set_course_tag_divs', $coursetagdivs);
}
if ($coursetags = $DB->get_records('tag', null, 'name ASC', 'name, id')) {
foreach ($coursetags as $key => $value) {
$PAGE->requires->js_function_call('set_course_tag', array($key));
}
}
$PAGE->requires->js('blocks/tags/coursetags.js');
return '';
}
/**
* Returns javascript to create the links in the tag block footer.
*/
function coursetag_get_jscript_links($coursetagslinks) {
global $PAGE;
if (!empty($coursetagslinks)) {
foreach ($coursetagslinks as $a) {
$PAGE->requires->js_function_call('add_tag_footer_link', array('coursetagslinks', $a['title'], $a['onclick'], $a['text']))->on_dom_ready();
}
}
return '';
}
/**
* Returns all tags created by a user for a course
*
* @uses $CFG
* @param int $courseid
* @param int $userid
*/
function coursetag_get_records($courseid, $userid) {
global $CFG, $DB;
$sql = "SELECT t.id, name, rawname
FROM {tag} t, {tag_instance} ti
WHERE t.id = ti.tagid
AND ti.tiuserid = :userid
AND ti.itemid = :courseid
ORDER BY name ASC";
return $DB->get_records_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid));
}
/**
* Stores a tag for a course for a user
*
* @uses $CFG
* @param array $tags simple array of keywords to be stored
* @param integer $courseid
* @param integer $userid
* @param string $tagtype official or default only
* @param string $myurl optional for logging creation of course tags
*/
function coursetag_store_keywords($tags, $courseid, $userid=0, $tagtype='official', $myurl='') {
global $CFG;
if (is_array($tags) and !empty($tags)) {
foreach($tags as $tag) {
$tag = trim($tag);
if (strlen($tag) > 0) {
//tag_set_add('course', $courseid, $tag, $userid); //deletes official tags
//add tag if does not exist
if (!$tagid = tag_get_id($tag)) {
$tag_id_array = tag_add(array($tag), $tagtype);
$tagid = $tag_id_array[moodle_strtolower($tag)];
}
//ordering
$ordering = 0;
if ($current_ids = tag_get_tags_ids('course', $courseid)) {
end($current_ids);
$ordering = key($current_ids) + 1;
}
//set type
tag_type_set($tagid, $tagtype);
//tag_instance entry
tag_assign('course', $courseid, $tagid, $ordering, $userid);
//logging - note only for user added tags
if ($tagtype == 'default' and $myurl != '') {
$url = $myurl.'?query='.urlencode($tag);
add_to_log($courseid, 'coursetags', 'add', $url, 'Course tagged');
}
}
}
}
}
/**
* Deletes a personal tag for a user for a course.
*
* @uses $CFG
* @param int $tagid
* @param int $userid
* @param int $courseid
*/
function coursetag_delete_keyword($tagid, $userid, $courseid) {
global $CFG, $DB;
$sql = "SELECT COUNT(*)
FROM {tag_instance}
WHERE tagid = $tagid
AND tiuserid = $userid
AND itemtype = 'course'
AND itemid = $courseid";
if ($DB->count_records_sql($sql) == 1) {
$sql = "tagid = $tagid
AND tiuserid = $userid
AND itemtype = 'course'
AND itemid = $courseid";
$DB->delete_records_select('tag_instance', $sql);
// 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 do official tags
if ($DB->record_exists('tag', array('id' => $tagid, 'tagtype' => 'default'))) {
$DB->delete_records('tag', array('id' => $tagid, 'tagtype' => 'default'));
}
}
} else {
print_error("errordeleting", 'tag', '', $tagid);
}
}
/**
* Get courses tagged with a tag
*
* @param int $tagid
* @return array of course objects
*/
function coursetag_get_tagged_courses($tagid) {
global $DB;
$courses = array();
if ($crs = $DB->get_records_select('tag_instance', "tagid=:tagid AND itemtype='course'", array('tagid'=>$tagid))) {
foreach ($crs as $c) {
//this capability check was introduced to stop display of courses that a student could not
//view, but arguably it is best that when clicking on a tag, the tagged course summary should
//be seen and then if the student clicks on that they will be given the opportunity to join
//note courses not visible should not have their tagid sent to this function
//if (has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $c->itemid))) {
$course = $DB->get_record('course', array('id'=>$c->itemid));
$courses[$c->itemid] = $course;
//}
}
}
return $courses;
}
/**
* Course tagging function used only during the deletion of a
* course (called by lib/moodlelib.php) to clean up associated tags
*
* @param $courseid
* @param $showfeedback
*/
function coursetag_delete_course_tags($courseid, $showfeedback=false) {
global $DB, $OUTPUT;
if ($tags = $DB->get_records_select('tag_instance', "itemtype='course' AND itemid=:courseid", array('courseid'=>$courseid))) {
foreach ($tags as $tag) {
//delete the course tag instance record
$DB->delete_records('tag_instance', array('tagid'=>$tag->tagid, 'itemtype'=>'course', 'itemid'=> $courseid));
// delete tag if there are no other tag_instance entries now
if (!($DB->record_exists('tag_instance', array('tagid'=>$tag->tagid)))) {
$DB->delete_records('tag', array('id'=>$tag->tagid));
}
}
}
if ($showfeedback) {
echo $OUTPUT->notification(get_string('deletedcoursetags', 'tag'));
}
}
/**
* Function called by cron to create/update users rss feeds
*
* @uses $CFG
* @return true
*
* Function removed.
* rsslib.php needs updating to accept Dublin Core tags (dc/cc) input before this can work.
*/
/*
function coursetag_rss_feeds() {
global $CFG, $DB;
require_once($CFG->dirroot.'/lib/dmllib.php');
require_once($CFG->dirroot.'/lib/rsslib.php');
$status = true;
mtrace(' Preparing to update all user unit tags RSS feeds');
if (empty($CFG->enablerssfeeds)) {
mtrace(' RSS DISABLED (admin variables - enablerssfeeds)');
} else {
// Load all the categories for use later on
$categories = $DB->get_records('course_categories');
// get list of users who have tagged a unit
$sql = "
SELECT DISTINCT u.id as userid, u.username, u.firstname, u.lastname, u.email
FROM {user} u, {course} c, {tag_instance} cti, {tag} t
WHERE c.id = cti.itemid
AND u.id = cti.tiuserid
AND t.id = cti.tagid
AND t.tagtype = 'personal'
AND u.confirmed = 1
AND u.deleted = 0
ORDER BY userid";
if ($users = $DB->get_records_sql($sql)) {
$items = array(); //contains rss data items for each user
foreach ($users as $user) {
// loop through each user, getting the data (tags for courses)
$sql = "
SELECT cti.id, c.id as courseid, c.fullname, c.shortname, c.category, t.rawname, cti.timemodified
FROM {course} c, {tag_instance} cti, {tag} t
WHERE c.id = cti.itemid
AND cti.tiuserid = :userid{$user->userid}
AND cti.tagid = t.id
AND t.tagtype = 'personal'
ORDER BY courseid";
if ($usertags = $DB->get_records_sql($sql, array('userid' => $user->userid))) {
$latest_date = 0; //latest date any tag was created by a user
$c = 0; //course identifier
foreach ($usertags as $usertag) {
if ($usertag->courseid != $c) {
$c = $usertag->courseid;
$items[$c] = new stdClass();
$items[$c]->title = $usertag->fullname . '(' . $usertag->shortname . ')';
$items[$c]->link = $CFG->wwwroot . '/course/view.php?name=' . $usertag->shortname;
$items[$c]->description = ''; //needs to be blank
$items[$c]->category = $categories[$usertag->category]->name;
$items[$c]->subject[] = $usertag->rawname;
$items[$c]->pubdate = $usertag->timemodified;
$items[$c]->tag = true;
} else {
$items[$c]->subject[] .= $usertag->rawname;
}
// Check and set the latest modified date.
$latest_date = $usertag->timemodified > $latest_date ? $usertag->timemodified : $latest_date;
}
// Setup some vars for use while creating the file
$path = $CFG->dataroot.'/1/usertagsrss/'.$user->userid;
$file_name = 'user_unit_tags_rss.xml';
$title = get_string('rsstitle', 'tag', ucwords(strtolower($user->firstname.' '.$user->lastname)));
$desc = get_string('rssdesc', 'tag');
// check that the path exists
if (!file_exists($path)) {
mtrace(' Creating folder '.$path);
check_dir_exists($path, TRUE, TRUE);
}
// create or update the feed for the user
// this functionality can be copied into seperate lib as in next two lines
//require_once($CFG->dirroot.'/local/ocilib.php');
//oci_create_rss_feed( $path, $file_name, $latest_date, $items, $title, $desc, $dc=true, $cc=false);
// Set path to RSS file
$full_path = "$save_path/$file_name";
mtrace(" Preparing to update RSS feed for $file_name");
// First let's make sure there is work to do by checking the time the file was last modified,
// if a course was update after the file was mofified
if (file_exists($full_path)) {
if ($lastmodified = filemtime($full_path)) {
mtrace(" XML File $file_name Created on ".date( "D, j M Y G:i:s T", $lastmodified ));
mtrace(' Lastest course modification on '.date( "D, j M Y G:i:s T", $latest_date ));
if ($latest_date > $lastmodified) {
mtrace(" XML File $file_name needs updating");
$changes = true;
} else {
mtrace(" XML File $file_name doesn't need updating");
$changes = false;
}
}
} else {
mtrace(" XML File $file_name needs updating");
$changes = true;
}
if ($changes) {
// Now we know something has changed, write the new file
if (!empty($items)) {
// First set rss feeds common headers
$header = rss_standard_header(strip_tags(format_string($title,true)),
$CFG->wwwroot,
$desc,
true, true);
// Now all the rss items
if (!empty($header)) {
$articles = rss_add_items($items,$dc,$cc);
}
// Now all rss feeds common footers
if (!empty($header) && !empty($articles)) {
$footer = rss_standard_footer();
}
// Now, if everything is ok, concatenate it
if (!empty($header) && !empty($articles) && !empty($footer)) {
$result = $header.$articles.$footer;
} else {
$result = false;
}
} else {
$result = false;
}
// Save the XML contents to file
if (!empty($result)) {
$rss_file = fopen($full_path, "w");
if ($rss_file) {
$status = fwrite ($rss_file, $result);
fclose($rss_file);
} else {
$status = false;
}
}
// Output result
if (empty($result)) {
// There was nothing to put into the XML file. Delete it!
if( is_file($full_path) ) {
mtrace(" There were no items for XML File $file_name. Deleting XML File");
unlink($full_path);
mtrace(" $full_path -> (deleted)");
} else {
mtrace(" There were no items for the XML File $file_name and no file to delete. Ignore.");
}
} else {
if (!empty($status)) {
mtrace(" $full_path -> OK");
} else {
mtrace(" $full_path -> FAILED");
}
}
}
//end of oci_create_rss_feed()
}
}
}
}
return $status;
}
*/
/**
* Get official keywords for the <meta name="keywords"> in header.html
* use: echo '<meta name="keywords" content="'.coursetag_get_official_keywords($COURSE->id).'"/>';
* @uses $CFG
* @param int $courseid
* @return string
*
* Function removed but fully working
* This function is potentially useful to anyone wanting to improve search results for course pages.
* The idea is to add official tags (not personal tags to prevent their deletion) to all
* courses (facility not added yet) which will be automatically added to the page header to boost
* search engine specificity/ratings.
*/
/*
function coursetag_get_official_keywords($courseid, $asarray=false) {
global $CFG;
$returnstr = '';
$sql = "SELECT t.id, name, rawname
FROM {tag} t, {tag_instance} ti
WHERE ti.itemid = :courseid
AND ti.itemtype = 'course'
AND t.tagtype = 'official'
AND ti.tagid = t.id
ORDER BY name ASC";
if ($tags = $DB->get_records_sql($sql, array('courseid' => $courseid))) {
if ($asarray) {
return $tags;
}
foreach ($tags as $tag) {
if( empty($CFG->keeptagnamecase) ) {
$textlib = textlib_get_instance();
$name = $textlib->strtotitle($tag->name);
} else {
$name = $tag->rawname;
}
$returnstr .= $name.', ';
}
$returnstr = rtrim($returnstr, ', ');
}
return $returnstr;
}
*/