Passed
Push — master ( f3a10f...0cfa7d )
by MusikAnimal
06:25
created

Pages   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 326
Duplicated Lines 0 %

Test Coverage

Coverage 71.05%

Importance

Changes 0
Metric Value
eloc 113
dl 0
loc 326
ccs 81
cts 114
cp 0.7105
rs 9.1199
c 0
b 0
f 0
wmc 41

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getNumDeleted() 0 7 2
A getNamespaces() 0 3 1
A getNumNamespaces() 0 3 1
A getNumRedirects() 0 7 2
A getResults() 0 6 2
A __construct() 0 18 6
A prepareData() 0 14 3
A getRedirects() 0 3 1
A getDeleted() 0 3 1
A getNumPages() 0 7 2
A getNumResults() 0 7 2
A formatPages() 0 27 3
A resultsPerPage() 0 9 3
A fetchPagesCreated() 0 12 1
A getCounts() 0 22 5
A countPagesCreated() 0 10 1
A getAssessmentCounts() 0 25 5

How to fix   Complexity   

Complex Class

Complex classes like Pages often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Pages, and based on these observations, apply Extract Interface, too.

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 = 100;
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 int Pagination offset. */
27
    protected $offset;
28
29
    /** @var mixed[] The list of pages including various statistics, keyed by namespace. */
30
    protected $pages;
31
32
    /** @var mixed[] Number of redirects/pages that were created/deleted, broken down by namespace. */
33
    protected $countsByNamespace;
34
35
    /**
36
     * Pages constructor.
37
     * @param Project $project
38
     * @param User $user
39
     * @param string|int $namespace Namespace ID or 'all'.
40
     * @param string $redirects One of 'noredirects', 'onlyredirects' or 'all' for both.
41
     * @param string $deleted One of 'live', 'deleted' or 'all' for both.
42
     * @param int|false $start Start date in a format accepted by strtotime()
43
     * @param int|false $end End date in a format accepted by strtotime()
44
     * @param int $offset Pagination offset.
45
     */
46 2
    public function __construct(
47
        Project $project,
48
        User $user,
49
        $namespace = 0,
50
        $redirects = 'noredirects',
51
        $deleted = 'all',
52
        $start = false,
53
        $end = false,
54
        $offset = 0
55
    ) {
56 2
        $this->project = $project;
57 2
        $this->user = $user;
58 2
        $this->namespace = 'all' === $namespace ? 'all' : (string)$namespace;
59 2
        $this->start = false === $start ? '' : date('Y-m-d', $start);
60 2
        $this->end = false === $end ? '' : date('Y-m-d', $end);
61 2
        $this->redirects = $redirects ?: 'noredirects';
62 2
        $this->deleted = $deleted ?: 'all';
63 2
        $this->offset = $offset;
64 2
    }
65
66
    /**
67
     * The redirects option associated with this Pages instance.
68
     * @return string
69
     */
70 1
    public function getRedirects(): string
71
    {
72 1
        return $this->redirects;
73
    }
74
75
    /**
76
     * The deleted pages option associated with this Page instance.
77
     * @return string
78
     */
79
    public function getDeleted(): string
80
    {
81
        return $this->deleted;
82
    }
83
84
    /**
85
     * Fetch and prepare the pages created by the user.
86
     * @param bool $all Whether to get *all* results. This should only be used for
87
     *     export options. HTTP and JSON should paginate.
88
     * @return array
89
     * @codeCoverageIgnore
90
     */
91
    public function prepareData(bool $all = false): array
92
    {
93
        $this->pages = [];
94
95
        foreach ($this->getNamespaces() as $ns) {
96
            $data = $this->fetchPagesCreated($ns, $all);
97
            $this->pages[$ns] = count($data) > 0
98
                ? $this->formatPages($data)[$ns]
99
                : [];
100
        }
101
102
        // $this->recreatedPages = $this->fetchRecreatedPages();
103
104
        return $this->pages;
105
    }
