Passed
Push — master ( 4fbd4f...e8494b )
by MusikAnimal
11:14
created

TopEdits::__construct()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

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

199
            $pages = $this->getRepository()->/** @scrutinizer ignore-call */ getTopEditsAllNamespaces(
Loading history...
200 1
                $this->project,
201 1
                $this->user,
202 1
                $this->start,
203 1
                $this->end,
204 1
                $this->limit
205
            );
206
        } else {
207 1
            $pages = $this->getRepository()->getTopEditsNamespace(
0 ignored issues
show
Bug introduced by
The method getTopEditsNamespace() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\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

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

235
        return (int)$this->getRepository()->/** @scrutinizer ignore-call */ countEditsNamespace(
Loading history...
236
            $this->project,
237
            $this->user,
238
            $this->namespace,
239
            $this->start,
240
            $this->end
241
        );
242
    }
243
244
    /**
245
     * Get the top edits to the given page.
246
     * @param bool $format Whether to format the results, including stats for
247
     *     number of reverts, etc. This is set to false for the API endpoint.
248
     * @return Edit[]
249
     */
250 1
    private function getTopEditsPage(bool $format = true): array
251
    {
252 1
        $revs = $this->getRepository()->getTopEditsPage(
0 ignored issues
show
Bug introduced by
The method getTopEditsPage() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\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

252
        $revs = $this->getRepository()->/** @scrutinizer ignore-call */ getTopEditsPage(
Loading history...
253 1
            $this->page,
254 1
            $this->user,
255 1
            $this->start,
256 1
            $this->end
257
        );
258
259 1
        if ($format) {
260 1
            return $this->formatTopEditsPage($revs);
261
        } else {
262
            return $revs;
263
        }
264
    }
265
266
    /**
267
     * Format the results for top edits to a single page. This method also computes
268
     * totals for added/removed text, automated and reverted edits.
269
     * @param array[] $revs As returned by TopEditsRepository::getTopEditsPage.
270
     * @return Edit[]
271
     */
272 1
    private function formatTopEditsPage(array $revs): array
273
    {
274 1
        $edits = [];
275
276
        /** @var AutomatedEditsHelper $aeh */
277 1
        $aeh = $this->getRepository()
278 1
            ->getContainer()
0 ignored issues
show
Bug introduced by
The method getContainer() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\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

278
            ->/** @scrutinizer ignore-call */ getContainer()
Loading history...
279 1
            ->get('app.automated_edits_helper');
280
281 1
        foreach ($revs as $revision) {
282
            // Check if the edit was reverted based on the edit summary of the following edit.
283
            // If so, update $revision so that when an Edit is instantiated, it will have the 'reverted' option set.
284 1
            if ($aeh->isRevert($revision['parent_comment'], $this->project)) {
285 1
                $revision['reverted'] = 1;
286
            }
287
288 1
            $edit = $this->getEditAndIncrementCounts($revision);
289
290 1
            $edits[] = $edit;
291
        }
292
293 1
        return $edits;
294
    }
295
296
    /**
297
     * Create an Edit instance for the given revision, and increment running totals.
298
     * This is used by self::formatTopEditsPage().
299
     * @param string[] $revision Revision row as retrieved from the database.
300
     * @return Edit
301
     */
302 1
    private function getEditAndIncrementCounts(array $revision): Edit
303
    {
304 1
        $edit = new Edit($this->page, $revision);
305
306 1
        if ($edit->isAutomated($this->getRepository()->getContainer())) {
307 1
            $this->totalAutomated++;
308
        }
309
310 1
        if ($edit->isMinor()) {
311 1
            $this->totalMinor++;
312
        }
313
314 1
        if ($edit->isReverted()) {
315 1
            $this->totalReverted++;
316
        } else {
317
            // Length changes don't count if they were reverted.
318 1
            if ($revision['length_change'] > 0) {
319 1
                $this->totalAdded += $revision['length_change'];
320
            } else {
321 1
                $this->totalRemoved += $revision['length_change'];
322
            }
323
        }
324
325 1
        return $edit;
326
    }
327
328
    /**
329
     * Format the results to be keyed by namespace.
330
     * @param array $pages As returned by TopEditsRepository::getTopEditsNamespace()
331
     *   or TopEditsRepository::getTopEditsAllNamespaces().
332
     * @return array Same results but keyed by namespace.
333
     */
334 2
    private function formatTopPagesNamespace(array $pages): array
335
    {
336
        /** @var string[] $topEditedPages The top edited pages, keyed by namespace ID. */
337 2
        $topEditedPages = [];
338
339 2
        foreach ($pages as $page) {
340 2
            $nsId = (int)$page['page_namespace'];
341
342
            // FIXME: needs refactoring, done in PagesController::getPagepileResult() and AppExtension::titleWithNs().
343 2
            if (0 === $nsId) {
344 1
                $page['page_title_ns'] = $page['page_title'];
345
            } else {
346 2
                $page['page_title_ns'] = (
347 2
                    $this->project->getNamespaces()[$page['page_namespace']] ?? ''
348 2
                ).':'.$page['page_title'];
349
            }
350
351 2
            if (isset($topEditedPages[$nsId])) {
352 2
                $topEditedPages[$nsId][] = $page;
353
            } else {
354 2
                $topEditedPages[$nsId] = [$page];
355
            }
356
        }
357
358 2
        return $topEditedPages;
359
    }
360
}
361