Passed
Push — swagger-docs ( 6837d7 )
by MusikAnimal
11:33
created

PagesRepository::getPagesCreatedInnerSql()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 70
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 39
nc 12
nop 8
dl 0
loc 70
rs 8.6737
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Repository;
6
7
use App\Model\Project;
8
use App\Model\User;
9
10
/**
11
 * An PagesRepository is responsible for retrieving information from the
12
 * databases for the Pages Created tool. It does not do any post-processing
13
 * of that data.
14
 * @codeCoverageIgnore
15
 */
16
class PagesRepository extends UserRepository
17
{
18
    /**
19
     * Count the number of pages created by a user.
20
     * @param Project $project
21
     * @param User $user
22
     * @param string|int $namespace Namespace ID or 'all'.
23
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
24
     * @param string $deleted One of 'live', 'deleted' or blank for both.
25
     * @param int|false $start Start date as Unix timestamp.
26
     * @param int|false $end End date as Unix timestamp.
27
     * @return string[] Result of query, see below. Includes live and deleted pages.
28
     */
29
    public function countPagesCreated(
30
        Project $project,
31
        User $user,
32
        $namespace,
33
        string $redirects,
34
        string $deleted,
35
        $start = false,
36
        $end = false
37
    ): array {
38
        $cacheKey = $this->getCacheKey(func_get_args(), 'num_user_pages_created');
39
        if ($this->cache->hasItem($cacheKey)) {
40
            return $this->cache->getItem($cacheKey)->get();
41
        }
42
43
        $conditions = [
44
            'paSelects' => '',
45
            'paSelectsArchive' => '',
46
            'paJoin' => '',
47
            'revPageGroupBy' => '',
48
        ];
49
        $conditions = array_merge(
50
            $conditions,
51
            $this->getNamespaceRedirectAndDeletedPagesConditions($namespace, $redirects),
52
            $this->getUserConditions('' !== $start.$end)
53
        );
54
55
        $sql = "SELECT `namespace`,
56
                    COUNT(page_title) AS `count`,
57
                    SUM(IF(type = 'arc', 1, 0)) AS `deleted`,
58
                    SUM(redirect) AS `redirects`,
59
                    SUM(rev_length) AS `total_length`
60
                FROM (" .
61
            $this->getPagesCreatedInnerSql($project, $conditions, $redirects, $deleted, $start, $end, false, true)."
62
                ) a ".
63
                "GROUP BY `namespace`";
64
65
        $result = $this->executeQuery($sql, $project, $user, $namespace)
66
            ->fetchAllAssociative();
67
68
        // Cache and return.
69
        return $this->setCache($cacheKey, $result);
70
    }
71
72
    /**
73
     * Get pages created by a user.
74
     * @param Project $project
75
     * @param User $user
76
     * @param string|int $namespace Namespace ID or 'all'.
77
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
78
     * @param string $deleted One of 'live', 'deleted' or blank for both.
79
     * @param int|false $start Start date as Unix timestamp.
80
     * @param int|false $end End date as Unix timestamp.
81
     * @param int|null $limit Number of results to return, or blank to return all.
82
     * @param false|int $offset Unix timestamp. Used for pagination.
83
     * @return string[] Result of query, see below. Includes live and deleted pages.
84
     */
85
    public function getPagesCreated(
86
        Project $project,
87
        User $user,
88
        $namespace,
89
        string $redirects,
90
        string $deleted,
91
        $start = false,
92
        $end = false,
93
        ?int $limit = 1000,
94
        $offset = false
95
    ): array {
96
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_pages_created');
97
        if ($this->cache->hasItem($cacheKey)) {
98
            return $this->cache->getItem($cacheKey)->get();
99
        }
100
101
        $conditions = [
102
            'paSelects' => '',
103
            'paSelectsArchive' => '',
104
            'paJoin' => '',
105
            'revPageGroupBy' => '',
106
        ];
107
108
        $conditions = array_merge(
109
            $conditions,
110
            $this->getNamespaceRedirectAndDeletedPagesConditions($namespace, $redirects),
111
            $this->getUserConditions('' !== $start.$end)
112
        );
113
114
        $pageAssessmentsTable = $project->getTableName('page_assessments');
115
116
        $hasPageAssessments = $this->isWMF && $project->hasPageAssessments();
117
        if ($hasPageAssessments) {
118
            $conditions['paSelects'] = ', pa_class';
119
            $conditions['paSelectsArchive'] = ', NULL AS pa_class';
120
            $conditions['paJoin'] = "LEFT JOIN $pageAssessmentsTable ON rev_page = pa_page_id";
121
            $conditions['revPageGroupBy'] = 'GROUP BY rev_page';
122
        }
123
124
        $sql = "SELECT * FROM (".
125
            $this->getPagesCreatedInnerSql($project, $conditions, $redirects, $deleted, $start, $end, $offset)."
126
                ) a ".
127
                "ORDER BY `timestamp` DESC
128
                ".(!empty($limit) ? "LIMIT $limit" : '');
129
130
        $result = $this->executeQuery($sql, $project, $user, $namespace)
131
            ->fetchAllAssociative();
132
133
        // Cache and return.
134
        return $this->setCache($cacheKey, $result);
135
    }