106
107
    /**
108
     * The public function to get the list of all pages created by the user,
109
     * up to self::resultsPerPage(), across all namespaces.
110
     * @param bool $all Whether to get *all* results. This should only be used for
111
     *     export options. HTTP and JSON should paginate.
112
     * @return array
113
     */
114 1
    public function getResults(bool $all = false): array
115
    {
116 1
        if (null === $this->pages) {
117
            $this->prepareData($all);
118
        }
119 1
        return $this->pages;
120
    }
121
122
    /**
123
     * Get the total number of pages the user has created.
124
     * @return int
125
     */
126
    public function getNumPages(): int
127
    {
128
        $total = 0;
129
        foreach (array_values($this->getCounts()) as $values) {
130
            $total += $values['count'];
131
        }
132
        return $total;
133
    }
134
135
    /**
136
     * Get the total number of pages we're showing data for.
137
     * @return int
138
     */
139 1
    public function getNumResults(): int
140
    {
141 1
        $total = 0;
142 1
        foreach (array_values($this->getResults()) as $pages) {
143 1
            $total += count($pages);
144
        }
145 1
        return $total;
146
    }
147
148
    /**
149
     * Get the total number of pages that are currently deleted.
150
     * @return int
151
     */
152 1
    public function getNumDeleted(): int
153
    {
154 1
        $total = 0;
155 1
        foreach (array_values($this->getCounts()) as $values) {
156 1
            $total += $values['deleted'];
157
        }
158 1
        return $total;
159
    }
160
161
    /**
162
     * Get the total number of pages that are currently redirects.
163
     * @return int
164
     */
165 1
    public function getNumRedirects(): int
166
    {
167 1
        $total = 0;
168 1
        foreach (array_values($this->getCounts()) as $values) {
169 1
            $total += $values['redirects'];
170
        }
171 1
        return $total;
172
    }
173
174
    /**
175
     * Get the namespaces in which this user has created pages.
176
     * @return string[] The IDs.
177
     */
178 1
    public function getNamespaces(): array
179
    {
180 1
        return array_keys($this->getCounts());
181
    }
182
183
    /**
184
     * Number of namespaces being reported.
185
     * @return int
186
     */
187
    public function getNumNamespaces(): int
188
    {
189
        return count(array_keys($this->getCounts()));
190
    }
191
192
    /**
193
     * Number of redirects/pages that were created/deleted, broken down by namespace.
194
     * @return array Namespace IDs as the keys, with values 'count', 'deleted' and 'redirects'.
195
     */
196 1
    public function getCounts(): array
197
    {
198 1
        if (null !== $this->countsByNamespace) {
199 1
            return $this->countsByNamespace;
200
        }
201
202 1
        $counts = [];
203
204 1
        foreach ($this->countPagesCreated() as $row) {
205 1
            $counts[$row['namespace']] = [
206 1
                'count' => (int)$row['count'],
207
            ];
208 1
            if ('live' !== $this->deleted) {
209 1
                $counts[$row['namespace']]['deleted'] = (int)$row['deleted'];
210
            }
211 1
            if ('noredirects' !== $this->redirects) {
212 1
                $counts[$row['namespace']]['redirects'] = (int)$row['redirects'];
213
            }
214
        }
215
216 1
        $this->countsByNamespace = $counts;
217 1
        return $this->countsByNamespace;
218
    }
219
220
    /**
221
     * Get the number of pages the user created by assessment.
222
     * @return array Keys are the assessment class, values are the counts.
223
     */
224
    public function getAssessmentCounts(): array
