Passed
Pull Request — master (#378)
by MusikAnimal
10:24
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
     * Get the total number of pages the user has created.
119
     * @return int
120
     */
121
    public function getNumPages(): int
122
    {
123
        $total = 0;
124
        foreach (array_values($this->getCounts()) as $values) {
125
            $total += $values['count'];
126
        }
127
        return $total;
128
    }
129
130
    /**
131
     * Get the total number of pages we're showing data for.
132
     * @return int
133
     */
134 1
    public function getNumResults(): int
135
    {
136 1
        $total = 0;
137 1
        foreach (array_values($this->getResults()) as $pages) {
138 1
            $total += count($pages);
139
        }
140 1
        return $total;
141
    }
142
143
    /**
144
     * Get the total number of pages that are currently deleted.
145
     * @return int
146
     */
147 1
    public function getNumDeleted(): int
148
    {
149 1
        $total = 0;
150 1
        foreach (array_values($this->getCounts()) as $values) {
151 1
            $total += $values['deleted'];
152
        }
153 1
        return $total;
154
    }
155
156
    /**
157
     * Get the total number of pages that are currently redirects.
158
     * @return int
159
     */
160 1
    public function getNumRedirects(): int
161
    {
162 1
        $total = 0;
163 1
        foreach (array_values($this->getCounts()) as $values) {
164 1
            $total += $values['redirects'];
165
        }
166 1
        return $total;
167
    }
168
169
    /**
170
     * Get the namespaces in which this user has created pages.
171
     * @return int[] The IDs.
172
     */
173 1
    public function getNamespaces(): array
174
    {
175 1
        return array_keys($this->getCounts());
176
    }
177
178
    /**
179
     * Number of namespaces being reported.
180
     * @return int
181
     */
182 1
    public function getNumNamespaces(): int
183
    {
184 1
        return count(array_keys($this->getCounts()));
185
    }
186
187
    /**
188
     * Are there more than one namespace in the results?
189
     * @return bool
190
     */
191 1
    public function isMultiNamespace(): bool
192
    {
193 1
        return $this->getNumNamespaces() > 1;
194
    }
195
196
    /**
197
     * Get the sum of all page sizes, across all specified namespaces.
198
     * @return int
199
     */
200
    public function getTotalPageSize(): int
201
    {
202
        return array_sum(array_column($this->getCounts(), 'total_length'));
203
    }
204
205
    /**
206
     * Get average size across all pages.
207
     * @return float
208
     */
209
    public function averagePageSize(): float
210
    {
211
        return $this->getTotalPageSize() / $this->getNumPages();
212
    }
213
214
    /**
215
     * Number of redirects/pages that were created/deleted, broken down by namespace.
216
     * @return array Namespace IDs as the keys, with values 'count', 'deleted' and 'redirects'.
217
     */
218 1
    public function getCounts(): array
219
    {
220 1
        if (null !== $this->countsByNamespace) {
221 1
            return $this->countsByNamespace;
222
        }
223
224 1
        $counts = [];
225
226 1
        foreach ($this->countPagesCreated() as $row) {
227 1
            $ns = (int)$row['namespace'];
228 1
            $count = (int)$row['count'];
229 1
            $totalLength = (int)$row['total_length'];
230 1
            $counts[$ns] = [
231 1
                'count' => $count,
232 1
                'total_length' => $totalLength,
233 1
                'avg_length' => $count > 0 ? $totalLength / $count : 0,
234
            ];
235 1
            if ('live' !== $this->deleted) {
236 1
                $counts[$ns]['deleted'] = (int)$row['deleted'];
237
            }
238 1
            if ('noredirects' !== $this->redirects) {
239 1
                $counts[$ns]['redirects'] = (int)$row['redirects'];
240
            }
241
        }
242
243 1
        $this->countsByNamespace = $counts;
244 1
        return $this->countsByNamespace;
245
    }
246
247
    /**
248
     * Get the number of pages the user created by assessment.
249
     * @return array Keys are the assessment class, values are the counts.
250
     */
251
    public function getAssessmentCounts(): array
252
    {
253
        if ($this->getNumPages() > $this->resultsPerPage()) {
254
            $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

254
            $counts = $this->getRepository()->/** @scrutinizer ignore-call */ getAssessmentCounts(
Loading history...
255
                $this->project,
256
                $this->user,
257
                $this->namespace,
258
                $this->redirects
259
            );
260
        } else {
261
            $counts = [];
262
            foreach ($this->pages as $nsPages) {
263
                foreach ($nsPages as $page) {
264
                    if (!isset($counts[$page['pa_class']])) {
265
                        $counts[$page['pa_class']] = 1;
266
                    } else {
267
                        $counts[$page['pa_class']]++;
268
                    }
269
                }
270
            }
271
        }
272
273
        arsort($counts);
274
275
        return $counts;
276
    }
277
278
    /**
279
     * Number of results to show, depending on the namespace.
280
     * @param bool $all Whether to get *all* results. This should only be used for
281
     *     export options. HTTP and JSON should paginate.
282
     * @return int|false
283
     */
284 1
    public function resultsPerPage(bool $all = false)
285
    {
286 1
        if (true === $all) {
287
            return false;
288
        }
289 1
        if ('all' === $this->namespace) {
290
            return self::RESULTS_LIMIT_ALL_NAMESPACES;
291
        }
292 1
        return self::RESULTS_LIMIT_SINGLE_NAMESPACE;
293
    }
294
295
    /**
296
     * Run the query to get pages created by the user with options.
297
     * This is ran independently for each namespace if $this->namespace is 'all'.
298
     * @param int $namespace Namespace ID.
299
     * @param bool $all Whether to get *all* results. This should only be used for
300
     *     export options. HTTP and JSON should paginate.
301
     * @return array
302
     */
303 1
    private function fetchPagesCreated(int $namespace, bool $all = false): array
304
    {
305 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

305
        return $this->getRepository()->/** @scrutinizer ignore-call */ getPagesCreated(
Loading history...
306 1
            $this->project,
307 1
            $this->user,
308 1
            $namespace,
309 1
            $this->redirects,
310 1
            $this->deleted,
311 1
            $this->start,
312 1
            $this->end,
313 1
            $this->resultsPerPage($all),
314 1
            $this->offset
315
        );
316
    }
317
318
    /**
319
     * Run the query to get the number of pages created by the user with given options.
320
     * @return array
321
     */
322 1
    private function countPagesCreated(): array
323
    {
324 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

324
        return $this->getRepository()->/** @scrutinizer ignore-call */ countPagesCreated(
Loading history...
325 1
            $this->project,
326 1
            $this->user,
327 1
            $this->namespace,
328 1
            $this->redirects,
329 1
            $this->deleted,
330 1
            $this->start,
331 1
            $this->end
332
        );
333
    }
334
335
    /**
336
     * Format the data, adding humanized timestamps, page titles, assessment badges,
337
     * and sorting by namespace and then timestamp.
338
     * @param array $pages As returned by self::fetchPagesCreated()
339
     * @return array
340
     */
341 1
    private function formatPages(array $pages): array
342
    {
343 1
        $results = [];
344
345 1
        foreach ($pages as $row) {
346 1
            $datetime = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']);
347 1
            $datetimeHuman = $datetime->format('Y-m-d H:i');
348
349 1
            $pageData = array_merge($row, [
350 1
                'raw_time' => $row['rev_timestamp'],
351 1
                'human_time' => $datetimeHuman,
352 1
                'page_title' => str_replace('_', ' ', $row['page_title']),
353
            ]);
354
355 1
            if ($this->project->hasPageAssessments()) {
356
                $pageData['badge'] = $this->project
357
                    ->getPageAssessments()
358
                    ->getBadgeURL($pageData['pa_class']);
359
                $pageData['badge_file'] = $this->project
360
                    ->getPageAssessments()
361
                    ->getBadgeURL($pageData['pa_class'], true);
362
            }
363
364 1
            $results[$row['namespace']][] = $pageData;
365
        }
366
367 1
        return $results;
368
    }
369
}
370