Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
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
}