Passed
Branch master (0917e1)
by MusikAnimal
11:12
created

Pages::__construct()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 2
nop 8
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 4
rs 10
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 Pages class.
4
 */
5
6
declare(strict_types = 1);
7
8
namespace AppBundle\Model;
9
10
use DateTime;
11
12
/**
13
 * A Pages provides statistics about the pages created by a given User.
14
 */
15
class Pages extends Model
16
{
17
    private const RESULTS_LIMIT_SINGLE_NAMESPACE = 1000;
18
    private const RESULTS_LIMIT_ALL_NAMESPACES = 50;
19
20
    /** @var string One of 'noredirects', 'onlyredirects' or 'all' for both. */
21
    protected $redirects;
22
23
    /** @var string One of 'live', 'deleted' or 'all' for both. */
24
    protected $deleted;
25
26
    /** @var mixed[] The list of pages including various statistics, keyed by namespace. */
27
    protected $pages;
28
29
    /** @var mixed[] Number of redirects/pages that were created/deleted, broken down by namespace. */
30
    protected $countsByNamespace;
31
32
    /**
33
     * Pages constructor.
34
     * @param Project $project
35
     * @param User $user
36
     * @param string|int $namespace Namespace ID or 'all'.
37
     * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both.
38
     * @param string $deleted One of 'live', 'deleted' or 'all' for both.
39
     * @param int|false $start Start date as Unix timestamp.
40
     * @param int|false $end End date as Unix timestamp.
41
     * @param int|false $offset Unix timestamp. Used for pagination.
42
     */
43 2
    public function __construct(
44
        Project $project,
45
        User $user,
46
        $namespace = 0,
47
        $redirects = 'noredirects',
48
        $deleted = 'all',
49
        $start = false,
50
        $end = false,
51
        $offset = false
52
    ) {
53 2
        $this->project = $project;
54 2
        $this->user = $user;
55 2
        $this->namespace = 'all' === $namespace ? 'all' : (string)$namespace;
56 2
        $this->start = $start;
57 2
        $this->end = $end;
58 2
        $this->redirects = $redirects ?: 'noredirects';
59 2
        $this->deleted = $deleted ?: 'all';
60 2
        $this->offset = $offset;
61 2
    }
62
63
    /**
64
     * The redirects option associated with this Pages instance.
65
     * @return string
66
     */
67 1
    public function getRedirects(): string
68
    {
69 1
        return $this->redirects;
70
    }
71
72
    /**
73
     * The deleted pages option associated with this Page instance.
74
     * @return string
75
     */
76
    public function getDeleted(): string
77
    {
78
        return $this->deleted;
79
    }
80
81
    /**
82
     * Fetch and prepare the pages created by the user.
83
     * @param bool $all Whether to get *all* results. This should only be used for
84
     *     export options. HTTP and JSON should paginate.
85
     * @return array
86
     * @codeCoverageIgnore
87
     */
88
    public function prepareData(bool $all = false): array
89
    {
90
        $this->pages = [];
91
92
        foreach ($this->getNamespaces() as $ns) {
93
            $data = $this->fetchPagesCreated($ns, $all);
94
            $this->pages[$ns] = count($data) > 0
95
                ? $this->formatPages($data)[$ns]
96
                : [];
97
        }
98
99
        return $this->pages;
100
    }
101
102
    /**
103
     * The public function to get the list of all pages created by the user,
104
     * up to self::resultsPerPage(), across all namespaces.
105
     * @param bool $all Whether to get *all* results. This should only be used for
106
     *     export options. HTTP and JSON should paginate.
107
     * @return array
108
     */
109 1
    public function getResults(bool $all = false): array
110
    {
111 1
        if (null === $this->pages) {
112
            $this->prepareData($all);
113
        }
114 1
        return $this->pages;
115
    }
116
117
    /**
118
     * Return a ISO 8601 timestamp of the last result. This is used for pagination purposes.
119
     * @return string|null
120
     */
121
    public function getLastTimestamp(): ?string
122
    {
123
        if ($this->isMultiNamespace()) {
124
            // No pagination in multi-namespace view.
125
            return null;
126
        }
127
128
        $numResults = count($this->getResults()[$this->getNamespace()]);
129
        $timestamp = new DateTime($this->getResults()[$this->getNamespace()][$numResults - 1]['rev_timestamp']);
130
        return $timestamp->format('Y-m-d\TH:i:s');
131
    }
132
133
    /**
134
     * Get the total number of pages the user has created.
135
     * @return int
136
     */
137
    public function getNumPages(): int
138
    {
139
        $total = 0;
140
        foreach (array_values($this->getCounts()) as $values) {
141
            $total += $values['count'];
142
        }
143
        return $total;
144
    }
145
146
    /**
147
     * Get the total number of pages we're showing data for.
148
     * @return int
149
     */
150 1
    public function getNumResults(): int
151
    {
152 1
        $total = 0;
153 1
        foreach (array_values($this->getResults()) as $pages) {
154 1
            $total += count($pages);
155
        }
156 1
        return $total;
157
    }
158
159
    /**
160
     * Get the total number of pages that are currently deleted.
161
     * @return int
162
     */
163 1
    public function getNumDeleted(): int
164
    {
165 1
        $total = 0;
166 1
        foreach (array_values($this->getCounts()) as $values) {
167 1
            $total += $values['deleted'];
168
        }
169 1
        return $total;
170
    }
171
172
    /**
173
     * Get the total number of pages that are currently redirects.
174
     * @return int
175
     */
176 1
    public function getNumRedirects(): int
177
    {
178 1
        $total = 0;
179 1
        foreach (array_values($this->getCounts()) as $values) {
180 1
            $total += $values['redirects'];
181
        }
182 1
        return $total;
183
    }
184
185
    /**
186
     * Get the namespaces in which this user has created pages.
187
     * @return int[] The IDs.
188
     */
189 1
    public function getNamespaces(): array
190
    {
191 1
        return array_keys($this->getCounts());
192
    }
193
194
    /**
195
     * Number of namespaces being reported.
196
     * @return int
197
     */
198 1
    public function getNumNamespaces(): int
199
    {
200 1
        return count(array_keys($this->getCounts()));
201
    }
202
203
    /**
204
     * Are there more than one namespace in the results?
205
     * @return bool
206
     */
207 1
    public function isMultiNamespace(): bool
208
    {
209 1
        return $this->getNumNamespaces() > 1;
210
    }
211
212
    /**
213
     * Get the sum of all page sizes, across all specified namespaces.
214
     * @return int
215
     */
216
    public function getTotalPageSize(): int
217
    {
218
        return array_sum(array_column($this->getCounts(), 'total_length'));
219
    }
220
221
    /**
222
     * Get average size across all pages.
223
     * @return float
224
     */
225
    public function averagePageSize(): float
226
    {
227
        return $this->getTotalPageSize() / $this->getNumPages();
228
    }
229
230
    /**
231
     * Number of redirects/pages that were created/deleted, broken down by namespace.
232
     * @return array Namespace IDs as the keys, with values 'count', 'deleted' and 'redirects'.
233
     */
234 1
    public function getCounts(): array
235
    {
236 1
        if (null !== $this->countsByNamespace) {
237 1
            return $this->countsByNamespace;
238
        }
239
240 1
        $counts = [];
241
242 1
        foreach ($this->countPagesCreated() as $row) {
243 1
            $ns = (int)$row['namespace'];
244 1
            $count = (int)$row['count'];
245 1
            $totalLength = (int)$row['total_length'];
246 1
            $counts[$ns] = [
247 1
                'count' => $count,
248 1
                'total_length' => $totalLength,
249 1
                'avg_length' => $count > 0 ? $totalLength / $count : 0,
250
            ];
251 1
            if ('live' !== $this->deleted) {
252 1
                $counts[$ns]['deleted'] = (int)$row['deleted'];
253
            }
254 1
            if ('noredirects' !== $this->redirects) {
255 1
                $counts[$ns]['redirects'] = (int)$row['redirects'];
256
            }
257
        }
258
259 1
        $this->countsByNamespace = $counts;
260 1
        return $this->countsByNamespace;
261
    }
262
263
    /**
264
     * Get the number of pages the user created by assessment.
265
     * @return array Keys are the assessment class, values are the counts.
266
     */
267
    public function getAssessmentCounts(): array
268
    {
269
        if ($this->getNumPages() > $this->resultsPerPage()) {
270
            $counts = $this->getRepository()->getAssessmentCounts(
0 ignored issues
show
Bug introduced by
The method getAssessmentCounts() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\PagesRepository. ( Ignorable by Annotation )

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

270
            $counts = $this->getRepository()->/** @scrutinizer ignore-call */ getAssessmentCounts(
Loading history...
271
                $this->project,
272
                $this->user,
273
                $this->namespace,
274
                $this->redirects
275
            );
276
        } else {
277
            $counts = [];
278
            foreach ($this->pages as $nsPages) {
279
                foreach ($nsPages as $page) {
280
                    if (!isset($counts[$page['pa_class']])) {
281
                        $counts[$page['pa_class']] = 1;
282
                    } else {
283
                        $counts[$page['pa_class']]++;
284
                    }
285
                }
286
            }
287
        }
288
289
        arsort($counts);
290
291
        return $counts;
292
    }
293
294
    /**
295
     * Number of results to show, depending on the namespace.
296
     * @param bool $all Whether to get *all* results. This should only be used for
297
     *     export options. HTTP and JSON should paginate.
298
     * @return int|false
299
     */
300 1
    public function resultsPerPage(bool $all = false)
301
    {
302 1
        if (true === $all) {
303
            return false;
304
        }
305 1
        if ('all' === $this->namespace) {
306
            return self::RESULTS_LIMIT_ALL_NAMESPACES;
307
        }
308 1
        return self::RESULTS_LIMIT_SINGLE_NAMESPACE;
309
    }
310
311
    /**
312
     * Run the query to get pages created by the user with options.
313
     * This is ran independently for each namespace if $this->namespace is 'all'.
314
     * @param int $namespace Namespace ID.
315
     * @param bool $all Whether to get *all* results. This should only be used for
316
     *     export options. HTTP and JSON should paginate.
317
     * @return array
318
     */
319 1
    private function fetchPagesCreated(int $namespace, bool $all = false): array
320
    {
321 1
        return $this->getRepository()->getPagesCreated(
0 ignored issues
show
Bug introduced by
The method getPagesCreated() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\PagesRepository. ( Ignorable by Annotation )

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

321
        return $this->getRepository()->/** @scrutinizer ignore-call */ getPagesCreated(
Loading history...
322 1
            $this->project,
323 1
            $this->user,
324 1
            $namespace,
325 1
            $this->redirects,
326 1
            $this->deleted,
327 1
            $this->start,
328 1
            $this->end,
329 1
            $this->resultsPerPage($all),
330 1
            $this->offset
331
        );
332
    }
333
334
    /**
335
     * Run the query to get the number of pages created by the user with given options.
336
     * @return array
337
     */
338 1
    private function countPagesCreated(): array
339
    {
340 1
        return $this->getRepository()->countPagesCreated(
0 ignored issues
show
Bug introduced by
The method countPagesCreated() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\PagesRepository. ( Ignorable by Annotation )

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

340
        return $this->getRepository()->/** @scrutinizer ignore-call */ countPagesCreated(
Loading history...
341 1
            $this->project,
342 1
            $this->user,
343 1
            $this->namespace,
344 1
            $this->redirects,
345 1
            $this->deleted,
346 1
            $this->start,
347 1
            $this->end
348
        );
349
    }
350
351
    /**
352
     * Format the data, adding humanized timestamps, page titles, assessment badges,
353
     * and sorting by namespace and then timestamp.
354
     * @param array $pages As returned by self::fetchPagesCreated()
355
     * @return array
356
     */
357 1
    private function formatPages(array $pages): array
358
    {
359 1
        $results = [];
360
361 1
        foreach ($pages as $row) {
362 1
            $datetime = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']);
363 1
            $datetimeHuman = $datetime->format('Y-m-d H:i');
364
365 1
            $pageData = array_merge($row, [
366 1
                'raw_time' => $row['rev_timestamp'],
367 1
                'human_time' => $datetimeHuman,
368 1
                'page_title' => str_replace('_', ' ', $row['page_title']),
369
            ]);
370
371 1
            if ($this->project->hasPageAssessments()) {
372
                $pageData['badge'] = $this->project
373
                    ->getPageAssessments()
374
                    ->getBadgeURL($pageData['pa_class']);
375
                $pageData['badge_file'] = $this->project
376
                    ->getPageAssessments()
377
                    ->getBadgeURL($pageData['pa_class'], true);
378
            }
379
380 1
            $results[$row['namespace']][] = $pageData;
381
        }
382
383 1
        return $results;
384
    }
385
}
386