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

PagesRepository::getPagesCreatedInnerSql()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 68
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 38
nc 12
nop 7
dl 0
loc 68
rs 9.0008
c 0
b 0
f 0

How to fix   Long Method   

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:

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