225
    {
226
        if ($this->getNumPages() > $this->resultsPerPage()) {
227
            $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

227
            $counts = $this->getRepository()->/** @scrutinizer ignore-call */ getAssessmentCounts(
Loading history...
228
                $this->project,
229
                $this->user,
230
                $this->namespace,
231
                $this->redirects
232
            );
233
        } else {
234
            $counts = [];
235
            foreach ($this->pages as $nsPages) {
236
                foreach ($nsPages as $page) {
237
                    if (!isset($counts[$page['pa_class']])) {
238
                        $counts[$page['pa_class']] = 1;
239
                    } else {
240
                        $counts[$page['pa_class']]++;
241
                    }
242
                }
243
            }
244
        }
245
246
        arsort($counts);
247
248
        return $counts;
249
    }
250
251
    /**
252
     * Number of results to show, depending on the namespace.
253
     * @param bool $all Whether to get *all* results. This should only be used for
254
     *     export options. HTTP and JSON should paginate.
255
     * @return int|false
256
     */
257 1
    public function resultsPerPage(bool $all = false)
258
    {
259 1
        if (true === $all) {
260
            return false;
261
        }
262 1
        if ('all' === $this->namespace) {
263
            return self::RESULTS_LIMIT_ALL_NAMESPACES;
264
        }
265 1
        return self::RESULTS_LIMIT_SINGLE_NAMESPACE;
266
    }
267
268
    /**
269
     * Run the query to get pages created by the user with options.
270
     * This is ran independently for each namespace if $this->namespace is 'all'.
271
     * @param int $namespace Namespace ID.
272
     * @param bool $all Whether to get *all* results. This should only be used for
273
     *     export options. HTTP and JSON should paginate.
274
     * @return array
275
     */
276 1
    private function fetchPagesCreated(int $namespace, bool $all = false): array
277
    {
278 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

278
        return $this->getRepository()->/** @scrutinizer ignore-call */ getPagesCreated(
Loading history...
279 1
            $this->project,
280 1
            $this->user,
281 1
            $namespace,
282 1
            $this->redirects,
283 1
            $this->deleted,
284 1
            $this->start,
285 1
            $this->end,
286 1
            $this->resultsPerPage($all),
287 1
            $this->offset * $this->resultsPerPage()
288
        );
289
    }
290
291
    /**
292
     * Run the query to get the number of pages created by the user with given options.
293
     * @return array
294
     */
295 1
    private function countPagesCreated(): array
296
    {
297 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

297
        return $this->getRepository()->/** @scrutinizer ignore-call */ countPagesCreated(
Loading history...
298 1
            $this->project,
299 1
            $this->user,
300 1
            $this->namespace,
301 1
            $this->redirects,
302 1
            $this->deleted,
303 1
            $this->start,
304 1
            $this->end
305
        );
306
    }
307
308
    /**
309
     * Format the data, adding humanized timestamps, page titles, assessment badges,
310
     * and sorting by namespace and then timestamp.
311
     * @param array $pages As returned by self::fetchPagesCreated()
312
     * @return array
313
     */
314 1
    private function formatPages(array $pages): array
315
    {
316 1
        $results = [];
317
318 1
        foreach ($pages as $row) {
319 1
            $datetime = DateTime::createFromFormat('YmdHis', $row['rev_timestamp']);
320 1
            $datetimeHuman = $datetime->format('Y-m-d H:i');
321
322 1
            $pageData = array_merge($row, [
323 1
                'raw_time' => $row['rev_timestamp'],
324 1
                'human_time' => $datetimeHuman,
325 1
                'page_title' => str_replace('_', ' ', $row['page_title']),
326
            ]);
327
328 1
            if ($this->project->hasPageAssessments()) {
329
                $pageData['badge'] = $this->project
330
                    ->getPageAssessments()
331
                    ->getBadgeURL($pageData['pa_class']);
332
                $pageData['badgeFile'] = $this->project
333
                    ->getPageAssessments()
334
                    ->getBadgeURL($pageData['pa_class'], true);
335
            }
336
337 1
            $results[$row['namespace']][] = $pageData;
338
        }
339
340 1
        return $results;
341
    }
342
}
343