Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   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   * A URL factory for the forum.
  19   *
  20   * @package    mod_forum
  21   * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace mod_forum\local\factories;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  use mod_forum\local\entities\author as author_entity;
  30  use mod_forum\local\entities\forum as forum_entity;
  31  use mod_forum\local\entities\discussion as discussion_entity;
  32  use mod_forum\local\entities\post as post_entity;
  33  use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
  34  use moodle_url;
  35  use stored_file;
  36  use user_picture;
  37  
  38  require_once($CFG->dirroot . '/mod/forum/lib.php');
  39  
  40  /**
  41   * A URL factory for the forum.
  42   *
  43   * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
  44   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  45   */
  46  class url {
  47      /** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
  48      private $legacydatamapperfactory;
  49  
  50      /**
  51       * Constructor.
  52       *
  53       * @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
  54       */
  55      public function __construct(legacy_data_mapper_factory $legacydatamapperfactory) {
  56          $this->legacydatamapperfactory = $legacydatamapperfactory;
  57      }
  58  
  59      /**
  60       * Get the course url from the given course id.
  61       *
  62       * @param int $courseid The course id
  63       * @return moodle_url
  64       */
  65      public function get_course_url_from_courseid(int $courseid) : moodle_url {
  66          return new moodle_url('/course/view.php', [
  67              'id' => $courseid,
  68          ]);
  69      }
  70  
  71      /**
  72       * Get the course url from the given forum entity.
  73       *
  74       * @param forum_entity $forum The forum entity
  75       * @return moodle_url
  76       */
  77      public function get_course_url_from_forum(forum_entity $forum) : moodle_url {
  78          return $this->get_course_url_from_courseid($forum->get_course_id());
  79      }
  80  
  81      /**
  82       * Get the create discussion url for the given forum.
  83       *
  84       * @param forum_entity $forum The forum entity
  85       * @return moodle_url
  86       */
  87      public function get_discussion_create_url(forum_entity $forum) : moodle_url {
  88          return new moodle_url('/mod/forum/post.php', [
  89              'forum' => $forum->get_id(),
  90          ]);
  91      }
  92  
  93      /**
  94       * Get the view forum url for the given forum and optionally a page number.
  95       *
  96       * @param forum_entity $forum The forum entity
  97       * @param int|null $pageno The page number
  98       * @param int|null $sortorder The sorting order
  99       * @return moodle_url
 100       */
 101      public function get_forum_view_url_from_forum(forum_entity $forum, ?int $pageno = null,
 102              ?int $sortorder = null) : moodle_url {
 103  
 104          return $this->get_forum_view_url_from_course_module_id($forum->get_course_module_record()->id, $pageno, $sortorder);
 105      }
 106  
 107      /**
 108       * Get the view forum url for the given course module id and optionally a page number.
 109       *
 110       * @param int $coursemoduleid The course module id
 111       * @param int|null $pageno The page number
 112       * @param int|null $sortorder The sorting order
 113       * @return moodle_url
 114       */
 115      public function get_forum_view_url_from_course_module_id(int $coursemoduleid, ?int $pageno = null,
 116              ?int $sortorder = null) : moodle_url {
 117  
 118          $url = new moodle_url('/mod/forum/view.php', [
 119              'id' => $coursemoduleid,
 120          ]);
 121  
 122          if (null !== $pageno) {
 123              $url->param('p', $pageno);
 124          }
 125  
 126          if (null !== $sortorder) {
 127              $url->param('o', $sortorder);
 128          }
 129  
 130          return $url;
 131      }
 132  
 133      /**
 134       * Get the view discussion url from the given discussion id.
 135       *
 136       * @param int $discussionid The discussion id
 137       * @return moodle_url
 138       */
 139      public function get_discussion_view_url_from_discussion_id(int $discussionid) : moodle_url {
 140          return new moodle_url('/mod/forum/discuss.php', [
 141              'd' => $discussionid
 142          ]);
 143      }
 144  
 145      /**
 146       * Get the view discussion url from the given discussion.
 147       *
 148       * @param discussion_entity $discussion The discussion
 149       * @return moodle_url
 150       */
 151      public function get_discussion_view_url_from_discussion(discussion_entity $discussion) : moodle_url {
 152          return $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
 153      }
 154  
 155      /**
 156       * Get the url to view the first unread post in a discussion.
 157       *
 158       * @param discussion_entity $discussion The discussion
 159       * @return moodle_url
 160       */
 161      public function get_discussion_view_first_unread_post_url_from_discussion(discussion_entity $discussion) {
 162          $viewurl = $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
 163          $viewurl->set_anchor('unread');
 164  
 165          return $viewurl;
 166      }
 167  
 168      /**
 169       * Get the url to view the latest post in a discussion.
 170       *
 171       * @param discussion_entity $discussion The discussion
 172       * @param int|null $latestpost The id of the latest post
 173       * @return moodle_url
 174       */
 175      public function get_discussion_view_latest_post_url_from_discussion(discussion_entity $discussion, ?int $latestpost) {
 176          $viewurl = $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
 177          if (null === $latestpost) {
 178              return $viewurl;
 179          } else {
 180              return new moodle_url($viewurl, ['parent' => $latestpost]);
 181          }
 182      }
 183  
 184      /**
 185       * Get the url to view a discussion from a post.
 186       *
 187       * @param post_entity $post The post
 188       * @return moodle_url
 189       */
 190      public function get_discussion_view_url_from_post(post_entity $post) : moodle_url {
 191          return $this->get_discussion_view_url_from_discussion_id($post->get_discussion_id());
 192      }
 193  
 194      /**
 195       * Get the url to view a discussion from a discussion id and post id.
 196       *
 197       * @param int $discussionid The discussion id
 198       * @param int $postid The post id
 199       * @return moodle_url
 200       */
 201      public function get_view_post_url_from_post_id(int $discussionid, int $postid) : moodle_url {
 202          $url = $this->get_discussion_view_url_from_discussion_id($discussionid);
 203          $url->set_anchor('p' . $postid);
 204          return $url;
 205      }
 206  
 207      /**
 208       * Get the url to view a post in the context of the rest of the discussion.
 209       *
 210       * @param post_entity $post The post
 211       * @return moodle_url
 212       */
 213      public function get_view_post_url_from_post(post_entity $post) : moodle_url {
 214          return $this->get_view_post_url_from_post_id($post->get_discussion_id(), $post->get_id());
 215      }
 216  
 217      /**
 218       * Get the url to view a post and it's replies in isolation without the rest of the
 219       * discussion.
 220       *
 221       * @param int $discussionid The discussion id
 222       * @param int $postid The post id
 223       * @return moodle_url
 224       */
 225      public function get_view_isolated_post_url_from_post_id(int $discussionid, int $postid) : moodle_url {
 226          $url = $this->get_discussion_view_url_from_discussion_id($discussionid);
 227          $url->params(['parent' => $postid]);
 228          return $url;
 229      }
 230  
 231      /**
 232       * Get the url to view a post and it's replies in isolation without the rest of the
 233       * discussion.
 234       *
 235       * @param post_entity $post The post
 236       * @return moodle_url
 237       */
 238      public function get_view_isolated_post_url_from_post(post_entity $post) : moodle_url {
 239          return $this->get_view_isolated_post_url_from_post_id($post->get_discussion_id(), $post->get_id());
 240      }
 241  
 242      /**
 243       * Get the url to edit a post.
 244       *
 245       * @param forum_entity $forum The forum the post belongs to
 246       * @param post_entity $post The post
 247       * @return moodle_url
 248       */
 249      public function get_edit_post_url_from_post(forum_entity $forum, post_entity $post) : moodle_url {
 250          if ($forum->get_type() == 'single' && !$post->has_parent()) {
 251              return new moodle_url('/course/modedit.php', [
 252                  'update' => $forum->get_course_module_record()->id,
 253                  'sesskey' => sesskey(),
 254                  'return' => 1
 255              ]);
 256          } else {
 257              return new moodle_url('/mod/forum/post.php', [
 258                  'edit' => $post->get_id()
 259              ]);
 260          }
 261      }
 262  
 263      /**
 264       * Get the url to split a discussion at a post.
 265       *
 266       * @param post_entity $post The post
 267       * @return moodle_url
 268       */
 269      public function get_split_discussion_at_post_url_from_post(post_entity $post) : moodle_url {
 270          return new moodle_url('/mod/forum/post.php', [
 271              'prune' => $post->get_id()
 272          ]);
 273      }
 274  
 275      /**
 276       * Get the url to delete a post.
 277       *
 278       * @param post_entity $post The post
 279       * @return moodle_url
 280       */
 281      public function get_delete_post_url_from_post(post_entity $post) : moodle_url {
 282          return new moodle_url('/mod/forum/post.php', [
 283              'delete' => $post->get_id()
 284          ]);
 285      }
 286  
 287      /**
 288       * Get the url to reply to a post.
 289       *
 290       * @param post_entity $post The post
 291       * @return moodle_url
 292       */
 293      public function get_reply_to_post_url_from_post(post_entity $post) : moodle_url {
 294          return new moodle_url('/mod/forum/post.php#mformforum', [
 295              'reply' => $post->get_id()
 296          ]);
 297      }
 298  
 299      /**
 300       * Get the url to export (see portfolios) a post.
 301       *
 302       * @param post_entity $post The post
 303       * @return moodle_url
 304       */
 305      public function get_export_post_url_from_post(post_entity $post) : ?moodle_url {
 306          global $CFG;
 307  
 308          require_once($CFG->libdir . '/portfoliolib.php');
 309          $button = new \portfolio_add_button();
 310          $button->set_callback_options('forum_portfolio_caller', ['postid' => $post->get_id()], 'mod_forum');
 311          if ($post->has_attachments()) {
 312              $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
 313          } else {
 314              $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
 315          }
 316  
 317          $url = $button->to_html(PORTFOLIO_ADD_MOODLE_URL);
 318          return $url ?: null;
 319      }
 320  
 321      /**
 322       * Get the url to mark a post as read.
 323       *
 324       * @param post_entity $post The post
 325       * @param int $displaymode The display mode to show the forum in after marking as read
 326       * @return moodle_url
 327       */
 328      public function get_mark_post_as_read_url_from_post(post_entity $post, int $displaymode = FORUM_MODE_THREADED) : moodle_url {
 329          $params = [
 330              'd' => $post->get_discussion_id(),
 331              'postid' => $post->get_id(),
 332              'mark' => 'read'
 333          ];
 334  
 335          $url = new moodle_url('/mod/forum/discuss.php', $params);
 336  
 337          if ($displaymode == FORUM_MODE_THREADED) {
 338              $url->param('parent', $post->get_parent_id());
 339          } else {
 340              $url->set_anchor('p' . $post->get_id());
 341          }
 342  
 343          return $url;
 344      }
 345  
 346      /**
 347       * Get the url to mark a post as unread.
 348       *
 349       * @param post_entity $post The post
 350       * @param int $displaymode The display mode to show the forum in after marking as unread
 351       * @return moodle_url
 352       */
 353      public function get_mark_post_as_unread_url_from_post(post_entity $post, int $displaymode = FORUM_MODE_THREADED) : moodle_url {
 354          $params = [
 355              'd' => $post->get_discussion_id(),
 356              'postid' => $post->get_id(),
 357              'mark' => 'unread'
 358          ];
 359  
 360          $url = new moodle_url('/mod/forum/discuss.php', $params);
 361  
 362          if ($displaymode == FORUM_MODE_THREADED) {
 363              $url->param('parent', $post->get_parent_id());
 364          } else {
 365              $url->set_anchor('p' . $post->get_id());
 366          }
 367  
 368          return $url;
 369      }
 370  
 371      /**
 372       * Get the url to export attachments for a post.
 373       *
 374       * @param post_entity $post The post
 375       * @param stored_file $attachment
 376       * @return moodle_url|null
 377       */
 378      public function get_export_attachment_url_from_post_and_attachment(post_entity $post, stored_file $attachment) : ?moodle_url {
 379          global $CFG;
 380  
 381          require_once($CFG->libdir . '/portfoliolib.php');
 382          $button = new \portfolio_add_button();
 383          $button->set_callback_options(
 384              'forum_portfolio_caller',
 385              ['postid' => $post->get_id(), 'attachment' => $attachment->get_id()],
 386              'mod_forum'
 387          );
 388          $button->set_format_by_file($attachment);
 389          $url = $button->to_html(PORTFOLIO_ADD_MOODLE_URL);
 390          return $url ?: null;
 391      }
 392  
 393      /**
 394       * Get the url to view an author's profile.
 395       *
 396       * @param author_entity $author The author
 397       * @param int $courseid The course id
 398       * @return moodle_url
 399       */
 400      public function get_author_profile_url(author_entity $author, int $courseid) : moodle_url {
 401          return new moodle_url('/user/view.php', [
 402              'id' => $author->get_id(),
 403              'course' => $courseid
 404          ]);
 405      }
 406  
 407      /**
 408       * Get the url to view the author's profile image. The author's context id should be
 409       * provided to prevent the code from needing to load it.
 410       *
 411       * @param author_entity $author The author
 412       * @param int|null $authorcontextid The author context id
 413       * @param int $size The size of the image to return
 414       * @return moodle_url
 415       */
 416      public function get_author_profile_image_url(
 417          author_entity $author,
 418          int $authorcontextid = null,
 419          int $size = 100
 420      ) : moodle_url {
 421          global $PAGE;
 422  
 423          $datamapper = $this->legacydatamapperfactory->get_author_data_mapper();
 424          $record = $datamapper->to_legacy_object($author);
 425          $record->contextid = $authorcontextid;
 426          $userpicture = new user_picture($record);
 427          $userpicture->size = $size;
 428  
 429          return $userpicture->get_url($PAGE);
 430      }
 431  
 432      /**
 433       * Get the url to view an author's group.
 434       *
 435       * @param \stdClass $group The group
 436       * @return moodle_url
 437       */
 438      public function get_author_group_url(\stdClass $group) : moodle_url {
 439          return new moodle_url('/user/index.php', [
 440                  'id' => $group->courseid,
 441                  'group' => $group->id
 442          ]);
 443      }
 444      /**
 445       * Get the url to mark a discussion as read.
 446       *
 447       * @param forum_entity $forum The forum that the discussion belongs to
 448       * @param discussion_entity $discussion The discussion
 449       * @return moodle_url
 450       */
 451      public function get_mark_discussion_as_read_url_from_discussion(
 452          forum_entity $forum,
 453          discussion_entity $discussion
 454      ) : moodle_url {
 455          return new moodle_url('/mod/forum/markposts.php', [
 456              'f' => $discussion->get_forum_id(),
 457              'd' => $discussion->get_id(),
 458              'mark' => 'read',
 459              'sesskey' => sesskey(),
 460              'return' => $this->get_forum_view_url_from_forum($forum)->out(),
 461          ]);
 462      }
 463  
 464      /**
 465       * Get the url to mark all discussions as read.
 466       *
 467       * @param forum_entity $forum The forum that the discussions belong to
 468       * @return moodle_url
 469       */
 470      public function get_mark_all_discussions_as_read_url(forum_entity $forum) : moodle_url {
 471          return new moodle_url('/mod/forum/markposts.php', [
 472              'f' => $forum->get_id(),
 473              'mark' => 'read',
 474              'sesskey' => sesskey(),
 475              'return' => $this->get_forum_view_url_from_forum($forum)->out(),
 476          ]);
 477      }
 478  
 479      /**
 480       * Get the url to subscribe to a discussion.
 481       *
 482       * @param discussion_entity $discussion The discussion
 483       * @return moodle_url
 484       */
 485      public function get_discussion_subscribe_url(discussion_entity $discussion) : moodle_url {
 486          return new moodle_url('/mod/forum/subscribe.php', [
 487              'sesskey' => sesskey(),
 488              'id' => $discussion->get_forum_id(),
 489              'd' => $discussion->get_id()
 490          ]);
 491      }
 492  
 493      /**
 494       * Generate the pinned discussion link
 495       *
 496       * @param discussion_entity $discussion
 497       * @return moodle_url
 498       * @throws \moodle_exception
 499       */
 500      public function get_pin_discussion_url_from_discussion(discussion_entity $discussion) : moodle_url {
 501          return new moodle_url('discuss.php', [
 502              'sesskey' => sesskey(),
 503              'd' => $discussion->get_id(),
 504              'pin' => $discussion->is_pinned() ? FORUM_DISCUSSION_UNPINNED : FORUM_DISCUSSION_PINNED
 505          ]);
 506      }
 507  }