PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/mod/forum/classes/output/forum_post.php

http://github.com/moodle/moodle
PHP | 584 lines | 253 code | 70 blank | 261 comment | 14 complexity | a405bdcbd23ed815286f53cab7be2e34 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  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. * Forum post renderable.
  18. *
  19. * @package mod_forum
  20. * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace mod_forum\output;
  24. defined('MOODLE_INTERNAL') || die();
  25. /**
  26. * Forum post renderable.
  27. *
  28. * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30. *
  31. * @property boolean $viewfullnames Whether to override fullname()
  32. */
  33. class forum_post implements \renderable, \templatable {
  34. /**
  35. * The course that the forum post is in.
  36. *
  37. * @var object $course
  38. */
  39. protected $course = null;
  40. /**
  41. * The course module for the forum.
  42. *
  43. * @var object $cm
  44. */
  45. protected $cm = null;
  46. /**
  47. * The forum that the post is in.
  48. *
  49. * @var object $forum
  50. */
  51. protected $forum = null;
  52. /**
  53. * The discussion that the forum post is in.
  54. *
  55. * @var object $discussion
  56. */
  57. protected $discussion = null;
  58. /**
  59. * The forum post being displayed.
  60. *
  61. * @var object $post
  62. */
  63. protected $post = null;
  64. /**
  65. * Whether the user can reply to this post.
  66. *
  67. * @var boolean $canreply
  68. */
  69. protected $canreply = false;
  70. /**
  71. * Whether to override forum display when displaying usernames.
  72. * @var boolean $viewfullnames
  73. */
  74. protected $viewfullnames = false;
  75. /**
  76. * The user that is reading the post.
  77. *
  78. * @var object $userto
  79. */
  80. protected $userto = null;
  81. /**
  82. * The user that wrote the post.
  83. *
  84. * @var object $author
  85. */
  86. protected $author = null;
  87. /**
  88. * An associative array indicating which keys on this object should be writeable.
  89. *
  90. * @var array $writablekeys
  91. */
  92. protected $writablekeys = array(
  93. 'viewfullnames' => true,
  94. );
  95. /**
  96. * Builds a renderable forum post
  97. *
  98. * @param object $course Course of the forum
  99. * @param object $cm Course Module of the forum
  100. * @param object $forum The forum of the post
  101. * @param object $discussion Discussion thread in which the post appears
  102. * @param object $post The post
  103. * @param object $author Author of the post
  104. * @param object $recipient Recipient of the email
  105. * @param bool $canreply True if the user can reply to the post
  106. */
  107. public function __construct($course, $cm, $forum, $discussion, $post, $author, $recipient, $canreply) {
  108. $this->course = $course;
  109. $this->cm = $cm;
  110. $this->forum = $forum;
  111. $this->discussion = $discussion;
  112. $this->post = $post;
  113. $this->author = $author;
  114. $this->userto = $recipient;
  115. $this->canreply = $canreply;
  116. }
  117. /**
  118. * Export this data so it can be used as the context for a mustache template.
  119. *
  120. * @param \mod_forum_renderer $renderer The render to be used for formatting the message and attachments
  121. * @param bool $plaintext Whethe the target is a plaintext target
  122. * @return array Data ready for use in a mustache template
  123. */
  124. public function export_for_template(\renderer_base $renderer, $plaintext = false) {
  125. if ($plaintext) {
  126. return $this->export_for_template_text($renderer);
  127. } else {
  128. return $this->export_for_template_html($renderer);
  129. }
  130. }
  131. /**
  132. * Export this data so it can be used as the context for a mustache template.
  133. *
  134. * @param \mod_forum_renderer $renderer The render to be used for formatting the message and attachments
  135. * @return array Data ready for use in a mustache template
  136. */
  137. protected function export_for_template_text(\mod_forum_renderer $renderer) {
  138. $data = $this->export_for_template_shared($renderer);
  139. return $data + array(
  140. 'id' => html_entity_decode($this->post->id),
  141. 'coursename' => html_entity_decode($this->get_coursename()),
  142. 'courselink' => html_entity_decode($this->get_courselink()),
  143. 'forumname' => html_entity_decode($this->get_forumname()),
  144. 'showdiscussionname' => html_entity_decode($this->get_showdiscussionname()),
  145. 'discussionname' => html_entity_decode($this->get_discussionname()),
  146. 'subject' => html_entity_decode($this->get_subject()),
  147. 'authorfullname' => html_entity_decode($this->get_author_fullname()),
  148. 'postdate' => html_entity_decode($this->get_postdate()),
  149. // Format some components according to the renderer.
  150. 'message' => html_entity_decode($renderer->format_message_text($this->cm, $this->post)),
  151. 'attachments' => html_entity_decode($renderer->format_message_attachments($this->cm, $this->post)),
  152. 'canreply' => $this->canreply,
  153. 'permalink' => $this->get_permalink(),
  154. 'firstpost' => $this->get_is_firstpost(),
  155. 'replylink' => $this->get_replylink(),
  156. 'unsubscribediscussionlink' => $this->get_unsubscribediscussionlink(),
  157. 'unsubscribeforumlink' => $this->get_unsubscribeforumlink(),
  158. 'parentpostlink' => $this->get_parentpostlink(),
  159. 'forumindexlink' => $this->get_forumindexlink(),
  160. 'forumviewlink' => $this->get_forumviewlink(),
  161. 'discussionlink' => $this->get_discussionlink(),
  162. 'authorlink' => $this->get_authorlink(),
  163. 'authorpicture' => $this->get_author_picture($renderer),
  164. 'grouppicture' => $this->get_group_picture($renderer),
  165. );
  166. }
  167. /**
  168. * Export this data so it can be used as the context for a mustache template.
  169. *
  170. * @param \mod_forum_renderer $renderer The render to be used for formatting the message and attachments
  171. * @return array Data ready for use in a mustache template
  172. */
  173. protected function export_for_template_html(\mod_forum_renderer $renderer) {
  174. $data = $this->export_for_template_shared($renderer);
  175. return $data + array(
  176. 'id' => $this->post->id,
  177. 'coursename' => $this->get_coursename(),
  178. 'courselink' => $this->get_courselink(),
  179. 'forumname' => $this->get_forumname(),
  180. 'showdiscussionname' => $this->get_showdiscussionname(),
  181. 'discussionname' => $this->get_discussionname(),
  182. 'subject' => $this->get_subject(),
  183. 'authorfullname' => $this->get_author_fullname(),
  184. 'postdate' => $this->get_postdate(),
  185. // Format some components according to the renderer.
  186. 'message' => $renderer->format_message_text($this->cm, $this->post),
  187. 'attachments' => $renderer->format_message_attachments($this->cm, $this->post),
  188. );
  189. }
  190. /**
  191. * Export this data so it can be used as the context for a mustache template.
  192. *
  193. * @param \mod_forum_renderer $renderer The render to be used for formatting the message and attachments
  194. * @return stdClass Data ready for use in a mustache template
  195. */
  196. protected function export_for_template_shared(\mod_forum_renderer $renderer) {
  197. return array(
  198. 'canreply' => $this->canreply,
  199. 'permalink' => $this->get_permalink(),
  200. 'firstpost' => $this->get_is_firstpost(),
  201. 'replylink' => $this->get_replylink(),
  202. 'unsubscribediscussionlink' => $this->get_unsubscribediscussionlink(),
  203. 'unsubscribeforumlink' => $this->get_unsubscribeforumlink(),
  204. 'parentpostlink' => $this->get_parentpostlink(),
  205. 'forumindexlink' => $this->get_forumindexlink(),
  206. 'forumviewlink' => $this->get_forumviewlink(),
  207. 'discussionlink' => $this->get_discussionlink(),
  208. 'authorlink' => $this->get_authorlink(),
  209. 'authorpicture' => $this->get_author_picture($renderer),
  210. 'grouppicture' => $this->get_group_picture($renderer),
  211. 'isprivatereply' => !empty($this->post->privatereplyto),
  212. );
  213. }
  214. /**
  215. * Magically sets a property against this object.
  216. *
  217. * @param string $key
  218. * @param mixed $value
  219. */
  220. public function __set($key, $value) {
  221. // First attempt to use the setter function.
  222. $methodname = 'set_' . $key;
  223. if (method_exists($this, $methodname)) {
  224. return $this->{$methodname}($value);
  225. }
  226. // Fall back to the writable keys list.
  227. if (isset($this->writablekeys[$key]) && $this->writablekeys[$key]) {
  228. return $this->{$key} = $value;
  229. }
  230. // Throw an error rather than fail silently.
  231. throw new \coding_exception('Tried to set unknown property "' . $key . '"');
  232. }
  233. /**
  234. * Whether this is the first post.
  235. *
  236. * @return boolean
  237. */
  238. public function get_is_firstpost() {
  239. return empty($this->post->parent);
  240. }
  241. /**
  242. * Get the link to the course.
  243. *
  244. * @return string
  245. */
  246. public function get_courselink() {
  247. $link = new \moodle_url(
  248. // Posts are viewed on the topic.
  249. '/course/view.php', array(
  250. 'id' => $this->course->id,
  251. )
  252. );
  253. return $link->out(false);
  254. }
  255. /**
  256. * Get the link to the forum index for this course.
  257. *
  258. * @return string
  259. */
  260. public function get_forumindexlink() {
  261. $link = new \moodle_url(
  262. // Posts are viewed on the topic.
  263. '/mod/forum/index.php', array(
  264. 'id' => $this->course->id,
  265. )
  266. );
  267. return $link->out(false);
  268. }
  269. /**
  270. * Get the link to the view page for this forum.
  271. *
  272. * @return string
  273. */
  274. public function get_forumviewlink() {
  275. $link = new \moodle_url(
  276. // Posts are viewed on the topic.
  277. '/mod/forum/view.php', array(
  278. 'f' => $this->forum->id,
  279. )
  280. );
  281. return $link->out(false);
  282. }
  283. /**
  284. * Get the link to the current discussion.
  285. *
  286. * @return string
  287. */
  288. protected function _get_discussionlink() {
  289. return new \moodle_url(
  290. // Posts are viewed on the topic.
  291. '/mod/forum/discuss.php', array(
  292. // Within a discussion.
  293. 'd' => $this->discussion->id,
  294. )
  295. );
  296. }
  297. /**
  298. * Get the link to the current discussion.
  299. *
  300. * @return string
  301. */
  302. public function get_discussionlink() {
  303. $link = $this->_get_discussionlink();
  304. return $link->out(false);
  305. }
  306. /**
  307. * Get the link to the current post, including post anchor.
  308. *
  309. * @return string
  310. */
  311. public function get_permalink() {
  312. $link = $this->_get_discussionlink();
  313. $link->set_anchor($this->get_postanchor());
  314. return $link->out(false);
  315. }
  316. /**
  317. * Get the link to the parent post.
  318. *
  319. * @return string
  320. */
  321. public function get_parentpostlink() {
  322. $link = $this->_get_discussionlink();
  323. $link->param('parent', $this->post->parent);
  324. return $link->out(false);
  325. }
  326. /**
  327. * Get the link to the author's profile page.
  328. *
  329. * @return string
  330. */
  331. public function get_authorlink() {
  332. $link = new \moodle_url(
  333. '/user/view.php', array(
  334. 'id' => $this->post->userid,
  335. 'course' => $this->course->id,
  336. )
  337. );
  338. return $link->out(false);
  339. }
  340. /**
  341. * Get the link to unsubscribe from the forum.
  342. *
  343. * @return string
  344. */
  345. public function get_unsubscribeforumlink() {
  346. if (!\mod_forum\subscriptions::is_subscribable($this->forum)) {
  347. return null;
  348. }
  349. $link = new \moodle_url(
  350. '/mod/forum/subscribe.php', array(
  351. 'id' => $this->forum->id,
  352. )
  353. );
  354. return $link->out(false);
  355. }
  356. /**
  357. * Get the link to unsubscribe from the discussion.
  358. *
  359. * @return string
  360. */
  361. public function get_unsubscribediscussionlink() {
  362. if (!\mod_forum\subscriptions::is_subscribable($this->forum)) {
  363. return null;
  364. }
  365. $link = new \moodle_url(
  366. '/mod/forum/subscribe.php', array(
  367. 'id' => $this->forum->id,
  368. 'd' => $this->discussion->id,
  369. )
  370. );
  371. return $link->out(false);
  372. }
  373. /**
  374. * Get the link to reply to the current post.
  375. *
  376. * @return string
  377. */
  378. public function get_replylink() {
  379. return new \moodle_url(
  380. '/mod/forum/post.php', array(
  381. 'reply' => $this->post->id,
  382. )
  383. );
  384. }
  385. /**
  386. * The formatted subject for the current post.
  387. *
  388. * @return string
  389. */
  390. public function get_subject() {
  391. return format_string($this->post->subject, true);
  392. }
  393. /**
  394. * The plaintext anchor id for the current post.
  395. *
  396. * @return string
  397. */
  398. public function get_postanchor() {
  399. return 'p' . $this->post->id;
  400. }
  401. /**
  402. * ID number of the course that the forum is in.
  403. *
  404. * @return string
  405. */
  406. public function get_courseidnumber() {
  407. return s($this->course->idnumber);
  408. }
  409. /**
  410. * The full name of the course that the forum is in.
  411. *
  412. * @return string
  413. */
  414. public function get_coursefullname() {
  415. return format_string($this->course->fullname, true, array(
  416. 'context' => \context_course::instance($this->course->id),
  417. ));
  418. }
  419. /**
  420. * The name of the course that the forum is in.
  421. *
  422. * @return string
  423. */
  424. public function get_coursename() {
  425. return format_string($this->course->shortname, true, array(
  426. 'context' => \context_course::instance($this->course->id),
  427. ));
  428. }
  429. /**
  430. * The name of the forum.
  431. *
  432. * @return string
  433. */
  434. public function get_forumname() {
  435. return format_string($this->forum->name, true);
  436. }
  437. /**
  438. * The name of the current discussion.
  439. *
  440. * @return string
  441. */
  442. public function get_discussionname() {
  443. return format_string($this->discussion->name, true);
  444. }
  445. /**
  446. * Whether to show the discussion name.
  447. * If the forum name matches the discussion name, the discussion name
  448. * is not typically displayed.
  449. *
  450. * @return boolean
  451. */
  452. public function get_showdiscussionname() {
  453. return ($this->forum->name !== $this->discussion->name);
  454. }
  455. /**
  456. * The fullname of the post author.
  457. *
  458. * @return string
  459. */
  460. public function get_author_fullname() {
  461. return fullname($this->author, $this->viewfullnames);
  462. }
  463. /**
  464. * The recipient of the post.
  465. *
  466. * @return string
  467. */
  468. protected function get_postto() {
  469. global $USER;
  470. if (null === $this->userto) {
  471. return $USER;
  472. }
  473. return $this->userto;
  474. }
  475. /**
  476. * The date of the post, formatted according to the postto user's
  477. * preferences.
  478. *
  479. * @return string.
  480. */
  481. public function get_postdate() {
  482. global $CFG;
  483. $postmodified = $this->post->modified;
  484. if (!empty($CFG->forum_enabletimedposts) && ($this->discussion->timestart > $postmodified)) {
  485. $postmodified = $this->discussion->timestart;
  486. }
  487. return userdate($postmodified, "", \core_date::get_user_timezone($this->get_postto()));
  488. }
  489. /**
  490. * The HTML for the author's user picture.
  491. *
  492. * @param \renderer_base $renderer
  493. * @return string
  494. */
  495. public function get_author_picture(\renderer_base $renderer) {
  496. return $renderer->user_picture($this->author, array('courseid' => $this->course->id));
  497. }
  498. /**
  499. * The HTML for a group picture.
  500. *
  501. * @param \renderer_base $renderer
  502. * @return string
  503. */
  504. public function get_group_picture(\renderer_base $renderer) {
  505. if (isset($this->userfrom->groups)) {
  506. $groups = $this->userfrom->groups[$this->forum->id];
  507. } else {
  508. $groups = groups_get_all_groups($this->course->id, $this->author->id, $this->cm->groupingid);
  509. }
  510. if ($this->get_is_firstpost()) {
  511. return print_group_picture($groups, $this->course->id, false, true, true, true);
  512. }
  513. }
  514. }