136
137
    /**
138
     * Get SQL fragments for the namespace and redirects,
139
     * to be used in self::getPagesCreatedInnerSql().
140
     * @param string|int $namespace Namespace ID or 'all'.
141
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
142
     * @return string[] With keys 'namespaceRev', 'namespaceArc' and 'redirects'
143
     */
144
    private function getNamespaceRedirectAndDeletedPagesConditions($namespace, string $redirects): array
145
    {
146
        $conditions = [
147
            'namespaceArc' => '',
148
            'namespaceRev' => '',
149
            'redirects' => '',
150
        ];
151
152
        if ('all' !== $namespace) {
153
            $conditions['namespaceRev'] = " AND page_namespace = '".intval($namespace)."' ";
154
            $conditions['namespaceArc'] = " AND ar_namespace = '".intval($namespace)."' ";
155
        }
156
157
        if ('onlyredirects' == $redirects) {
158
            $conditions['redirects'] = " AND page_is_redirect = '1' ";
159
        } elseif ('noredirects' == $redirects) {
160
            $conditions['redirects'] = " AND page_is_redirect = '0' ";
161
        }
162
163
        return $conditions;
164
    }
165
166
    /**
167
     * Inner SQL for getting or counting pages created by the user.
168
     * @param Project $project
169
     * @param string[] $conditions Conditions for the SQL, must include 'paSelects',
170
     *     'paSelectsArchive', 'paJoin', 'whereRev', 'whereArc', 'namespaceRev', 'namespaceArc',
171
     *     'redirects' and 'revPageGroupBy'.
172
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
173
     * @param string $deleted One of 'live', 'deleted' or blank for both.
174
     * @param int|false $start Start date as Unix timestamp.
175
     * @param int|false $end End date as Unix timestamp.
176
     * @param int|false $offset Unix timestamp, used for pagination.
177
     * @param bool $count Omit unneeded columns from the SELECT clause.
178
     * @return string Raw SQL.
179
     */
180
    private function getPagesCreatedInnerSql(
181
        Project $project,
182
        array $conditions,
183
        string $redirects,
184
        string $deleted,
185
        $start,
186
        $end,
187
        $offset = false,
188
        bool $count = false
189
    ): string {
190
        $pageTable = $project->getTableName('page');
191
        $revisionTable = $project->getTableName('revision');
192
        $archiveTable = $project->getTableName('archive');
193
        $logTable = $project->getTableName('logging', 'logindex');
194
195
        // Only SELECT things that are needed, based on whether or not we're doing a COUNT.
196
        $revSelects = "DISTINCT page_namespace AS `namespace`, 'rev' AS `type`, page_title, "
197
            . "page_is_redirect AS `redirect`, rev_len AS `rev_length`";
198
        if (!$count) {
199
            $revSelects .= ", page_len AS `length`, rev_timestamp AS `timestamp`, "
200
                . "rev_id, NULL AS `recreated` ";
201
        }
202
203
        $revDateConditions = $this->getDateConditions($start, $end, $offset);
204
        $arDateConditions = $this->getDateConditions($start, $end, $offset, '', 'ar_timestamp');
205
206
        $revisionsSelect = "
207
            SELECT $revSelects ".$conditions['paSelects']."
208
            FROM $pageTable
209
            JOIN $revisionTable ON page_id = rev_page ".
210
            $conditions['paJoin']."
211
            WHERE ".$conditions['whereRev']."
212
                AND rev_parent_id = '0'".
213
                $conditions['namespaceRev'].
214
                $conditions['redirects'].
215
                $revDateConditions.
216
            $conditions['revPageGroupBy'];
217
218
        // Only SELECT things that are needed, based on whether or not we're doing a COUNT.
219
        $arSelects = "ar_namespace AS `namespace`, 'arc' AS `type`, ar_title AS `page_title`, "
220
            . "'0' AS `redirect`, ar_len AS `rev_length`";
221
        if (!$count) {
222
            $arSelects .= ", NULL AS `length`, MIN(ar_timestamp) AS `timestamp`, ".
223
                "ar_rev_id AS `rev_id`, EXISTS(
224
                    SELECT 1 FROM $pageTable
225
                    WHERE namespace = ar_namespace
226
                    AND page_title = ar_title
227
                ) AS `recreated`";
228
        }
