2 // This file is part of Moodle - http://moodle.org/
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.
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 * Comment is helper class to add/delete comments anywhere in moodle
21 * @copyright 2010 Dongsheng Cai <dongsheng@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') ||
die();
29 * there may be several comment box in one page
30 * so we need a client_id to recognize them
35 * commentarea is used to specify different
36 * parts shared the same itemid
41 * itemid is used to associate with commenting content
46 * this html snippet will be used as a template
47 * to build comment content
52 * The context id for comments
62 * The course id for comments
67 * course module object, only be used to help find pluginname automatically
68 * if pluginname is specified, it won't be used at all
73 * The component that this comment is for. It is STRONGLY recommended to set this.
78 * This is calculated by normalising the component
83 * This is calculated by normalising the component
88 * Whether the user has the required capabilities/permissions to view comments.
91 private $viewcap = false;
93 * Whether the user has the required capabilities/permissions to post comments.
96 private $postcap = false;
98 * to costomize link text
103 * If set to true then comment sections won't be able to be opened and closed
104 * instead they will always be visible.
107 protected $notoggle = false;
109 * If set to true comments are automatically loaded as soon as the page loads.
110 * Normally this happens when the user expands the comment section.
113 protected $autostart = false;
115 * If set to true the total count of comments is displayed when displaying comments.
118 protected $displaytotalcount = false;
120 * If set to true a cancel button will be shown on the form used to submit comments.
123 protected $displaycancel = false;
125 * The number of comments associated with this comments params
128 protected $totalcommentcount = null;
130 * By default a user must have the generic comment capabilities plus any capabilities the
131 * component being commented on requires.
132 * When set to true only the component capabilities are checked, the system capabilities are
134 * This can be toggled by the component defining a callback in its lib.php e.g.
135 * function forum_comment_allow_anonymous_access(comment $comment) {}
136 * Note: On the front page this defaults to true.
139 protected $ignoresystempermissions = false;
142 * static variable will be used by non-js comments UI
144 private static $nonjs = false;
145 private static $comment_itemid = null;
146 private static $comment_context = null;
147 private static $comment_area = null;
148 private static $comment_page = null;
149 private static $comment_component = null;
153 * Construct function of comment class, initialise
155 * @param stdClass $options
156 * @param object $options {
157 * context => context context to use for the comment [required]
158 * component => string which plugin will comment being added to [required]
159 * itemid => int the id of the associated item (forum post, glossary item etc) [required]
160 * area => string comment area
161 * cm => stdClass course module
162 * course => course course object
163 * client_id => string an unique id to identify comment area
164 * autostart => boolean automatically expend comments
165 * showcount => boolean display the number of comments
166 * displaycancel => boolean display cancel button
167 * notoggle => boolean don't show/hide button
168 * linktext => string title of show/hide button
171 public function __construct(stdClass
$options) {
172 $this->viewcap
= false;
173 $this->postcap
= false;
176 if (!empty($options->client_id
)) {
177 $this->cid
= $options->client_id
;
179 $this->cid
= uniqid();
183 if (!empty($options->context
)) {
184 $this->context
= $options->context
;
185 $this->contextid
= $this->context
->id
;
186 } else if(!empty($options->contextid
)) {
187 $this->contextid
= $options->contextid
;
188 $this->context
= get_context_instance_by_id($this->contextid
);
190 print_error('invalidcontext');
193 if (!empty($options->component
)) {
194 // set and validate component
195 $this->set_component($options->component
);
197 // component cannot be empty
198 throw new comment_exception('invalidcomponent');
202 // course will be used to generate user profile link
203 if (!empty($options->course
)) {
204 $this->courseid
= $options->course
->id
;
205 } else if (!empty($options->courseid
)) {
206 $this->courseid
= $options->courseid
;
208 $this->courseid
= SITEID
;
211 // setup coursemodule
212 if (!empty($options->cm
)) {
213 $this->cm
= $options->cm
;
219 if (!empty($options->area
)) {
220 $this->commentarea
= $options->area
;
224 if (!empty($options->itemid
)) {
225 $this->itemid
= $options->itemid
;
230 // setup customized linktext
231 if (!empty($options->linktext
)) {
232 $this->linktext
= $options->linktext
;
234 $this->linktext
= get_string('comments');
237 // setup options for callback functions
238 $this->comment_param
= new stdClass();
239 $this->comment_param
->context
= $this->context
;
240 $this->comment_param
->courseid
= $this->courseid
;
241 $this->comment_param
->cm
= $this->cm
;
242 $this->comment_param
->commentarea
= $this->commentarea
;
243 $this->comment_param
->itemid
= $this->itemid
;
245 $this->allowanonymousaccess
= false;
246 // By default everyone can view comments on the front page
247 if ($this->context
->contextlevel
== CONTEXT_COURSE
&& $this->context
->instanceid
== SITEID
) {
248 $this->allowanonymousaccess
= true;
249 } else if ($this->context
->contextlevel
== CONTEXT_MODULE
&& $this->courseid
== SITEID
) {
250 $this->allowanonymousaccess
= true;
252 if (!empty($this->plugintype
) && !empty($this->pluginname
)) {
253 // Plugins can override this if they wish.
254 $this->allowanonymousaccess
= plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'allow_anonymous_access', array($this), $this->allowanonymousaccess
);
258 if (!empty($options->notoggle
)) {
259 $this->set_notoggle($options->notoggle
);
263 if (!empty($options->autostart
)) {
264 $this->set_autostart($options->autostart
);
267 // setup displaycancel
268 if (!empty($options->displaycancel
)) {
269 $this->set_displaycancel($options->displaycancel
);
272 // setup displaytotalcount
273 if (!empty($options->showcount
)) {
274 $this->set_displaytotalcount($options->showcount
);
277 // setting post and view permissions
278 $this->check_permissions();
281 $this->template
= html_writer
::tag('div', '___picture___', array('class' => 'comment-userpicture'));
282 $this->template
.= html_writer
::start_tag('div', array('class' => 'comment-content'));
283 $this->template
.= '___name___ - ';
284 $this->template
.= html_writer
::tag('span', '___time___');
285 $this->template
.= html_writer
::tag('div', '___content___');
286 $this->template
.= html_writer
::end_tag('div'); // .comment-content
287 if (!empty($this->plugintype
)) {
288 $this->template
= plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'template', array($this->comment_param
), $this->template
);
295 * Receive nonjs comment parameters
297 * @param moodle_page $page The page object to initialise comments within
298 * If not provided the global $PAGE is used
300 public static function init(moodle_page
$page = null) {
306 // setup variables for non-js interface
307 self
::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHANUM
);
308 self
::$comment_itemid = optional_param('comment_itemid', '', PARAM_INT
);
309 self
::$comment_context = optional_param('comment_context', '', PARAM_INT
);
310 self
::$comment_page = optional_param('comment_page', '', PARAM_INT
);
311 self
::$comment_area = optional_param('comment_area', '', PARAM_ALPHAEXT
);
313 $page->requires
->string_for_js('addcomment', 'moodle');
314 $page->requires
->string_for_js('deletecomment', 'moodle');
315 $page->requires
->string_for_js('comments', 'moodle');
316 $page->requires
->string_for_js('commentsrequirelogin', 'moodle');
320 * Sets the component.
322 * This method shouldn't be public, changing the component once it has been set potentially
323 * invalidates permission checks.
324 * A coding_error is now thrown if code attempts to change the component.
326 * @param string $component
329 public function set_component($component) {
330 if (!empty($this->component
) && $this->component
!== $component) {
331 throw new coding_exception('You cannot change the component of a comment once it has been set');
333 $this->component
= $component;
334 list($this->plugintype
, $this->pluginname
) = normalize_component($component);
338 * Determines if the user can view the comment.
342 public function set_view_permission($value) {
343 $this->viewcap
= (bool)$value;
347 * Determines if the user can post a comment
351 public function set_post_permission($value) {
352 $this->postcap
= (bool)$value;
356 * check posting comments permission
357 * It will check based on user roles and ask modules
358 * If you need to check permission by modules, a
359 * function named $pluginname_check_comment_post must be implemented
361 private function check_permissions() {
362 $this->postcap
= has_capability('moodle/comment:post', $this->context
);
363 $this->viewcap
= has_capability('moodle/comment:view', $this->context
);
364 if (!empty($this->plugintype
)) {
365 $permissions = plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'permissions', array($this->comment_param
), array('post'=>false, 'view'=>false));
366 if ($this->allowanonymousaccess
) {
367 $this->postcap
= $permissions['post'];
368 $this->viewcap
= $permissions['view'];
370 $this->postcap
= $this->postcap
&& $permissions['post'];
371 $this->viewcap
= $this->viewcap
&& $permissions['view'];
377 * Gets a link for this page that will work with JS disabled.
379 * @global moodle_page $PAGE
380 * @param moodle_page $page
383 public function get_nojslink(moodle_page
$page = null) {
384 if ($page === null) {
389 $link = new moodle_url($page->url
, array(
390 'nonjscomment' => true,
391 'comment_itemid' => $this->itemid
,
392 'comment_context' => $this->context
->id
,
393 'comment_area' => $this->commentarea
,
395 $link->remove_params(array('comment_page'));
400 * Sets the value of the notoggle option.
402 * If set to true then the user will not be able to expand and collase
403 * the comment section.
405 * @param bool $newvalue
407 public function set_notoggle($newvalue = true) {
408 $this->notoggle
= (bool)$newvalue;
412 * Sets the value of the autostart option.
414 * If set to true then the comments will be loaded during page load.
415 * Normally this happens only once the user expands the comment section.
417 * @param bool $newvalue
419 public function set_autostart($newvalue = true) {
420 $this->autostart
= (bool)$newvalue;
424 * Sets the displaycancel option
426 * If set to true then a cancel button will be shown when using the form
429 * @param bool $newvalue
431 public function set_displaycancel($newvalue = true) {
432 $this->displaycancel
= (bool)$newvalue;
436 * Sets the displaytotalcount option
438 * If set to true then the total number of comments will be displayed
439 * when printing comments.
441 * @param bool $newvalue
443 public function set_displaytotalcount($newvalue = true) {
444 $this->displaytotalcount
= (bool)$newvalue;
448 * Initialises the JavaScript that enchances the comment API.
450 * @param moodle_page $page The moodle page object that the JavaScript should be
453 public function initialise_javascript(moodle_page
$page) {
455 $options = new stdClass
;
456 $options->client_id
= $this->cid
;
457 $options->commentarea
= $this->commentarea
;
458 $options->itemid
= $this->itemid
;
460 $options->courseid
= $this->courseid
;
461 $options->contextid
= $this->contextid
;
462 $options->component
= $this->component
;
463 $options->notoggle
= $this->notoggle
;
464 $options->autostart
= $this->autostart
;
466 $page->requires
->js_init_call('M.core_comment.init', array($options), true);
472 * Prepare comment code in html
473 * @param boolean $return
476 public function output($return = true) {
477 global $PAGE, $OUTPUT;
478 static $template_printed;
480 $this->initialise_javascript($PAGE);
482 if (!empty(self
::$nonjs)) {
483 // return non js comments interface
484 return $this->print_comments(self
::$comment_page, $return, true);
489 // print html template
490 // Javascript will use the template to render new comments
491 if (empty($template_printed) && $this->can_view()) {
492 $html .= html_writer
::tag('div', $this->template
, array('style' => 'display:none', 'id' => 'cmt-tmpl'));
493 $template_printed = true;
496 if ($this->can_view()) {
497 // print commenting icon and tooltip
498 $html .= html_writer
::start_tag('div', array('class' => 'mdl-left'));
499 $html .= html_writer
::link($this->get_nojslink($PAGE), get_string('showcommentsnonjs'), array('class' => 'showcommentsnonjs'));
501 if (!$this->notoggle
) {
502 // If toggling is enabled (notoggle=false) then print the controls to toggle
503 // comments open and closed
505 if ($this->displaytotalcount
) {
506 $countstring = '('.$this->count().')';
508 $html .= html_writer
::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid
, 'href' => '#'));
509 $html .= html_writer
::empty_tag('img', array('id' => 'comment-img-'.$this->cid
, 'src' => $OUTPUT->pix_url('t/collapsed'), 'alt' => $this->linktext
, 'title' => $this->linktext
));
510 $html .= html_writer
::tag('span', $this->linktext
.' '.$countstring, array('id' => 'comment-link-text-'.$this->cid
));
511 $html .= html_writer
::end_tag('a');
514 $html .= html_writer
::start_tag('div', array('id' => 'comment-ctrl-'.$this->cid
, 'class' => 'comment-ctrl'));
516 if ($this->autostart
) {
517 // If autostart has been enabled print the comments list immediatly
518 $html .= html_writer
::start_tag('ul', array('id' => 'comment-list-'.$this->cid
, 'class' => 'comment-list comments-loaded'));
519 $html .= html_writer
::tag('li', '', array('class' => 'first'));
520 $html .= $this->print_comments(0, true, false);
521 $html .= html_writer
::end_tag('ul'); // .comment-list
522 $html .= $this->get_pagination(0);
524 $html .= html_writer
::start_tag('ul', array('id' => 'comment-list-'.$this->cid
, 'class' => 'comment-list'));
525 $html .= html_writer
::tag('li', '', array('class' => 'first'));
526 $html .= html_writer
::end_tag('ul'); // .comment-list
527 $html .= html_writer
::tag('div', '', array('id' => 'comment-pagination-'.$this->cid
, 'class' => 'comment-pagination'));
530 if ($this->can_post()) {
531 // print posting textarea
532 $html .= html_writer
::start_tag('div', array('class' => 'comment-area'));
533 $html .= html_writer
::start_tag('div', array('class' => 'db'));
534 $html .= html_writer
::tag('textarea', '', array('name' => 'content', 'rows' => 2, 'cols' => 20, 'id' => 'dlg-content-'.$this->cid
));
535 $html .= html_writer
::end_tag('div'); // .db
537 $html .= html_writer
::start_tag('div', array('class' => 'fd', 'id' => 'comment-action-'.$this->cid
));
538 $html .= html_writer
::link('#', get_string('savecomment'), array('id' => 'comment-action-post-'.$this->cid
));
540 if ($this->displaycancel
) {
541 $html .= html_writer
::tag('span', ' | ');
542 $html .= html_writer
::link('#', get_string('cancel'), array('id' => 'comment-action-cancel-'.$this->cid
));
545 $html .= html_writer
::end_tag('div'); // .fd
546 $html .= html_writer
::end_tag('div'); // .comment-area
547 $html .= html_writer
::tag('div', '', array('class' => 'clearer'));
550 $html .= html_writer
::end_tag('div'); // .comment-ctrl
551 $html .= html_writer
::end_tag('div'); // .mdl-left
564 * Return matched comments
569 public function get_comments($page = '') {
570 global $DB, $CFG, $USER, $OUTPUT;
571 if (!$this->can_view()) {
574 if (!is_numeric($page)) {
578 $perpage = (!empty($CFG->commentsperpage
))?
$CFG->commentsperpage
:15;
579 $start = $page * $perpage;
580 $ufields = user_picture
::fields('u');
581 $sql = "SELECT $ufields, c.id AS cid, c.content AS ccontent, c.format AS cformat, c.timecreated AS ctimecreated
583 JOIN {user} u ON u.id = c.userid
584 WHERE c.contextid = :contextid AND c.commentarea = :commentarea AND c.itemid = :itemid
585 ORDER BY c.timecreated DESC";
586 $params['contextid'] = $this->contextid
;
587 $params['commentarea'] = $this->commentarea
;
588 $params['itemid'] = $this->itemid
;
591 $formatoptions = array('overflowdiv' => true);
592 $rs = $DB->get_recordset_sql($sql, $params, $start, $perpage);
593 foreach ($rs as $u) {
596 $c->content
= $u->ccontent
;
597 $c->format
= $u->cformat
;
598 $c->timecreated
= $u->ctimecreated
;
599 $url = new moodle_url('/user/view.php', array('id'=>$u->id
, 'course'=>$this->courseid
));
600 $c->profileurl
= $url->out();
601 $c->fullname
= fullname($u);
602 $c->time
= userdate($c->timecreated
, get_string('strftimerecent', 'langconfig'));
603 $c->content
= format_text($c->content
, $c->format
, $formatoptions);
604 $c->avatar
= $OUTPUT->user_picture($u, array('size'=>18));
606 $candelete = $this->can_delete($c->id
);
607 if (($USER->id
== $u->id
) ||
!empty($candelete)) {
614 if (!empty($this->plugintype
)) {
615 // moodle module will filter comments
616 $comments = plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'display', array($comments, $this->comment_param
), $comments);
623 * Returns the number of comments associated with the details of this object
625 * @global moodle_database $DB
628 public function count() {
630 if ($this->totalcommentcount
=== null) {
631 $this->totalcommentcount
= $DB->count_records('comments', array('itemid' => $this->itemid
, 'commentarea' => $this->commentarea
, 'contextid' => $this->context
->id
));
633 return $this->totalcommentcount
;
637 * Returns HTML to display a pagination bar
639 * @global stdClass $CFG
640 * @global core_renderer $OUTPUT
644 public function get_pagination($page = 0) {
645 global $CFG, $OUTPUT;
646 $count = $this->count();
647 $perpage = (!empty($CFG->commentsperpage
))?
$CFG->commentsperpage
:15;
648 $pages = (int)ceil($count/$perpage);
649 if ($pages == 1 ||
$pages == 0) {
650 return html_writer
::tag('div', '', array('id' => 'comment-pagination-'.$this->cid
, 'class' => 'comment-pagination'));
652 if (!empty(self
::$nonjs)) {
653 // used in non-js interface
654 return $OUTPUT->paging_bar($count, $page, $perpage, $this->get_nojslink(), 'comment_page');
656 // return ajax paging bar
658 $str .= '<div class="comment-paging" id="comment-pagination-'.$this->cid
.'">';
659 for ($p=0; $p<$pages; $p++
) {
665 $str .= '<a href="#" class="'.$class.'" id="comment-page-'.$this->cid
.'-'.$p.'">'.($p+
1).'</a> ';
675 * @global moodle_database $DB
676 * @param string $content
679 public function add($content, $format = FORMAT_MOODLE
) {
680 global $CFG, $DB, $USER, $OUTPUT;
681 if (!$this->can_post()) {
682 throw new comment_exception('nopermissiontocomment');
685 $newcmt = new stdClass
;
686 $newcmt->contextid
= $this->contextid
;
687 $newcmt->commentarea
= $this->commentarea
;
688 $newcmt->itemid
= $this->itemid
;
689 $newcmt->content
= $content;
690 $newcmt->format
= $format;
691 $newcmt->userid
= $USER->id
;
692 $newcmt->timecreated
= $now;
694 // This callback allow module to modify the content of comment, such as filter or replacement
695 plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'add', array(&$newcmt, $this->comment_param
));
697 $cmt_id = $DB->insert_record('comments', $newcmt);
698 if (!empty($cmt_id)) {
699 $newcmt->id
= $cmt_id;
700 $newcmt->time
= userdate($now, get_string('strftimerecent', 'langconfig'));
701 $newcmt->fullname
= fullname($USER);
702 $url = new moodle_url('/user/view.php', array('id' => $USER->id
, 'course' => $this->courseid
));
703 $newcmt->profileurl
= $url->out();
704 $newcmt->content
= format_text($newcmt->content
, $format, array('overflowdiv'=>true));
705 $newcmt->avatar
= $OUTPUT->user_picture($USER, array('size'=>16));
708 throw new comment_exception('dbupdatefailed');
713 * delete by context, commentarea and itemid
714 * @param stdClass|array $param {
715 * contextid => int the context in which the comments exist [required]
716 * commentarea => string the comment area [optional]
717 * itemid => int comment itemid [optional]
721 public function delete_comments($param) {
723 $param = (array)$param;
724 if (empty($param['contextid'])) {
727 $DB->delete_records('comments', $param);
732 * Delete page_comments in whole course, used by course reset
734 * @param stdClass $context course context
736 public function reset_course_page_comments($context) {
739 $contexts[] = $context->id
;
740 $children = get_child_contexts($context);
741 foreach ($children as $c) {
742 $contexts[] = $c->id
;
744 list($ids, $params) = $DB->get_in_or_equal($contexts);
745 $DB->delete_records_select('comments', "commentarea='page_comments' AND contextid $ids", $params);
751 * @param int $commentid
754 public function delete($commentid) {
756 $candelete = has_capability('moodle/comment:delete', $this->context
);
757 if (!$comment = $DB->get_record('comments', array('id'=>$commentid))) {
758 throw new comment_exception('dbupdatefailed');
760 if (!($USER->id
== $comment->userid ||
!empty($candelete))) {
761 throw new comment_exception('nopermissiontocomment');
763 $DB->delete_records('comments', array('id'=>$commentid));
771 * @param boolean $return return comments list string or print it out
772 * @param boolean $nonjs print nonjs comments list or not?
775 public function print_comments($page = 0, $return = true, $nonjs = true) {
776 global $DB, $CFG, $PAGE;
778 if (!$this->can_view()) {
783 if (!(self
::$comment_itemid == $this->itemid
&&
784 self
::$comment_context == $this->context
->id
&&
785 self
::$comment_area == $this->commentarea
)) {
788 $comments = $this->get_comments($page);
792 $html .= html_writer
::tag('h3', get_string('comments'));
793 $html .= html_writer
::start_tag('ul', array('id' => 'comment-list-'.$this->cid
, 'class' => 'comment-list'));
795 // Reverse the comments array to display them in the correct direction
796 foreach (array_reverse($comments) as $cmt) {
797 $html .= html_writer
::tag('li', $this->print_comment($cmt, $nonjs), array('id' => 'comment-'.$cmt->id
.'-'.$this->cid
));
800 $html .= html_writer
::end_tag('ul');
801 $html .= $this->get_pagination($page);
803 if ($nonjs && $this->can_post()) {
804 // Form to add comments
805 $html .= html_writer
::start_tag('form', array('method' => 'post', 'action' => new moodle_url('/comment/comment_post.php')));
806 // Comment parameters
807 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'contextid', 'value' => $this->contextid
));
808 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'add'));
809 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'area', 'value' => $this->commentarea
));
810 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'component', 'value' => $this->component
));
811 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'itemid', 'value' => $this->itemid
));
812 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'courseid', 'value' => $this->courseid
));
813 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
814 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'returnurl', 'value' => $PAGE->url
));
815 // Textarea for the actual comment
816 $html .= html_writer
::tag('textarea', '', array('name' => 'content', 'rows' => 2));
817 // Submit button to add the comment
818 $html .= html_writer
::empty_tag('input', array('type' => 'submit', 'value' => get_string('submit')));
819 $html .= html_writer
::end_tag('form');
829 * Returns an array containing comments in HTML format.
831 * @global core_renderer $OUTPUT
832 * @param stdClass $cmt {
833 * id => int comment id
834 * content => string comment content
835 * format => int comment text format
836 * timecreated => int comment's timecreated
837 * profileurl => string link to user profile
838 * fullname => comment author's full name
839 * avatar => string user's avatar
840 * delete => boolean does user have permission to delete comment?
845 public function print_comment($cmt, $nonjs = true) {
848 $replacements = array();
850 if (!empty($cmt->delete
) && empty($nonjs)) {
851 $deletelink = html_writer
::start_tag('div', array('class'=>'comment-delete'));
852 $deletelink .= html_writer
::start_tag('a', array('href' => '#', 'id' => 'comment-delete-'.$this->cid
.'-'.$cmt->id
));
853 $deletelink .= $OUTPUT->pix_icon('t/delete', get_string('delete'));
854 $deletelink .= html_writer
::end_tag('a');
855 $deletelink .= html_writer
::end_tag('div');
856 $cmt->content
= $deletelink . $cmt->content
;
858 $patterns[] = '___picture___';
859 $patterns[] = '___name___';
860 $patterns[] = '___content___';
861 $patterns[] = '___time___';
862 $replacements[] = $cmt->avatar
;
863 $replacements[] = html_writer
::link($cmt->profileurl
, $cmt->fullname
);
864 $replacements[] = $cmt->content
;
865 $replacements[] = userdate($cmt->timecreated
, get_string('strftimerecent', 'langconfig'));
867 // use html template to format a single comment.
868 return str_replace($patterns, $replacements, $this->template
);
872 * Revoke validate callbacks
874 * @param stdClass $params addtionall parameters need to add to callbacks
876 protected function validate($params=array()) {
877 foreach ($params as $key=>$value) {
878 $this->comment_param
->$key = $value;
880 $validation = plugin_callback($this->plugintype
, $this->pluginname
, 'comment', 'validate', array($this->comment_param
), false);
882 throw new comment_exception('invalidcommentparam');
887 * Returns true if the user is able to view comments
890 public function can_view() {
892 return !empty($this->viewcap
);
896 * Returns true if the user can add comments against this comment description
899 public function can_post() {
901 return isloggedin() && !empty($this->postcap
);
905 * Returns true if the user can delete this comment
906 * @param int $commentid
909 public function can_delete($commentid) {
910 $this->validate(array('commentid'=>$commentid));
911 return has_capability('moodle/comment:delete', $this->context
);
915 * Returns the component associated with the comment
918 public function get_compontent() {
919 return $this->component
;
923 * Returns the context associated with the comment
926 public function get_context() {
927 return $this->context
;
931 * Returns the course id associated with the comment
934 public function get_courseid() {
935 return $this->courseid
;
939 * Returns the course module associated with the comment
943 public function get_cm() {
948 * Returns the item id associated with the comment
952 public function get_itemid() {
953 return $this->itemid
;
957 * Returns the comment area associated with the commentarea
961 public function get_commentarea() {
962 return $this->commentarea
;
966 class comment_exception
extends moodle_exception
{