<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Discussion list renderer.
*
* @package mod_forum
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_forum\local\renderers;
defined('MOODLE_INTERNAL') || die();
use mod_forum\grades\forum_gradeitem;
use mod_forum\local\entities\forum as forum_entity;
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
use mod_forum\local\factories\exporter as exporter_factory;
use mod_forum\local\factories\vault as vault_factory;
use mod_forum\local\factories\url as url_factory;
use mod_forum\local\managers\capability as capability_manager;
use mod_forum\local\vaults\discussion_list as discussion_list_vault;
use renderer_base;
use stdClass;
use core\output\notification;
> use mod_forum\local\data_mappers\legacy\forum;
use mod_forum\local\factories\builder as builder_factory;
require_once($CFG->dirroot . '/mod/forum/lib.php');
/**
* The discussion list renderer.
*
* @package mod_forum
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class discussion_list {
/** @var forum_entity The forum being rendered */
private $forum;
/** @var stdClass The DB record for the forum being rendered */
private $forumrecord;
/** @var renderer_base The renderer used to render the view */
private $renderer;
/** @var legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory */
private $legacydatamapperfactory;
/** @var exporter_factory $exporterfactory Exporter factory */
private $exporterfactory;
/** @var vault_factory $vaultfactory Vault factory */
private $vaultfactory;
/** @var capability_manager $capabilitymanager Capability manager */
private $capabilitymanager;
/** @var url_factory $urlfactory URL factory */
private $urlfactory;
/** @var array $notifications List of notification HTML */
private $notifications;
/** @var builder_factory $builderfactory Builder factory */
private $builderfactory;
/** @var callable $postprocessfortemplate Function to process exported posts before template rendering */
private $postprocessfortemplate;
/** @var string $template The template to use when displaying */
private $template;
/** @var gradeitem The gradeitem instance associated with this forum */
private $forumgradeitem;
/**
* Constructor for a new discussion list renderer.
*
* @param forum_entity $forum The forum entity to be rendered
* @param renderer_base $renderer The renderer used to render the view
* @param legacy_data_mapper_factory $legacydatamapperfactory The factory used to fetch a legacy record
* @param exporter_factory $exporterfactory The factory used to fetch exporter instances
* @param vault_factory $vaultfactory The factory used to fetch the vault instances
* @param builder_factory $builderfactory The factory used to fetch the builder instances
* @param capability_manager $capabilitymanager The managed used to check capabilities on the forum
* @param url_factory $urlfactory The factory used to create URLs in the forum
* @param string $template
* @param notification[] $notifications A list of any notifications to be displayed within the page
* @param callable|null $postprocessfortemplate Callback function to process discussion lists for templates
*/
public function __construct(
forum_entity $forum,
renderer_base $renderer,
legacy_data_mapper_factory $legacydatamapperfactory,
exporter_factory $exporterfactory,
vault_factory $vaultfactory,
builder_factory $builderfactory,
capability_manager $capabilitymanager,
url_factory $urlfactory,
forum_gradeitem $forumgradeitem,
string $template,
array $notifications = [],
callable $postprocessfortemplate = null
) {
$this->forum = $forum;
$this->renderer = $renderer;
$this->legacydatamapperfactory = $legacydatamapperfactory;
$this->exporterfactory = $exporterfactory;
$this->vaultfactory = $vaultfactory;
$this->builderfactory = $builderfactory;
$this->capabilitymanager = $capabilitymanager;
$this->urlfactory = $urlfactory;
$this->notifications = $notifications;
$this->postprocessfortemplate = $postprocessfortemplate;
$this->template = $template;
$this->forumgradeitem = $forumgradeitem;
$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
$this->forumrecord = $forumdatamapper->to_legacy_object($forum);
}
/**
* Render for the specified user.
*
* @param stdClass $user The user to render for
* @param cm_info $cm The course module info for this discussion list
* @param int $groupid The group to render
* @param int $sortorder The sort order to use when selecting the discussions in the list
* @param int $pageno The zero-indexed page number to use
* @param int $pagesize The number of discussions to show on the page
* @param int $displaymode The discussion display mode
> * @param bool $enablediscussioncreation To show the discussion button.
* @return string The rendered content for display
*/
public function render(
stdClass $user,
\cm_info $cm,
?int $groupid,
?int $sortorder,
?int $pageno,
?int $pagesize,
< int $displaymode = null
> int $displaymode = null,
> bool $enablediscussioncreation = true
) : string {
global $PAGE;
$forum = $this->forum;
$course = $forum->get_course_record();
$forumexporter = $this->exporterfactory->get_forum_exporter(
$user,
$this->forum,
$groupid
);
$pagesize = $this->get_page_size($pagesize);
$pageno = $this->get_page_number($pageno);
// Count all forum discussion posts.
$alldiscussionscount = mod_forum_count_all_discussions($forum, $user, $groupid);
// Get all forum discussion summaries.
$discussions = mod_forum_get_discussion_summaries($forum, $user, $groupid, $sortorder, $pageno, $pagesize);
$capabilitymanager = $this->capabilitymanager;
$hasanyactions = false;
$hasanyactions = $hasanyactions || $capabilitymanager->can_favourite_discussion($user);
$hasanyactions = $hasanyactions || $capabilitymanager->can_pin_discussions($user);
$hasanyactions = $hasanyactions || $capabilitymanager->can_manage_forum($user);
$forumview = [
'forum' => (array) $forumexporter->export($this->renderer),
'contextid' => $forum->get_context()->id,
'cmid' => $cm->id,
'groupid' => $groupid,
'name' => format_string($forum->get_name()),
'courseid' => $course->id,
'coursename' => format_string($course->shortname),
'experimentaldisplaymode' => $displaymode == FORUM_MODE_NESTED_V2,
'gradingcomponent' => $this->forumgradeitem->get_grading_component_name(),
'gradingcomponentsubtype' => $this->forumgradeitem->get_grading_component_subtype(),
'sendstudentnotifications' => $forum->should_notify_students_default_when_grade_for_forum(),
> 'gradeonlyactiveusers' => $this->forumgradeitem->should_grade_only_active_users(),
'hasanyactions' => $hasanyactions,
'groupchangemenu' => groups_print_activity_menu(
$cm,
$this->urlfactory->get_forum_view_url_from_forum($forum),
true
),
'hasmore' => ($alldiscussionscount > $pagesize),
'notifications' => $this->get_notifications($user, $groupid),
'settings' => [
'excludetext' => true,
'togglemoreicon' => true,
'excludesubscription' => true
],
'totaldiscussioncount' => $alldiscussionscount,
'userid' => $user->id,
< 'visiblediscussioncount' => count($discussions)
> 'visiblediscussioncount' => count($discussions),
> 'enablediscussioncreation' => $enablediscussioncreation,
];
if ($forumview['forum']['capabilities']['create']) {
$forumview['newdiscussionhtml'] = $this->get_discussion_form($user, $cm, $groupid);
}
if (!$discussions) {
return $this->renderer->render_from_template($this->template, $forumview);
}
if ($this->postprocessfortemplate !== null) {
// We've got some post processing to do!
$exportedposts = ($this->postprocessfortemplate) ($discussions, $user, $forum);
}
$baseurl = new \moodle_url($PAGE->url, array('o' => $sortorder));
$forumview = array_merge(
$forumview,
[
'pagination' => $this->renderer->render(new \paging_bar($alldiscussionscount, $pageno, $pagesize, $baseurl, 'p')),
],
$exportedposts
);
$firstdiscussion = reset($discussions);
$forumview['firstgradeduserid'] = $firstdiscussion->get_latest_post_author()->get_id();
return $this->renderer->render_from_template($this->template, $forumview);
}
/**
> * Add new discussion button to the action bar for tertiary nav.
* Get the mod_forum_post_form. This is the default boiler plate from mod_forum/post_form.php with the inpage flag caveat
> *
*
> * @param stdClass $user The user object.
* @param stdClass $user The user the form is being generated for
> * @param int|null $groupid The group id.
* @param \cm_info $cm
> * @return string rendered HTML string
* @param int $groupid The groupid if any
> */
*
> public function render_new_discussion(stdClass $user, ?int $groupid): string {
* @return string The rendered html
> $forumexporter = $this->exporterfactory->get_forum_exporter(
*/
> $user,
private function get_discussion_form(stdClass $user, \cm_info $cm, ?int $groupid) {
> $this->forum,
$forum = $this->forum;
> $groupid
$forumrecord = $this->legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum);
> );
$modcontext = \context_module::instance($cm->id);
>
$coursecontext = \context_course::instance($forum->get_course_id());
> $forumview = [
$post = (object) [
> 'forum' => (array) $forumexporter->export($this->renderer),
'course' => $forum->get_course_id(),
> ];
'forum' => $forum->get_id(),
>
'discussion' => 0, // Ie discussion # not defined yet.
> return $this->renderer->render_from_template('mod_forum/forum_new_discussion_actionbar', $forumview);
'parent' => 0,
> }
'subject' => '',
>
'userid' => $user->id,
> /**
'message' => '',
'messageformat' => editors_get_preferred_format(),
'messagetrust' => 0,
'groupid' => $groupid,
];
$thresholdwarning = forum_check_throttling($forumrecord, $cm);
$formparams = array(
'course' => $forum->get_course_record(),
'cm' => $cm,
'coursecontext' => $coursecontext,
'modcontext' => $modcontext,
'forum' => $forumrecord,
'post' => $post,
'subscribe' => \mod_forum\subscriptions::is_subscribed($user->id, $forumrecord,
null, $cm),
'thresholdwarning' => $thresholdwarning,
'inpagereply' => true,
'edit' => 0
);
$posturl = new \moodle_url('/mod/forum/post.php');
$mformpost = new \mod_forum_post_form($posturl, $formparams, 'post', '', array('id' => 'mformforum'));
$discussionsubscribe = \mod_forum\subscriptions::get_user_default_subscription($forumrecord, $coursecontext, $cm, null);
$params = array('reply' => 0, 'forum' => $forumrecord->id, 'edit' => 0) +
(isset($post->groupid) ? array('groupid' => $post->groupid) : array()) +
array(
'userid' => $post->userid,
'parent' => $post->parent,
'discussion' => $post->discussion,
'course' => $forum->get_course_id(),
'discussionsubscribe' => $discussionsubscribe
);
$mformpost->set_data($params);
return $mformpost->render();
}
/**
* Fetch the page size to use when displaying the page.
*
* @param int $pagesize The number of discussions to show on the page
* @return int The normalised page size
*/
private function get_page_size(?int $pagesize) : int {
if (null === $pagesize || $pagesize <= 0) {
$pagesize = discussion_list_vault::PAGESIZE_DEFAULT;
}
return $pagesize;
}
/**
* Fetch the current page number (zero-indexed).
*
* @param int $pageno The zero-indexed page number to use
* @return int The normalised page number
*/
private function get_page_number(?int $pageno) : int {
if (null === $pageno || $pageno < 0) {
$pageno = 0;
}
return $pageno;
}
/**
* Get the list of notification for display.
*
* @param stdClass $user The viewing user
* @param int|null $groupid The forum's group id
* @return array
*/
private function get_notifications(stdClass $user, ?int $groupid) : array {
$notifications = $this->notifications;
$forum = $this->forum;
< $renderer = $this->renderer;
$capabilitymanager = $this->capabilitymanager;
if ($forum->is_cutoff_date_reached()) {
$notifications[] = (new notification(
get_string('cutoffdatereached', 'forum'),
notification::NOTIFY_INFO
))->set_show_closebutton();
< } else if ($forum->is_due_date_reached()) {
< $notifications[] = (new notification(
< get_string('thisforumisdue', 'forum', userdate($forum->get_due_date())),
< notification::NOTIFY_INFO
< ))->set_show_closebutton();
< } else if ($forum->has_due_date()) {
< $notifications[] = (new notification(
< get_string('thisforumhasduedate', 'forum', userdate($forum->get_due_date())),
< notification::NOTIFY_INFO
< ))->set_show_closebutton();
}
if ($forum->has_blocking_enabled()) {
$notifications[] = (new notification(
get_string('thisforumisthrottled', 'forum', [
'blockafter' => $forum->get_block_after(),
'blockperiod' => get_string('secondstotime' . $forum->get_block_period())
< ])
> ]),
> notification::NOTIFY_INFO
))->set_show_closebutton();
}
if ($forum->is_in_group_mode() && !$capabilitymanager->can_access_all_groups($user)) {
if ($groupid === null) {
if (!$capabilitymanager->can_post_to_my_groups($user)) {
$notifications[] = (new notification(
get_string('cannotadddiscussiongroup', 'mod_forum'),
\core\output\notification::NOTIFY_WARNING
))->set_show_closebutton();
} else {
$notifications[] = (new notification(
get_string('cannotadddiscussionall', 'mod_forum'),
\core\output\notification::NOTIFY_WARNING
))->set_show_closebutton();
}
} else if (!$capabilitymanager->can_access_group($user, $groupid)) {
$notifications[] = (new notification(
get_string('cannotadddiscussion', 'mod_forum'),
\core\output\notification::NOTIFY_WARNING
))->set_show_closebutton();
}
}
if ('qanda' === $forum->get_type() && !$capabilitymanager->can_manage_forum($user)) {
$notifications[] = (new notification(
get_string('qandanotify', 'forum'),
notification::NOTIFY_INFO
< ))->set_show_closebutton();
> ))->set_show_closebutton()->set_extra_classes(['mt-3']);
}
if ('eachuser' === $forum->get_type()) {
$notifications[] = (new notification(
get_string('allowsdiscussions', 'forum'),
notification::NOTIFY_INFO)
)->set_show_closebutton();
}
return array_map(function($notification) {
return $notification->export_for_template($this->renderer);
}, $notifications);
}
}