TopEdits::__construct()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 6
nop 10
dl 0
loc 28
rs 9.7666
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types = 1);
4
5
namespace App\Model;
6
7
use App\Helper\AutomatedEditsHelper;
8
use App\Repository\TopEditsRepository;
9
10
/**
11
 * TopEdits returns the top-edited pages by a user.
12
 */
13
class TopEdits extends Model
14
{
15
    protected AutomatedEditsHelper $autoEditsHelper;
16
17
    /** @var string[]|Edit[] Top edits, either to a page or across namespaces. */
18
    protected array $topEdits = [];
19
20
    /** @var int Number of bytes added across all top edits. */
21
    protected int $totalAdded = 0;
22
23
    /** @var int Number of bytes removed across all top edits. */
24
    protected int $totalRemoved = 0;
25
26
    /** @var int Number of top edits marked as minor. */
27
    protected int $totalMinor = 0;
28
29
    /** @var int Number of automated top edits. */
30
    protected int $totalAutomated = 0;
31
32
    /** @var int Number of reverted top edits. */
33
    protected int $totalReverted = 0;
34
35
    /** @var int Which page of results to show. */
36
    protected int $pagination = 0;
37
38
    private const DEFAULT_LIMIT_SINGLE_NAMESPACE = 1000;
39
    private const DEFAULT_LIMIT_ALL_NAMESPACES = 20;
40
41
    /**
42
     * TopEdits constructor.
43
     * @param TopEditsRepository $repository
44
     * @param AutomatedEditsHelper $autoEditsHelper
45
     * @param Project $project
46
     * @param User $user
47
     * @param Page|null $page
48
     * @param string|int $namespace Namespace ID or 'all'.
49
     * @param int|false $start Start date as Unix timestamp.
50
     * @param int|false $end End date as Unix timestamp.
51
     * @param int|null $limit Number of rows to fetch. This defaults to DEFAULT_LIMIT_SINGLE_NAMESPACE if
52
     *   $this->namespace is a single namespace (int), and DEFAULT_LIMIT_ALL_NAMESPACES if $this->namespace is 'all'.
53
     * @param int $pagination Which page of results to show.
54
     */
55
    public function __construct(
56
        TopEditsRepository $repository,
57
        AutomatedEditsHelper $autoEditsHelper,
58
        Project $project,
59
        User $user,
60
        ?Page $page = null,
61
        $namespace = 0,
62
        $start = false,
63
        $end = false,
64
        ?int $limit = null,
65
        int $pagination = 0
66
    ) {
67
        $this->repository = $repository;
68
        $this->autoEditsHelper = $autoEditsHelper;
69
        $this->project = $project;
70
        $this->user = $user;
71
        $this->page = $page;
72
        $this->namespace = 'all' === $namespace ? 'all' : (int)$namespace;
73
        $this->start = $start;
74
        $this->end = $end;
75
        $this->pagination = $pagination;
76
77
        if (null !== $limit) {
78
            $this->limit = $limit;
79
        } else {
80
            $this->limit = 'all' === $this->namespace
81
                ? self::DEFAULT_LIMIT_ALL_NAMESPACES
82
                : self::DEFAULT_LIMIT_SINGLE_NAMESPACE;
83
        }
84
    }
85
86
    /**
87
     * Which page of results we're showing.
88
     * @return int
89
     */
90
    public function getPagination(): int
91
    {
92
        return $this->pagination;
93
    }
94
95
    /**
96
     * Get total number of bytes added.
97
     * @return int
98
     */
99
    public function getTotalAdded(): int
100
    {
101
        return $this->totalAdded;
102
    }
103
104
    /**
105
     * Get total number of bytes removed.
106
     * @return int
107
     */
108
    public function getTotalRemoved(): int
109
    {
110
        return $this->totalRemoved;
111
    }
112
113
    /**
114
     * Get total number of edits marked as minor.
115
     * @return int
116
     */
117
    public function getTotalMinor(): int
118
    {
119
        return $this->totalMinor;
120
    }
121
122
    /**
123
     * Get total number of automated edits.
124
     * @return int
125
     */
126
    public function getTotalAutomated(): int
127
    {
128
        return $this->totalAutomated;
129
    }
130
131
    /**
132
     * Get total number of edits that were reverted.
133
     * @return int
134
     */
135
    public function getTotalReverted(): int
136
    {
137
        return $this->totalReverted;
138
    }
139
140
    /**
141
     * Get the top edits data.
142
     * @return Edit[]
143
     */
144
    public function getTopEdits(): array
145
    {
146
        return $this->topEdits;
147
    }
148
149
    /**
150
     * Get the total number of top edits.
151
     * @return int
152
     */
153
    public function getNumTopEdits(): int
154
    {
155
        return count($this->topEdits);
156
    }
157
158
    /**
159
     * Get the average time between edits (in days).
160
     * @return float
161
     */
162
    public function getAtbe(): float
163
    {
164
        $firstDateTime = $this->topEdits[0]->getTimestamp();
165
        $lastDateTime = end($this->topEdits)->getTimestamp();
166
        $secs = $firstDateTime->getTimestamp() - $lastDateTime->getTimestamp();
167
        $days = $secs / (60 * 60 * 24);
168
        return $days / count($this->topEdits);
169
    }
170
171
    /**
172
     * Set the Page on the TopEdits instance.
173
     * @param Page $page
174
     */
175
    public function setPage(Page $page): void
176
    {
177
        $this->page = $page;
178
    }
179
180
    /**
181
     * Fetch and store all the data we need to show the TopEdits view.
182
     * This is the public method that should be called before using
183
     * the getter methods.
184
     */
185
    public function prepareData(): void
186
    {
187
        if (isset($this->page)) {
188
            $this->topEdits = $this->getTopEditsPage();
189
        } else {
190
            $this->topEdits = $this->getTopEditsNamespace();
191
        }
192
    }
193
194
    /**
195
     * Get the top edits by a user in the given namespace, or 'all' namespaces.
196
     * @return string[] Results keyed by namespace.
197
     */
198
    private function getTopEditsNamespace(): array
199
    {
200
        if ('all' === $this->namespace) {
201
            $pages = $this->repository->getTopEditsAllNamespaces(
0 ignored issues
show
Bug introduced by
The method getTopEditsAllNamespaces() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\TopEditsRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

201
            /** @scrutinizer ignore-call */ 
202
            $pages = $this->repository->getTopEditsAllNamespaces(
Loading history...
202
                $this->project,
203
                $this->user,
204
                $this->start,
205
                $this->end,
206
                $this->limit
207
            );
208
        } else {
209
            $pages = $this->repository->getTopEditsNamespace(
0 ignored issues
show
Bug introduced by
The method getTopEditsNamespace() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\TopEditsRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

209
            /** @scrutinizer ignore-call */ 
210
            $pages = $this->repository->getTopEditsNamespace(
Loading history...
210
                $this->project,
211
                $this->user,
212
                $this->namespace,
213
                $this->start,
214
                $this->end,
215
                $this->limit,
216
                $this->pagination
217
            );
218
        }
219
220
        return $this->formatTopPagesNamespace($pages);
221
    }
222
223
    /**
224
     * Get the total number of pages edited in the namespace.
225
     * @return int|null
226
     */
227
    public function getNumPagesNamespace(): ?int
228
    {
229
        if ('all' === $this->namespace) {
230
            return null;
231
        }
232
233
        return (int)$this->repository->countEditsNamespace(
0 ignored issues
show
Bug introduced by
The method countEditsNamespace() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\TopEditsRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

233
        return (int)$this->repository->/** @scrutinizer ignore-call */ countEditsNamespace(
Loading history...
234
            $this->project,
235
            $this->user,
236
            $this->namespace,
237
            $this->start,
238
            $this->end
239
        );
240
    }
241
242
    /**
243
     * Get the top edits to the given page.
244
     * @return Edit[]
245
     */
246
    private function getTopEditsPage(): array
247
    {
248
        $revs = $this->repository->getTopEditsPage(
0 ignored issues
show
Bug introduced by
The method getTopEditsPage() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\TopEditsRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

248
        /** @scrutinizer ignore-call */ 
249
        $revs = $this->repository->getTopEditsPage(
Loading history...
249
            $this->page,
250
            $this->user,
251
            $this->start,
252
            $this->end
253
        );
254
255
        return $this->formatTopEditsPage($revs);
256
    }
257
258
    /**
259
     * Format the results for top edits to a single page. This method also computes
260
     * totals for added/removed text, automated and reverted edits.
261
     * @param array[] $revs As returned by TopEditsRepository::getTopEditsPage.
262
     * @return Edit[]
263
     */
264
    private function formatTopEditsPage(array $revs): array
265
    {
266
        $edits = [];
267
268
        foreach ($revs as $revision) {
269
            // Check if the edit was reverted based on the edit summary of the following edit.
270
            // If so, update $revision so that when an Edit is instantiated, it will have the 'reverted' option set.
271
            if ($this->autoEditsHelper->isRevert($revision['parent_comment'], $this->project)) {
272
                $revision['reverted'] = 1;
273
            }
274
275
            $edits[] = $this->getEditAndIncrementCounts($revision);
276
        }
277
278
        return $edits;
279
    }
280
281
    /**
282
     * Create an Edit instance for the given revision, and increment running totals.
283
     * This is used by self::formatTopEditsPage().
284
     * @param string[] $revision Revision row as retrieved from the database.
285
     * @return Edit
286
     */
287
    private function getEditAndIncrementCounts(array $revision): Edit
288
    {
289
        $edit = $this->repository->getEdit($this->page, $revision);
0 ignored issues
show
Bug introduced by
The method getEdit() does not exist on App\Repository\Repository. It seems like you code against a sub-type of App\Repository\Repository such as App\Repository\TopEditsRepository or App\Repository\PageInfoRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

289
        /** @scrutinizer ignore-call */ 
290
        $edit = $this->repository->getEdit($this->page, $revision);
Loading history...
290
291
        if ($edit->isAutomated()) {
292
            $this->totalAutomated++;
293
        }
294
295
        if ($edit->isMinor()) {
296
            $this->totalMinor++;
297
        }
298
299
        if ($edit->isReverted()) {
300
            $this->totalReverted++;
301
        } else {
302
            // Length changes don't count if they were reverted.
303
            if ($revision['length_change'] > 0) {
304
                $this->totalAdded += (int)$revision['length_change'];
305
            } else {
306
                $this->totalRemoved += (int)$revision['length_change'];
307
            }
308
        }
309
310
        return $edit;
311
    }
312
313
    /**
314
     * Format the results to be keyed by namespace.
315
     * @param array $pages As returned by TopEditsRepository::getTopEditsNamespace()
316
     *   or TopEditsRepository::getTopEditsAllNamespaces().
317
     * @return array Same results but keyed by namespace.
318
     */
319
    private function formatTopPagesNamespace(array $pages): array
320
    {
321
        /** @var string[] $topEditedPages The top edited pages, keyed by namespace ID. */
322
        $topEditedPages = [];
323
324
        foreach ($pages as $page) {
325
            $nsId = (int)$page['namespace'];
326
            $page['page_title'] = str_replace('_', ' ', $page['page_title']);
327
328
            // FIXME: needs refactoring, done in PagesController::getPagepileResult() and AppExtension::titleWithNs().
329
            if (0 === $nsId) {
330
                $page['full_page_title'] = $page['page_title'];
331
            } else {
332
                $page['full_page_title'] = str_replace('_', ' ', (
333
                    $this->project->getNamespaces()[$page['namespace']] ?? ''
334
                ).':'.$page['page_title']);
335
            }
336
337
            if (array_key_exists('pa_class', $page)) {
338
                $page['assessment'] = array_merge(
339
                    ['class' => $page['pa_class']],
340
                    $this->project->getPageAssessments()->getClassAttrs($page['pa_class'])
341
                );
342
                unset($page['pa_class']);
343
            }
344
345
            if (isset($topEditedPages[$nsId])) {
346
                $topEditedPages[$nsId][] = $page;
347
            } else {
348
                $topEditedPages[$nsId] = [$page];
349
            }
350
        }
351
352
        return $topEditedPages;
353
    }
354
}
355