[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/comment/ -> lib.php (source)

   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.
  13  //
  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/>.
  16  
  17  /**
  18   * Functions and classes for commenting
  19   *
  20   * @package   core
  21   * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  defined('MOODLE_INTERNAL') || die();
  25  
  26  /**
  27   * Comment is helper class to add/delete comments anywhere in moodle
  28   *
  29   * @package   core
  30   * @category  comment
  31   * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
  32   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class comment {
  35      /** @var int there may be several comment box in one page so we need a client_id to recognize them */
  36      private $cid;
  37      /** @var string commentarea is used to specify different parts shared the same itemid */
  38      private $commentarea;
  39      /** @var int itemid is used to associate with commenting content */
  40      private $itemid;
  41      /** @var string this html snippet will be used as a template to build comment content */
  42      private $template;
  43      /** @var int The context id for comments */
  44      private $contextid;
  45      /** @var stdClass The context itself */
  46      private $context;
  47      /** @var int The course id for comments */
  48      private $courseid;
  49      /** @var stdClass course module object, only be used to help find pluginname automatically */
  50      private $cm;
  51      /** @var string The component that this comment is for. It is STRONGLY recommended to set this. */
  52      private $component;
  53      /** @var string This is calculated by normalising the component */
  54      private $pluginname;
  55      /** @var string This is calculated by normalising the component */
  56      private $plugintype;
  57      /** @var bool Whether the user has the required capabilities/permissions to view comments. */
  58      private $viewcap = false;
  59      /** @var bool Whether the user has the required capabilities/permissions to post comments. */
  60      private $postcap = false;
  61      /** @var string to customize link text */
  62      private $linktext;
  63      /** @var bool If set to true then comment sections won't be able to be opened and closed instead they will always be visible. */
  64      protected $notoggle = false;
  65      /** @var bool If set to true comments are automatically loaded as soon as the page loads. */
  66      protected $autostart = false;
  67      /** @var bool If set to true the total count of comments is displayed when displaying comments. */
  68      protected $displaytotalcount = false;
  69      /** @var bool If set to true a cancel button will be shown on the form used to submit comments. */
  70      protected $displaycancel = false;
  71      /** @var int The number of comments associated with this comments params */
  72      protected $totalcommentcount = null;
  73  
  74      /**
  75       * Set to true to remove the col attribute from the textarea making it full width.
  76       * @var bool
  77       */
  78      protected $fullwidth = false;
  79  
  80      /** @var bool Use non-javascript UI */
  81      private static $nonjs = false;
  82      /** @var int comment itemid used in non-javascript UI */
  83      private static $comment_itemid = null;
  84      /** @var int comment context used in non-javascript UI */
  85      private static $comment_context = null;
  86      /** @var string comment area used in non-javascript UI */
  87      private static $comment_area = null;
  88      /** @var string comment page used in non-javascript UI */
  89      private static $comment_page = null;
  90      /** @var string comment itemid component in non-javascript UI */
  91      private static $comment_component = null;
  92  
  93      /**
  94       * Construct function of comment class, initialise
  95       * class members
  96       *
  97       * @param stdClass $options {
  98       *            context => context context to use for the comment [required]
  99       *            component => string which plugin will comment being added to [required]
 100       *            itemid  => int the id of the associated item (forum post, glossary item etc) [required]
 101       *            area    => string comment area
 102       *            cm      => stdClass course module
 103       *            course  => course course object
 104       *            client_id => string an unique id to identify comment area
 105       *            autostart => boolean automatically expend comments
 106       *            showcount => boolean display the number of comments
 107       *            displaycancel => boolean display cancel button
 108       *            notoggle => boolean don't show/hide button
 109       *            linktext => string title of show/hide button
 110       * }
 111       */
 112      public function __construct(stdClass $options) {
 113          $this->viewcap = false;
 114          $this->postcap = false;
 115  
 116          // setup client_id
 117          if (!empty($options->client_id)) {
 118              $this->cid = $options->client_id;
 119          } else {
 120              $this->cid = uniqid();
 121          }
 122  
 123          // setup context
 124          if (!empty($options->context)) {
 125              $this->context = $options->context;
 126              $this->contextid = $this->context->id;
 127          } else if(!empty($options->contextid)) {
 128              $this->contextid = $options->contextid;
 129              $this->context = context::instance_by_id($this->contextid);
 130          } else {
 131              print_error('invalidcontext');
 132          }
 133  
 134          if (!empty($options->component)) {
 135              // set and validate component
 136              $this->set_component($options->component);
 137          } else {
 138              // component cannot be empty
 139              throw new comment_exception('invalidcomponent');
 140          }
 141  
 142          // setup course
 143          // course will be used to generate user profile link
 144          if (!empty($options->course)) {
 145              $this->courseid = $options->course->id;
 146          } else if (!empty($options->courseid)) {
 147              $this->courseid = $options->courseid;
 148          } else {
 149              $this->courseid = SITEID;
 150          }
 151  
 152          // setup coursemodule
 153          if (!empty($options->cm)) {
 154              $this->cm = $options->cm;
 155          } else {
 156              $this->cm = null;
 157          }
 158  
 159          // setup commentarea
 160          if (!empty($options->area)) {
 161              $this->commentarea = $options->area;
 162          }
 163  
 164          // setup itemid
 165          if (!empty($options->itemid)) {
 166              $this->itemid = $options->itemid;
 167          } else {
 168              $this->itemid = 0;
 169          }
 170  
 171          // setup customized linktext
 172          if (!empty($options->linktext)) {
 173              $this->linktext = $options->linktext;
 174          } else {
 175              $this->linktext = get_string('comments');
 176          }
 177  
 178          // setup options for callback functions
 179          $this->comment_param = new stdClass();
 180          $this->comment_param->context     = $this->context;
 181          $this->comment_param->courseid    = $this->courseid;
 182          $this->comment_param->cm          = $this->cm;
 183          $this->comment_param->commentarea = $this->commentarea;
 184          $this->comment_param->itemid      = $this->itemid;
 185  
 186          // setup notoggle
 187          if (!empty($options->notoggle)) {
 188              $this->set_notoggle($options->notoggle);
 189          }
 190  
 191          // setup notoggle
 192          if (!empty($options->autostart)) {
 193              $this->set_autostart($options->autostart);
 194          }
 195  
 196          // setup displaycancel
 197          if (!empty($options->displaycancel)) {
 198              $this->set_displaycancel($options->displaycancel);
 199          }
 200  
 201          // setup displaytotalcount
 202          if (!empty($options->showcount)) {
 203              $this->set_displaytotalcount($options->showcount);
 204          }
 205  
 206          // setting post and view permissions
 207          $this->check_permissions();
 208  
 209          // load template
 210          $this->template = html_writer::start_tag('div', array('class' => 'comment-message'));
 211  
 212          $this->template .= html_writer::start_tag('div', array('class' => 'comment-message-meta'));
 213  
 214          $this->template .= html_writer::tag('span', '___picture___', array('class' => 'picture'));
 215          $this->template .= html_writer::tag('span', '___name___', array('class' => 'user')) . ' - ';
 216          $this->template .= html_writer::tag('span', '___time___', array('class' => 'time'));
 217  
 218          $this->template .= html_writer::end_tag('div'); // .comment-message-meta
 219          $this->template .= html_writer::tag('div', '___content___', array('class' => 'text'));
 220  
 221          $this->template .= html_writer::end_tag('div'); // .comment-message
 222  
 223          if (!empty($this->plugintype)) {
 224              $this->template = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'template', array($this->comment_param), $this->template);
 225          }
 226  
 227          unset($options);
 228      }
 229  
 230      /**
 231       * Receive nonjs comment parameters
 232       *
 233       * @param moodle_page $page The page object to initialise comments within
 234       *                          If not provided the global $PAGE is used
 235       */
 236      public static function init(moodle_page $page = null) {
 237          global $PAGE;
 238  
 239          if (empty($page)) {
 240              $page = $PAGE;
 241          }
 242          // setup variables for non-js interface
 243          self::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHANUM);
 244          self::$comment_itemid  = optional_param('comment_itemid',  '', PARAM_INT);
 245          self::$comment_context = optional_param('comment_context', '', PARAM_INT);
 246          self::$comment_page    = optional_param('comment_page',    '', PARAM_INT);
 247          self::$comment_area    = optional_param('comment_area',    '', PARAM_AREA);
 248  
 249          $page->requires->string_for_js('addcomment', 'moodle');
 250          $page->requires->string_for_js('deletecomment', 'moodle');
 251          $page->requires->string_for_js('comments', 'moodle');
 252          $page->requires->string_for_js('commentsrequirelogin', 'moodle');
 253      }
 254  
 255      /**
 256       * Sets the component.
 257       *
 258       * This method shouldn't be public, changing the component once it has been set potentially
 259       * invalidates permission checks.
 260       * A coding_error is now thrown if code attempts to change the component.
 261       *
 262       * @param string $component
 263       */
 264      public function set_component($component) {
 265          if (!empty($this->component) && $this->component !== $component) {
 266              throw new coding_exception('You cannot change the component of a comment once it has been set');
 267          }
 268          $this->component = $component;
 269          list($this->plugintype, $this->pluginname) = core_component::normalize_component($component);
 270      }
 271  
 272      /**
 273       * Determines if the user can view the comment.
 274       *
 275       * @param bool $value
 276       */
 277      public function set_view_permission($value) {
 278          $this->viewcap = (bool)$value;
 279      }
 280  
 281      /**
 282       * Determines if the user can post a comment
 283       *
 284       * @param bool $value
 285       */
 286      public function set_post_permission($value) {
 287          $this->postcap = (bool)$value;
 288      }
 289  
 290      /**
 291       * check posting comments permission
 292       * It will check based on user roles and ask modules
 293       * If you need to check permission by modules, a
 294       * function named $pluginname_check_comment_post must be implemented
 295       */
 296      private function check_permissions() {
 297          $this->postcap = has_capability('moodle/comment:post', $this->context);
 298          $this->viewcap = has_capability('moodle/comment:view', $this->context);
 299          if (!empty($this->plugintype)) {
 300              $permissions = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'permissions', array($this->comment_param), array('post'=>false, 'view'=>false));
 301              $this->postcap = $this->postcap && $permissions['post'];
 302              $this->viewcap = $this->viewcap && $permissions['view'];
 303          }
 304      }
 305  
 306      /**
 307       * Gets a link for this page that will work with JS disabled.
 308       *
 309       * @global moodle_page $PAGE
 310       * @param moodle_page $page
 311       * @return moodle_url
 312       */
 313      public function get_nojslink(moodle_page $page = null) {
 314          if ($page === null) {
 315              global $PAGE;
 316              $page = $PAGE;
 317          }
 318  
 319          $link = new moodle_url($page->url, array(
 320              'nonjscomment'    => true,
 321              'comment_itemid'  => $this->itemid,
 322              'comment_context' => $this->context->id,
 323              'comment_area'    => $this->commentarea,
 324          ));
 325          $link->remove_params(array('comment_page'));
 326          return $link;
 327      }
 328  
 329      /**
 330       * Sets the value of the notoggle option.
 331       *
 332       * If set to true then the user will not be able to expand and collase
 333       * the comment section.
 334       *
 335       * @param bool $newvalue
 336       */
 337      public function set_notoggle($newvalue = true) {
 338          $this->notoggle = (bool)$newvalue;
 339      }
 340  
 341      /**
 342       * Sets the value of the autostart option.
 343       *
 344       * If set to true then the comments will be loaded during page load.
 345       * Normally this happens only once the user expands the comment section.
 346       *
 347       * @param bool $newvalue
 348       */
 349      public function set_autostart($newvalue = true) {
 350          $this->autostart = (bool)$newvalue;
 351      }
 352  
 353      /**
 354       * Sets the displaycancel option
 355       *
 356       * If set to true then a cancel button will be shown when using the form
 357       * to post comments.
 358       *
 359       * @param bool $newvalue
 360       */
 361      public function set_displaycancel($newvalue = true) {
 362          $this->displaycancel = (bool)$newvalue;
 363      }
 364  
 365      /**
 366       * Sets the displaytotalcount option
 367       *
 368       * If set to true then the total number of comments will be displayed
 369       * when printing comments.
 370       *
 371       * @param bool $newvalue
 372       */
 373      public function set_displaytotalcount($newvalue = true) {
 374          $this->displaytotalcount = (bool)$newvalue;
 375      }
 376  
 377      /**
 378       * Initialises the JavaScript that enchances the comment API.
 379       *
 380       * @param moodle_page $page The moodle page object that the JavaScript should be
 381       *                          initialised for.
 382       */
 383      public function initialise_javascript(moodle_page $page) {
 384  
 385          $options = new stdClass;
 386          $options->client_id   = $this->cid;
 387          $options->commentarea = $this->commentarea;
 388          $options->itemid      = $this->itemid;
 389          $options->page        = 0;
 390          $options->courseid    = $this->courseid;
 391          $options->contextid   = $this->contextid;
 392          $options->component   = $this->component;
 393          $options->notoggle    = $this->notoggle;
 394          $options->autostart   = $this->autostart;
 395  
 396          $page->requires->js_init_call('M.core_comment.init', array($options), true);
 397  
 398          return true;
 399      }
 400  
 401      /**
 402       * Prepare comment code in html
 403       * @param  boolean $return
 404       * @return string|void
 405       */
 406      public function output($return = true) {
 407          global $PAGE, $OUTPUT;
 408          static $template_printed;
 409  
 410          $this->initialise_javascript($PAGE);
 411  
 412          if (!empty(self::$nonjs)) {
 413              // return non js comments interface
 414              return $this->print_comments(self::$comment_page, $return, true);
 415          }
 416  
 417          $html = '';
 418  
 419          // print html template
 420          // Javascript will use the template to render new comments
 421          if (empty($template_printed) && $this->can_view()) {
 422              $html .= html_writer::tag('div', $this->template, array('style' => 'display:none', 'id' => 'cmt-tmpl'));
 423              $template_printed = true;
 424          }
 425  
 426          if ($this->can_view()) {
 427              // print commenting icon and tooltip
 428              $html .= html_writer::start_tag('div', array('class' => 'mdl-left'));
 429              $html .= html_writer::link($this->get_nojslink($PAGE), get_string('showcommentsnonjs'), array('class' => 'showcommentsnonjs'));
 430  
 431              if (!$this->notoggle) {
 432                  // If toggling is enabled (notoggle=false) then print the controls to toggle
 433                  // comments open and closed
 434                  $countstring = '';
 435                  if ($this->displaytotalcount) {
 436                      $countstring = '('.$this->count().')';
 437                  }
 438                  $collapsedimage= 't/collapsed';
 439                  if (right_to_left()) {
 440                      $collapsedimage= 't/collapsed_rtl';
 441                  } else {
 442                      $collapsedimage= 't/collapsed';
 443                  }
 444                  $html .= html_writer::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid, 'href' => '#'));
 445                  $html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url($collapsedimage), 'alt' => $this->linktext, 'title' => $this->linktext));
 446                  $html .= html_writer::tag('span', $this->linktext.' '.$countstring, array('id' => 'comment-link-text-'.$this->cid));
 447                  $html .= html_writer::end_tag('a');
 448              }
 449  
 450              $html .= html_writer::start_tag('div', array('id' => 'comment-ctrl-'.$this->cid, 'class' => 'comment-ctrl'));
 451  
 452              if ($this->autostart) {
 453                  // If autostart has been enabled print the comments list immediatly
 454                  $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list comments-loaded'));
 455                  $html .= html_writer::tag('li', '', array('class' => 'first'));
 456                  $html .= $this->print_comments(0, true, false);
 457                  $html .= html_writer::end_tag('ul'); // .comment-list
 458                  $html .= $this->get_pagination(0);
 459              } else {
 460                  $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
 461                  $html .= html_writer::tag('li', '', array('class' => 'first'));
 462                  $html .= html_writer::end_tag('ul'); // .comment-list
 463                  $html .= html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
 464              }
 465  
 466              if ($this->can_post()) {
 467                  // print posting textarea
 468                  $textareaattrs = array(
 469                      'name' => 'content',
 470                      'rows' => 2,
 471                      'id' => 'dlg-content-'.$this->cid
 472                  );
 473                  if (!$this->fullwidth) {
 474                      $textareaattrs['cols'] = '20';
 475                  } else {
 476                      $textareaattrs['class'] = 'fullwidth';
 477                  }
 478  
 479                  $html .= html_writer::start_tag('div', array('class' => 'comment-area'));
 480                  $html .= html_writer::start_tag('div', array('class' => 'db'));
 481                  $html .= html_writer::tag('textarea', '', $textareaattrs);
 482                  $html .= html_writer::end_tag('div'); // .db
 483  
 484                  $html .= html_writer::start_tag('div', array('class' => 'fd', 'id' => 'comment-action-'.$this->cid));
 485                  $html .= html_writer::link('#', get_string('savecomment'), array('id' => 'comment-action-post-'.$this->cid));
 486  
 487                  if ($this->displaycancel) {
 488                      $html .= html_writer::tag('span', ' | ');
 489                      $html .= html_writer::link('#', get_string('cancel'), array('id' => 'comment-action-cancel-'.$this->cid));
 490                  }
 491  
 492                  $html .= html_writer::end_tag('div'); // .fd
 493                  $html .= html_writer::end_tag('div'); // .comment-area
 494                  $html .= html_writer::tag('div', '', array('class' => 'clearer'));
 495              }
 496  
 497              $html .= html_writer::end_tag('div'); // .comment-ctrl
 498              $html .= html_writer::end_tag('div'); // .mdl-left
 499          } else {
 500              $html = '';
 501          }
 502  
 503          if ($return) {
 504              return $html;
 505          } else {
 506              echo $html;
 507          }
 508      }
 509  
 510      /**
 511       * Return matched comments
 512       *
 513       * @param  int $page
 514       * @return array
 515       */
 516      public function get_comments($page = '') {
 517          global $DB, $CFG, $USER, $OUTPUT;
 518          if (!$this->can_view()) {
 519              return false;
 520          }
 521          if (!is_numeric($page)) {
 522              $page = 0;
 523          }
 524          $params = array();
 525          $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
 526          $start = $page * $perpage;
 527          $ufields = user_picture::fields('u');
 528          $sql = "SELECT $ufields, c.id AS cid, c.content AS ccontent, c.format AS cformat, c.timecreated AS ctimecreated
 529                    FROM {comments} c
 530                    JOIN {user} u ON u.id = c.userid
 531                   WHERE c.contextid = :contextid AND c.commentarea = :commentarea AND c.itemid = :itemid
 532                ORDER BY c.timecreated DESC";
 533          $params['contextid'] = $this->contextid;
 534          $params['commentarea'] = $this->commentarea;
 535          $params['itemid'] = $this->itemid;
 536  
 537          $comments = array();
 538          $formatoptions = array('overflowdiv' => true);
 539          $rs = $DB->get_recordset_sql($sql, $params, $start, $perpage);
 540          foreach ($rs as $u) {
 541              $c = new stdClass();
 542              $c->id          = $u->cid;
 543              $c->content     = $u->ccontent;
 544              $c->format      = $u->cformat;
 545              $c->timecreated = $u->ctimecreated;
 546              $c->strftimeformat = get_string('strftimerecentfull', 'langconfig');
 547              $url = new moodle_url('/user/view.php', array('id'=>$u->id, 'course'=>$this->courseid));
 548              $c->profileurl = $url->out(false); // URL should not be escaped just yet.
 549              $c->fullname = fullname($u);
 550              $c->time = userdate($c->timecreated, $c->strftimeformat);
 551              $c->content = format_text($c->content, $c->format, $formatoptions);
 552              $c->avatar = $OUTPUT->user_picture($u, array('size'=>18));
 553              $c->userid = $u->id;
 554  
 555              $candelete = $this->can_delete($c->id);
 556              if (($USER->id == $u->id) || !empty($candelete)) {
 557                  $c->delete = true;
 558              }
 559              $comments[] = $c;
 560          }
 561          $rs->close();
 562  
 563          if (!empty($this->plugintype)) {
 564              // moodle module will filter comments
 565              $comments = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'display', array($comments, $this->comment_param), $comments);
 566          }
 567  
 568          return $comments;
 569      }
 570  
 571      /**
 572       * Returns the number of comments associated with the details of this object
 573       *
 574       * @global moodle_database $DB
 575       * @return int
 576       */
 577      public function count() {
 578          global $DB;
 579          if ($this->totalcommentcount === null) {
 580              $this->totalcommentcount = $DB->count_records('comments', array('itemid' => $this->itemid, 'commentarea' => $this->commentarea, 'contextid' => $this->context->id));
 581          }
 582          return $this->totalcommentcount;
 583      }
 584  
 585      /**
 586       * Returns HTML to display a pagination bar
 587       *
 588       * @global stdClass $CFG
 589       * @global core_renderer $OUTPUT
 590       * @param int $page
 591       * @return string
 592       */
 593      public function get_pagination($page = 0) {
 594          global $CFG, $OUTPUT;
 595          $count = $this->count();
 596          $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
 597          $pages = (int)ceil($count/$perpage);
 598          if ($pages == 1 || $pages == 0) {
 599              return html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
 600          }
 601          if (!empty(self::$nonjs)) {
 602              // used in non-js interface
 603              return $OUTPUT->paging_bar($count, $page, $perpage, $this->get_nojslink(), 'comment_page');
 604          } else {
 605              // return ajax paging bar
 606              $str = '';
 607              $str .= '<div class="comment-paging" id="comment-pagination-'.$this->cid.'">';
 608              for ($p=0; $p<$pages; $p++) {
 609                  if ($p == $page) {
 610                      $class = 'curpage';
 611                  } else {
 612                      $class = 'pageno';
 613                  }
 614                  $str .= '<a href="#" class="'.$class.'" id="comment-page-'.$this->cid.'-'.$p.'">'.($p+1).'</a> ';
 615              }
 616              $str .= '</div>';
 617          }
 618          return $str;
 619      }
 620  
 621      /**
 622       * Add a new comment
 623       *
 624       * @global moodle_database $DB
 625       * @param string $content
 626       * @param int $format
 627       * @return stdClass
 628       */
 629      public function add($content, $format = FORMAT_MOODLE) {
 630          global $CFG, $DB, $USER, $OUTPUT;
 631          if (!$this->can_post()) {
 632              throw new comment_exception('nopermissiontocomment');
 633          }
 634          $now = time();
 635          $newcmt = new stdClass;
 636          $newcmt->contextid    = $this->contextid;
 637          $newcmt->commentarea  = $this->commentarea;
 638          $newcmt->itemid       = $this->itemid;
 639          $newcmt->content      = $content;
 640          $newcmt->format       = $format;
 641          $newcmt->userid       = $USER->id;
 642          $newcmt->timecreated  = $now;
 643  
 644          // This callback allow module to modify the content of comment, such as filter or replacement
 645          plugin_callback($this->plugintype, $this->pluginname, 'comment', 'add', array(&$newcmt, $this->comment_param));
 646  
 647          $cmt_id = $DB->insert_record('comments', $newcmt);
 648          if (!empty($cmt_id)) {
 649              $newcmt->id = $cmt_id;
 650              $newcmt->strftimeformat = get_string('strftimerecent', 'langconfig');
 651              $newcmt->fullname = fullname($USER);
 652              $url = new moodle_url('/user/view.php', array('id' => $USER->id, 'course' => $this->courseid));
 653              $newcmt->profileurl = $url->out();
 654              $newcmt->content = format_text($newcmt->content, $format, array('overflowdiv'=>true));
 655              $newcmt->avatar = $OUTPUT->user_picture($USER, array('size'=>16));
 656  
 657              $commentlist = array($newcmt);
 658  
 659              if (!empty($this->plugintype)) {
 660                  // Call the display callback to allow the plugin to format the newly added comment.
 661                  $commentlist = plugin_callback($this->plugintype,
 662                                                 $this->pluginname,
 663                                                 'comment',
 664                                                 'display',
 665                                                 array($commentlist, $this->comment_param),
 666                                                 $commentlist);
 667                  $newcmt = $commentlist[0];
 668              }
 669              $newcmt->time = userdate($newcmt->timecreated, $newcmt->strftimeformat);
 670  
 671              // Trigger comment created event.
 672              if (core_component::is_core_subsystem($this->component)) {
 673                  $eventclassname = '\\core\\event\\' . $this->component . '_comment_created';
 674              } else {
 675                  $eventclassname = '\\' . $this->component . '\\event\comment_created';
 676              }
 677              if (class_exists($eventclassname)) {
 678                  $event = $eventclassname::create(
 679                          array(
 680                              'context' => $this->context,
 681                              'objectid' => $newcmt->id,
 682                              'other' => array(
 683                                  'itemid' => $this->itemid
 684                                  )
 685                              ));
 686                  $event->trigger();
 687              }
 688  
 689              return $newcmt;
 690          } else {
 691              throw new comment_exception('dbupdatefailed');
 692          }
 693      }
 694  
 695      /**
 696       * delete by context, commentarea and itemid
 697       * @param stdClass|array $param {
 698       *            contextid => int the context in which the comments exist [required]
 699       *            commentarea => string the comment area [optional]
 700       *            itemid => int comment itemid [optional]
 701       * }
 702       * @return boolean
 703       */
 704      public static function delete_comments($param) {
 705          global $DB;
 706          $param = (array)$param;
 707          if (empty($param['contextid'])) {
 708              return false;
 709          }
 710          $DB->delete_records('comments', $param);
 711          return true;
 712      }
 713  
 714      /**
 715       * Delete page_comments in whole course, used by course reset
 716       *
 717       * @param stdClass $context course context
 718       */
 719      public static function reset_course_page_comments($context) {
 720          global $DB;
 721          $contexts = array();
 722          $contexts[] = $context->id;
 723          $children = $context->get_child_contexts();
 724          foreach ($children as $c) {
 725              $contexts[] = $c->id;
 726          }
 727          list($ids, $params) = $DB->get_in_or_equal($contexts);
 728          $DB->delete_records_select('comments', "commentarea='page_comments' AND contextid $ids", $params);
 729      }
 730  
 731      /**
 732       * Delete a comment
 733       *
 734       * @param  int $commentid
 735       * @return bool
 736       */
 737      public function delete($commentid) {
 738          global $DB, $USER;
 739          $candelete = has_capability('moodle/comment:delete', $this->context);
 740          if (!$comment = $DB->get_record('comments', array('id'=>$commentid))) {
 741              throw new comment_exception('dbupdatefailed');
 742          }
 743          if (!($USER->id == $comment->userid || !empty($candelete))) {
 744              throw new comment_exception('nopermissiontocomment');
 745          }
 746          $DB->delete_records('comments', array('id'=>$commentid));
 747          // Trigger comment delete event.
 748          if (core_component::is_core_subsystem($this->component)) {
 749              $eventclassname = '\\core\\event\\' . $this->component . '_comment_deleted';
 750          } else {
 751              $eventclassname = '\\' . $this->component . '\\event\comment_deleted';
 752          }
 753          if (class_exists($eventclassname)) {
 754              $event = $eventclassname::create(
 755                      array(
 756                          'context' => $this->context,
 757                          'objectid' => $commentid,
 758                          'other' => array(
 759                              'itemid' => $this->itemid
 760                              )
 761                          ));
 762              $event->add_record_snapshot('comments', $comment);
 763              $event->trigger();
 764          }
 765          return true;
 766      }
 767  
 768      /**
 769       * Print comments
 770       *
 771       * @param int $page
 772       * @param bool $return return comments list string or print it out
 773       * @param bool $nonjs print nonjs comments list or not?
 774       * @return string|void
 775       */
 776      public function print_comments($page = 0, $return = true, $nonjs = true) {
 777          global $DB, $CFG, $PAGE;
 778  
 779          if (!$this->can_view()) {
 780              return '';
 781          }
 782  
 783          $html = '';
 784          if (!(self::$comment_itemid == $this->itemid &&
 785              self::$comment_context == $this->context->id &&
 786              self::$comment_area == $this->commentarea)) {
 787              $page = 0;
 788          }
 789          $comments = $this->get_comments($page);
 790  
 791          $html = '';
 792          if ($nonjs) {
 793              $html .= html_writer::tag('h3', get_string('comments'));
 794              $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
 795          }
 796          // Reverse the comments array to display them in the correct direction
 797          foreach (array_reverse($comments) as $cmt) {
 798              $html .= html_writer::tag('li', $this->print_comment($cmt, $nonjs), array('id' => 'comment-'.$cmt->id.'-'.$this->cid));
 799          }
 800          if ($nonjs) {
 801              $html .= html_writer::end_tag('ul');
 802              $html .= $this->get_pagination($page);
 803          }
 804          if ($nonjs && $this->can_post()) {
 805              // Form to add comments
 806              $html .= html_writer::start_tag('form', array('method' => 'post', 'action' => new moodle_url('/comment/comment_post.php')));
 807              // Comment parameters
 808              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'contextid', 'value' => $this->contextid));
 809              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action',    'value' => 'add'));
 810              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'area',      'value' => $this->commentarea));
 811              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'component', 'value' => $this->component));
 812              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'itemid',    'value' => $this->itemid));
 813              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'courseid',  'value' => $this->courseid));
 814              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey',   'value' => sesskey()));
 815              $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'returnurl', 'value' => $PAGE->url));
 816              // Textarea for the actual comment
 817              $html .= html_writer::tag('textarea', '', array('name' => 'content', 'rows' => 2));
 818              // Submit button to add the comment
 819              $html .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('submit')));
 820              $html .= html_writer::end_tag('form');
 821          }
 822          if ($return) {
 823              return $html;
 824          } else {
 825              echo $html;
 826          }
 827      }
 828  
 829      /**
 830       * Returns an array containing comments in HTML format.
 831       *
 832       * @global core_renderer $OUTPUT
 833       * @param stdClass $cmt {
 834       *          id => int comment id
 835       *          content => string comment content
 836       *          format  => int comment text format
 837       *          timecreated => int comment's timecreated
 838       *          profileurl  => string link to user profile
 839       *          fullname    => comment author's full name
 840       *          avatar      => string user's avatar
 841       *          delete      => boolean does user have permission to delete comment?
 842       * }
 843       * @param bool $nonjs
 844       * @return array
 845       */
 846      public function print_comment($cmt, $nonjs = true) {
 847          global $OUTPUT;
 848          $patterns = array();
 849          $replacements = array();
 850  
 851          if (!empty($cmt->delete) && empty($nonjs)) {
 852              $deletelink  = html_writer::start_tag('div', array('class'=>'comment-delete'));
 853              $deletelink .= html_writer::start_tag('a', array('href' => '#', 'id' => 'comment-delete-'.$this->cid.'-'.$cmt->id));
 854              $deletelink .= $OUTPUT->pix_icon('t/delete', get_string('delete'));
 855              $deletelink .= html_writer::end_tag('a');
 856              $deletelink .= html_writer::end_tag('div');
 857              $cmt->content = $deletelink . $cmt->content;
 858          }
 859          $patterns[] = '___picture___';
 860          $patterns[] = '___name___';
 861          $patterns[] = '___content___';
 862          $patterns[] = '___time___';
 863          $replacements[] = $cmt->avatar;
 864          $replacements[] = html_writer::link($cmt->profileurl, $cmt->fullname);
 865          $replacements[] = $cmt->content;
 866          $replacements[] = $cmt->time;
 867  
 868          // use html template to format a single comment.
 869          return str_replace($patterns, $replacements, $this->template);
 870      }
 871  
 872      /**
 873       * Revoke validate callbacks
 874       *
 875       * @param stdClass $params addtionall parameters need to add to callbacks
 876       */
 877      protected function validate($params=array()) {
 878          foreach ($params as $key=>$value) {
 879              $this->comment_param->$key = $value;
 880          }
 881          $validation = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'validate', array($this->comment_param), false);
 882          if (!$validation) {
 883              throw new comment_exception('invalidcommentparam');
 884          }
 885      }
 886  
 887      /**
 888       * Returns true if the user is able to view comments
 889       * @return bool
 890       */
 891      public function can_view() {
 892          $this->validate();
 893          return !empty($this->viewcap);
 894      }
 895  
 896      /**
 897       * Returns true if the user can add comments against this comment description
 898       * @return bool
 899       */
 900      public function can_post() {
 901          $this->validate();
 902          return isloggedin() && !empty($this->postcap);
 903      }
 904  
 905      /**
 906       * Returns true if the user can delete this comment
 907       * @param int $commentid
 908       * @return bool
 909       */
 910      public function can_delete($commentid) {
 911          $this->validate(array('commentid'=>$commentid));
 912          return has_capability('moodle/comment:delete', $this->context);
 913      }
 914  
 915      /**
 916       * Returns the component associated with the comment
 917       * @return string
 918       */
 919      public function get_compontent() {
 920          return $this->component;
 921      }
 922  
 923      /**
 924       * Returns the context associated with the comment
 925       * @return stdClass
 926       */
 927      public function get_context() {
 928          return $this->context;
 929      }
 930  
 931      /**
 932       * Returns the course id associated with the comment
 933       * @return int
 934       */
 935      public function get_courseid() {
 936          return $this->courseid;
 937      }
 938  
 939      /**
 940       * Returns the course module associated with the comment
 941       *
 942       * @return stdClass
 943       */
 944      public function get_cm() {
 945          return $this->cm;
 946      }
 947  
 948      /**
 949       * Returns the item id associated with the comment
 950       *
 951       * @return int
 952       */
 953      public function get_itemid() {
 954          return $this->itemid;
 955      }
 956  
 957      /**
 958       * Returns the comment area associated with the commentarea
 959       *
 960       * @return stdClass
 961       */
 962      public function get_commentarea() {
 963          return $this->commentarea;
 964      }
 965  
 966      /**
 967       * Make the comments textarea fullwidth.
 968       *
 969       * @since 2.8.1 + 2.7.4
 970       * @param bool $fullwidth
 971       */
 972      public function set_fullwidth($fullwidth = true) {
 973          $this->fullwidth = (bool)$fullwidth;
 974      }
 975  }
 976  
 977  /**
 978   * Comment exception class
 979   *
 980   * @package   core
 981   * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
 982   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 983   */
 984  class comment_exception extends moodle_exception {
 985  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1