1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Libraries;
7
8use App\Libraries\BeatmapsetDiscussion\Review;
9use App\Models\Beatmap;
10use App\Models\BeatmapDiscussion;
11use App\Models\Beatmapset;
12use App\Models\User;
13use App\Traits\Memoizes;
14use App\Transformers\BeatmapDiscussionTransformer;
15use App\Transformers\BeatmapsetTransformer;
16use App\Transformers\BeatmapTransformer;
17use App\Transformers\UserCompactTransformer;
18use Illuminate\Pagination\Paginator;
19
20class BeatmapsetDiscussionsBundle extends BeatmapsetDiscussionsBundleBase
21{
22 use Memoizes;
23
24 private const DISCUSSION_WITHS = ['beatmapDiscussionVotes', 'beatmap', 'beatmapset', 'startingPost'];
25
26 private $searchParams;
27
28 public function getData()
29 {
30 return $this->getDiscussions();
31 }
32
33 public function getSearchParams()
34 {
35 return $this->searchParams;
36 }
37
38 public function toArray()
39 {
40 static $discussionIncludes = ['starting_post', 'current_user_attributes'];
41
42 return array_merge([
43 'beatmaps' => json_collection($this->getBeatmaps(), new BeatmapTransformer()),
44 'beatmapsets' => json_collection($this->getBeatmapsets(), new BeatmapsetTransformer()),
45 'discussions' => json_collection($this->getDiscussions(), new BeatmapDiscussionTransformer(), $discussionIncludes),
46 'included_discussions' => json_collection($this->getRelatedDiscussions(), new BeatmapDiscussionTransformer(), $discussionIncludes),
47 'reviews_config' => Review::config(),
48 'users' => json_collection($this->getUsers(), new UserCompactTransformer(), ['groups']),
49 ], cursor_for_response($this->getCursor()));
50 }
51
52 private function getBeatmaps()
53 {
54 return $this->memoize(__FUNCTION__, function () {
55 // using all beatmaps of the beatmapsets for the beatmap selector when editing.
56 $beatmapsetIds = $this->getBeatmapsets()->pluck('beatmapset_id');
57
58 return Beatmap::withTrashed()->whereIn('beatmapset_id', $beatmapsetIds)->get();
59 });
60 }
61
62 private function getBeatmapsets()
63 {
64 return $this->memoize(__FUNCTION__, function () {
65 $beatmapsetIds = $this->getDiscussions()->pluck('beatmapset_id')->unique()->values();
66
67 // BeatmapDiscussion::beatmapset() includes trashed.
68 return Beatmapset::withTrashed()->whereIn('beatmapset_id', $beatmapsetIds)->get();
69 });
70 }
71
72 private function getDiscussions()
73 {
74 return $this->memoize(__FUNCTION__, function () {
75 ['query' => $query, 'params' => $this->searchParams] = BeatmapDiscussion::search($this->params);
76
77 $discussions = $query->with(static::DISCUSSION_WITHS)->limit($this->searchParams['limit'] + 1)->get();
78
79 $this->paginator = new Paginator(
80 $discussions,
81 $this->searchParams['limit'],
82 $this->searchParams['page'],
83 [
84 'path' => Paginator::resolveCurrentPath(),
85 'query' => $this->searchParams, // unfortunately getting query from Paginator is not public.
86 ]
87 );
88
89 return $this->paginator->getCollection();
90 });
91 }
92
93 private function getRelatedDiscussions()
94 {
95 return $this->memoize(__FUNCTION__, function () {
96 return BeatmapDiscussion::whereIn('parent_id', $this->getDiscussions()->pluck('id'))->with(static::DISCUSSION_WITHS)->get();
97 });
98 }
99
100 private function getUsers()
101 {
102 return $this->memoize(__FUNCTION__, function () {
103 $discussions = $this->getDiscussions();
104
105 $allDiscussions = $discussions->merge($this->getRelatedDiscussions());
106 $userIds = $allDiscussions->pluck('user_id')->merge($allDiscussions->pluck('startingPost.last_editor_id'))->unique()->values();
107
108 $users = User::whereIn('user_id', $userIds)->with('userGroups');
109
110 if (!$this->isModerator) {
111 $users->default();
112 }
113
114 return $users->get();
115 });
116 }
117}