229
230
        $archiveSelect = "
231
            SELECT $arSelects ".$conditions['paSelectsArchive']."
232
            FROM $archiveTable
233
            LEFT JOIN $logTable ON log_namespace = ar_namespace AND log_title = ar_title
234
                AND log_actor = ar_actor AND (log_action = 'move' OR log_action = 'move_redir')
235
                AND log_type = 'move'
236
            WHERE ".$conditions['whereArc']."
237
                AND ar_parent_id = '0' ".
238
                $conditions['namespaceArc']."
239
                AND log_action IS NULL
240
                $arDateConditions
241
            GROUP BY ar_namespace, ar_title";
242
243
        if ('live' === $deleted || 'onlyredirects' === $redirects) {
244
            return $revisionsSelect;
245
        } elseif ('deleted' === $deleted) {
246
            return $archiveSelect;
247
        }
248
249
        return "($revisionsSelect) UNION ($archiveSelect)";
250
    }
251
252
    /**
253
     * Get the number of pages the user created by assessment.
254
     * @param Project $project
255
     * @param User $user
256
     * @param int|string $namespace
257
     * @param string $redirects
258
     * @param int|false $start Start date as Unix timestamp.
259
     * @param int|false $end End date as Unix timestamp.
260
     * @return array Keys are the assessment class, values are the counts.
261
     */
262
    public function getAssessmentCounts(
263
        Project $project,
264
        User $user,
265
        $namespace,
266
        string $redirects,
267
        $start = false,
268
        $end = false
269
    ): array {
270
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_pages_created_assessments');
271
        if ($this->cache->hasItem($cacheKey)) {
272
            return $this->cache->getItem($cacheKey)->get();
273
        }
274
275
        $pageTable = $project->getTableName('page');
276
        $revisionTable = $project->getTableName('revision');
277
        $pageAssessmentsTable = $project->getTableName('page_assessments');
278
279
        $conditions = array_merge(
280
            $this->getNamespaceRedirectAndDeletedPagesConditions($namespace, $redirects),
281
            $this->getUserConditions('' !== $start.$end)
282
        );
283
        $revDateConditions = $this->getDateConditions($start, $end);
284
285
        $sql = "SELECT pa_class AS `class`, COUNT(pa_class) AS `count` FROM (
286
                    SELECT DISTINCT page_id, IFNULL(pa_class, '') AS pa_class
287
                    FROM $pageTable
288
                    JOIN $revisionTable ON page_id = rev_page
289
                    LEFT JOIN $pageAssessmentsTable ON rev_page = pa_page_id
290
                    WHERE ".$conditions['whereRev']."
291
                    AND rev_parent_id = '0'".
292
                    $conditions['namespaceRev'].
293
                    $conditions['redirects'].
294
                    $revDateConditions."
295
                    GROUP BY page_id
296
                ) a
297
                GROUP BY pa_class";
298
299
        $resultQuery = $this->executeQuery($sql, $project, $user, $namespace);
300
301
        $assessments = [];
302
        while ($result = $resultQuery->fetchAssociative()) {
303
            $class = '' == $result['class'] ? '' : $result['class'];
304
            $assessments[$class] = $result['count'];
305
        }
306
307
        // Cache and return.
308
        return $this->setCache($cacheKey, $assessments);
309
    }
310
}
311