1 |
efrain |
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 |
* Exported discussion summaries builder class.
|
|
|
19 |
*
|
|
|
20 |
* @package mod_forum
|
|
|
21 |
* @copyright 2019 Mihail Geshoski <mihail@moodle.com>
|
|
|
22 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
23 |
*/
|
|
|
24 |
|
|
|
25 |
namespace mod_forum\local\builders;
|
|
|
26 |
|
|
|
27 |
defined('MOODLE_INTERNAL') || die();
|
|
|
28 |
|
|
|
29 |
use mod_forum\local\entities\discussion as discussion_entity;
|
|
|
30 |
use mod_forum\local\entities\forum as forum_entity;
|
|
|
31 |
use mod_forum\local\entities\post as post_entity;
|
|
|
32 |
use mod_forum\local\factories\legacy_data_mapper as legacy_data_mapper_factory;
|
|
|
33 |
use mod_forum\local\factories\exporter as exporter_factory;
|
|
|
34 |
use mod_forum\local\factories\vault as vault_factory;
|
|
|
35 |
use mod_forum\local\factories\manager as manager_factory;
|
|
|
36 |
use rating_manager;
|
|
|
37 |
use renderer_base;
|
|
|
38 |
use stdClass;
|
|
|
39 |
|
|
|
40 |
/**
|
|
|
41 |
* Exported discussion summaries builder class.
|
|
|
42 |
*
|
|
|
43 |
* This class is an implementation of the builder pattern (loosely). It is responsible
|
|
|
44 |
* for taking a set of related forums, discussions, and posts and generate the exported
|
|
|
45 |
* version of the discussion summaries.
|
|
|
46 |
*
|
|
|
47 |
* It encapsulates the complexity involved with exporting discussions summaries. All of the relevant
|
|
|
48 |
* additional resources will be loaded by this class in order to ensure the exporting
|
|
|
49 |
* process can happen.
|
|
|
50 |
*
|
|
|
51 |
* See this doc for more information on the builder pattern:
|
|
|
52 |
* https://designpatternsphp.readthedocs.io/en/latest/Creational/Builder/README.html
|
|
|
53 |
*
|
|
|
54 |
* @package mod_forum
|
|
|
55 |
* @copyright 2019 Mihail Geshoski <mihail@moodle.com>
|
|
|
56 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
57 |
*/
|
|
|
58 |
class exported_discussion_summaries {
|
|
|
59 |
/** @var renderer_base $renderer Core renderer */
|
|
|
60 |
private $renderer;
|
|
|
61 |
|
|
|
62 |
/** @var legacy_data_mapper_factory $legacydatamapperfactory Data mapper factory */
|
|
|
63 |
private $legacydatamapperfactory;
|
|
|
64 |
|
|
|
65 |
/** @var exporter_factory $exporterfactory Exporter factory */
|
|
|
66 |
private $exporterfactory;
|
|
|
67 |
|
|
|
68 |
/** @var vault_factory $vaultfactory Vault factory */
|
|
|
69 |
private $vaultfactory;
|
|
|
70 |
|
|
|
71 |
/** @var manager_factory $managerfactory Manager factory */
|
|
|
72 |
private $managerfactory;
|
|
|
73 |
|
|
|
74 |
/** @var rating_manager $ratingmanager Rating manager */
|
|
|
75 |
private $ratingmanager;
|
|
|
76 |
|
|
|
77 |
/**
|
|
|
78 |
* Constructor.
|
|
|
79 |
*
|
|
|
80 |
* @param renderer_base $renderer Core renderer
|
|
|
81 |
* @param legacy_data_mapper_factory $legacydatamapperfactory Legacy data mapper factory
|
|
|
82 |
* @param exporter_factory $exporterfactory Exporter factory
|
|
|
83 |
* @param vault_factory $vaultfactory Vault factory
|
|
|
84 |
* @param manager_factory $managerfactory Manager factory
|
|
|
85 |
*/
|
|
|
86 |
public function __construct(
|
|
|
87 |
renderer_base $renderer,
|
|
|
88 |
legacy_data_mapper_factory $legacydatamapperfactory,
|
|
|
89 |
exporter_factory $exporterfactory,
|
|
|
90 |
vault_factory $vaultfactory,
|
|
|
91 |
manager_factory $managerfactory
|
|
|
92 |
) {
|
|
|
93 |
$this->renderer = $renderer;
|
|
|
94 |
$this->legacydatamapperfactory = $legacydatamapperfactory;
|
|
|
95 |
$this->exporterfactory = $exporterfactory;
|
|
|
96 |
$this->vaultfactory = $vaultfactory;
|
|
|
97 |
$this->managerfactory = $managerfactory;
|
|
|
98 |
$this->ratingmanager = $managerfactory->get_rating_manager();
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
/**
|
|
|
102 |
* Build the exported discussion summaries for a given set of discussions.
|
|
|
103 |
*
|
|
|
104 |
* This will typically be used for a list of discussions in the same forum.
|
|
|
105 |
*
|
|
|
106 |
* @param stdClass $user The user to export the posts for.
|
|
|
107 |
* @param forum_entity $forum The forum that each of the $discussions belong to
|
|
|
108 |
* @param discussion_summary_entity[] $discussions A list of all discussion summaries to export
|
|
|
109 |
* @return stdClass[] List of exported posts in the same order as the $posts array.
|
|
|
110 |
*/
|
|
|
111 |
public function build(
|
|
|
112 |
stdClass $user,
|
|
|
113 |
forum_entity $forum,
|
|
|
114 |
array $discussions
|
|
|
115 |
): array {
|
|
|
116 |
$capabilitymanager = $this->managerfactory->get_capability_manager($forum);
|
|
|
117 |
$canseeanyprivatereply = $capabilitymanager->can_view_any_private_reply($user);
|
|
|
118 |
|
|
|
119 |
$discussionids = array_keys($discussions);
|
|
|
120 |
|
|
|
121 |
$postvault = $this->vaultfactory->get_post_vault();
|
|
|
122 |
$posts = $postvault->get_from_discussion_ids($user, $discussionids, $canseeanyprivatereply);
|
|
|
123 |
$groupsbyid = $this->get_groups_available_in_forum($forum);
|
|
|
124 |
$groupsbyauthorid = $this->get_author_groups_from_posts($posts, $forum);
|
|
|
125 |
|
|
|
126 |
$replycounts = $postvault->get_reply_count_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
|
|
|
127 |
$latestposts = $postvault->get_latest_posts_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
|
|
|
128 |
$latestauthors = $this->get_latest_posts_authors($latestposts);
|
|
|
129 |
$latestpostsids = array_map(function($post) {
|
|
|
130 |
return $post->get_id();
|
|
|
131 |
}, $latestposts);
|
|
|
132 |
|
|
|
133 |
$postauthorids = array_unique(array_reduce($discussions, function($carry, $summary) use ($latestposts){
|
|
|
134 |
$firstpostauthorid = $summary->get_first_post_author()->get_id();
|
|
|
135 |
$discussion = $summary->get_discussion();
|
|
|
136 |
$lastpostauthorid = $latestposts[$discussion->get_id()]->get_author_id();
|
|
|
137 |
return array_merge($carry, [$firstpostauthorid, $lastpostauthorid]);
|
|
|
138 |
}, []));
|
|
|
139 |
$postauthorcontextids = $this->get_author_context_ids($postauthorids);
|
|
|
140 |
|
|
|
141 |
$unreadcounts = [];
|
|
|
142 |
$favourites = $this->get_favourites($user);
|
|
|
143 |
$forumdatamapper = $this->legacydatamapperfactory->get_forum_data_mapper();
|
|
|
144 |
$forumrecord = $forumdatamapper->to_legacy_object($forum);
|
|
|
145 |
|
|
|
146 |
if (forum_tp_can_track_forums($forumrecord)) {
|
|
|
147 |
$unreadcounts = $postvault->get_unread_count_for_discussion_ids($user, $discussionids, $canseeanyprivatereply);
|
|
|
148 |
}
|
|
|
149 |
|
|
|
150 |
$summaryexporter = $this->exporterfactory->get_discussion_summaries_exporter(
|
|
|
151 |
$user,
|
|
|
152 |
$forum,
|
|
|
153 |
$discussions,
|
|
|
154 |
$groupsbyid,
|
|
|
155 |
$groupsbyauthorid,
|
|
|
156 |
$replycounts,
|
|
|
157 |
$unreadcounts,
|
|
|
158 |
$latestpostsids,
|
|
|
159 |
$postauthorcontextids,
|
|
|
160 |
$favourites,
|
|
|
161 |
$latestauthors
|
|
|
162 |
);
|
|
|
163 |
|
|
|
164 |
$exportedposts = (array) $summaryexporter->export($this->renderer);
|
|
|
165 |
$firstposts = $postvault->get_first_post_for_discussion_ids($discussionids);
|
|
|
166 |
|
|
|
167 |
array_walk($exportedposts['summaries'], function($summary) use ($firstposts, $latestposts) {
|
|
|
168 |
$summary->discussion->times['created'] = (int) $firstposts[$summary->discussion->firstpostid]->get_time_created();
|
|
|
169 |
$summary->discussion->times['modified'] = (int) $latestposts[$summary->discussion->id]->get_time_created();
|
|
|
170 |
});
|
|
|
171 |
|
|
|
172 |
// Pass the current, preferred sort order for the discussions list.
|
|
|
173 |
$discussionlistvault = $this->vaultfactory->get_discussions_in_forum_vault();
|
|
|
174 |
$sortorder = get_user_preferences('forum_discussionlistsortorder',
|
|
|
175 |
$discussionlistvault::SORTORDER_LASTPOST_DESC);
|
|
|
176 |
|
|
|
177 |
$sortoptions = array(
|
|
|
178 |
'islastpostdesc' => $sortorder == $discussionlistvault::SORTORDER_LASTPOST_DESC,
|
|
|
179 |
'islastpostasc' => $sortorder == $discussionlistvault::SORTORDER_LASTPOST_ASC,
|
|
|
180 |
'isrepliesdesc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_DESC,
|
|
|
181 |
'isrepliesasc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_ASC,
|
|
|
182 |
'iscreateddesc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_DESC,
|
|
|
183 |
'iscreatedasc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_ASC,
|
|
|
184 |
'isdiscussiondesc' => $sortorder == $discussionlistvault::SORTORDER_DISCUSSION_DESC,
|
|
|
185 |
'isdiscussionasc' => $sortorder == $discussionlistvault::SORTORDER_DISCUSSION_ASC,
|
|
|
186 |
'isstarterdesc' => $sortorder == $discussionlistvault::SORTORDER_STARTER_DESC,
|
|
|
187 |
'isstarterasc' => $sortorder == $discussionlistvault::SORTORDER_STARTER_ASC,
|
|
|
188 |
'isgroupdesc' => $sortorder == $discussionlistvault::SORTORDER_GROUP_DESC,
|
|
|
189 |
'isgroupasc' => $sortorder == $discussionlistvault::SORTORDER_GROUP_ASC,
|
|
|
190 |
);
|
|
|
191 |
|
|
|
192 |
$exportedposts['state']['sortorder'] = $sortoptions;
|
|
|
193 |
|
|
|
194 |
return $exportedposts;
|
|
|
195 |
}
|
|
|
196 |
|
|
|
197 |
/**
|
|
|
198 |
* Get a list of all favourited discussions.
|
|
|
199 |
*
|
|
|
200 |
* @param stdClass $user The user we are getting favourites for
|
|
|
201 |
* @return int[] A list of favourited itemids
|
|
|
202 |
*/
|
|
|
203 |
private function get_favourites(stdClass $user): array {
|
|
|
204 |
$ids = [];
|
|
|
205 |
|
|
|
206 |
if (isloggedin()) {
|
|
|
207 |
$usercontext = \context_user::instance($user->id);
|
|
|
208 |
$ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext);
|
|
|
209 |
$favourites = $ufservice->find_favourites_by_type('mod_forum', 'discussions');
|
|
|
210 |
foreach ($favourites as $favourite) {
|
|
|
211 |
$ids[] = $favourite->itemid;
|
|
|
212 |
}
|
|
|
213 |
}
|
|
|
214 |
|
|
|
215 |
return $ids;
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
/**
|
|
|
219 |
* Returns a mapped array of discussionid to the authors of the latest post
|
|
|
220 |
*
|
|
|
221 |
* @param array $latestposts Mapped array of discussion to latest posts.
|
|
|
222 |
* @return array Array of authors mapped to the discussion
|
|
|
223 |
*/
|
|
|
224 |
private function get_latest_posts_authors($latestposts) {
|
|
|
225 |
$authors = $this->vaultfactory->get_author_vault()->get_authors_for_posts($latestposts);
|
|
|
226 |
|
|
|
227 |
$mappedauthors = array_reduce($latestposts, function($carry, $item) use ($authors) {
|
|
|
228 |
$carry[$item->get_discussion_id()] = $authors[$item->get_author_id()];
|
|
|
229 |
|
|
|
230 |
return $carry;
|
|
|
231 |
}, []);
|
|
|
232 |
return $mappedauthors;
|
|
|
233 |
}
|
|
|
234 |
|
|
|
235 |
/**
|
|
|
236 |
* Get the groups details for all groups available to the forum.
|
|
|
237 |
* @param forum_entity $forum The forum entity
|
|
|
238 |
* @return stdClass[]
|
|
|
239 |
*/
|
|
|
240 |
private function get_groups_available_in_forum($forum): array {
|
|
|
241 |
$course = $forum->get_course_record();
|
|
|
242 |
$coursemodule = $forum->get_course_module_record();
|
|
|
243 |
|
|
|
244 |
return groups_get_all_groups($course->id, 0, $coursemodule->groupingid);
|
|
|
245 |
}
|
|
|
246 |
|
|
|
247 |
/**
|
|
|
248 |
* Get the author's groups for a list of posts.
|
|
|
249 |
*
|
|
|
250 |
* @param post_entity[] $posts The list of posts
|
|
|
251 |
* @param forum_entity $forum The forum entity
|
|
|
252 |
* @return array Author groups indexed by author id
|
|
|
253 |
*/
|
|
|
254 |
private function get_author_groups_from_posts(array $posts, $forum): array {
|
|
|
255 |
$course = $forum->get_course_record();
|
|
|
256 |
$coursemodule = $forum->get_course_module_record();
|
|
|
257 |
$authorids = array_reduce($posts, function($carry, $post) {
|
|
|
258 |
$carry[$post->get_author_id()] = true;
|
|
|
259 |
return $carry;
|
|
|
260 |
}, []);
|
|
|
261 |
$authorgroups = groups_get_all_groups($course->id, array_keys($authorids), $coursemodule->groupingid,
|
|
|
262 |
'g.*, gm.id, gm.groupid, gm.userid');
|
|
|
263 |
|
|
|
264 |
$authorgroups = array_reduce($authorgroups, function($carry, $group) {
|
|
|
265 |
// Clean up data returned from groups_get_all_groups.
|
|
|
266 |
$userid = $group->userid;
|
|
|
267 |
$groupid = $group->groupid;
|
|
|
268 |
|
|
|
269 |
unset($group->userid);
|
|
|
270 |
unset($group->groupid);
|
|
|
271 |
$group->id = $groupid;
|
|
|
272 |
|
|
|
273 |
if (!isset($carry[$userid])) {
|
|
|
274 |
$carry[$userid] = [$group];
|
|
|
275 |
} else {
|
|
|
276 |
$carry[$userid][] = $group;
|
|
|
277 |
}
|
|
|
278 |
|
|
|
279 |
return $carry;
|
|
|
280 |
}, []);
|
|
|
281 |
|
|
|
282 |
foreach (array_diff(array_keys($authorids), array_keys($authorgroups)) as $authorid) {
|
|
|
283 |
$authorgroups[$authorid] = [];
|
|
|
284 |
}
|
|
|
285 |
|
|
|
286 |
return $authorgroups;
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
/**
|
|
|
290 |
* Get the user context ids for each of the authors.
|
|
|
291 |
*
|
|
|
292 |
* @param int[] $authorids The list of author ids to fetch context ids for.
|
|
|
293 |
* @return int[] Context ids indexed by author id
|
|
|
294 |
*/
|
|
|
295 |
private function get_author_context_ids(array $authorids): array {
|
|
|
296 |
$authorvault = $this->vaultfactory->get_author_vault();
|
|
|
297 |
return $authorvault->get_context_ids_for_author_ids($authorids);
|
|
|
298 |
}
|
|
|
299 |
}
|