Passed
Push — master ( e61fe1...3dcafc )
by MusikAnimal
07:03
created

PagesRepository   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 119
dl 0
loc 287
rs 10
c 0
b 0
f 0
wmc 20

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getPagesCreated() 0 50 5
A getNamespaceRedirectAndDeletedPagesConditions() 0 20 4
A countPagesCreated() 0 39 2
A getPagesCreatedInnerSql() 0 67 5
A getAssessmentCounts() 0 48 4
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 string $start Start date in a format accepted by strtotime()
29
     * @param string $end End date in a format accepted by strtotime()
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
        string $start = '',
39
        string $end = ''
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($project, $user, '' !== $start.$end)
56
        );
57
58
        $sql = "SELECT namespace,
59
                    COUNT(page_title) AS count,
60
                    SUM(CASE WHEN type = 'arc' THEN 1 ELSE 0 END) AS deleted,
61
                    SUM(page_is_redirect) AS redirects
62
                FROM (".
63
                    $this->getPagesCreatedInnerSql($project, $conditions, $deleted, $start, $end, true)."
64
                ) a ".
65
                "GROUP BY namespace";
66
67
        $result = $this->executeQuery($sql, $project, $user, $namespace, $start, $end)->fetchAll();
68
69
        // Cache and return.
70
        return $this->setCache($cacheKey, $result);
71
    }
72
73
    /**
74
     * Get pages created by a user.
75
     * @param Project $project
76
     * @param User $user
77
     * @param string|int $namespace Namespace ID or 'all'.
78
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
79
     * @param string $deleted One of 'live', 'deleted' or blank for both.
80
     * @param string $start Start date in a format accepted by strtotime()
81
     * @param string $end End date in a format accepted by strtotime()
82
     * @param int|null $limit Number of results to return, or blank to return all.
83
     * @param int $offset Number of results past the initial dataset. Used for pagination.
84
     * @return string[] Result of query, see below. Includes live and deleted pages.
85
     */
86
    public function getPagesCreated(
87
        Project $project,
88
        User $user,
89
        $namespace,
90
        string $redirects,
91
        string $deleted,
92
        string $start = '',
93
        string $end = '',
94
        $limit = 1000,
95
        $offset = 0
96
    ): array {
97
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_pages_created');
98
        if ($this->cache->hasItem($cacheKey)) {
99
            return $this->cache->getItem($cacheKey)->get();
100
        }
101
102
        $conditions = [
103
            'paSelects' => '',
104
            'paSelectsArchive' => '',
105
            'paJoin' => '',
106
            'revPageGroupBy' => '',
107
        ];
108
109
        $conditions = array_merge(
110
            $conditions,
111
            $this->getNamespaceRedirectAndDeletedPagesConditions($namespace, $redirects),
112
            $this->getUserConditions($project, $user, '' !== $start.$end)
113
        );
114
115
        $pageAssessmentsTable = $project->getTableName('page_assessments');
116
117
        $hasPageAssessments = $this->isLabs() && $project->hasPageAssessments();
118
        if ($hasPageAssessments) {
119
            $conditions['paSelects'] = ', pa_class, pa_importance, pa_page_revision';
120
            $conditions['paSelectsArchive'] = ', NULL AS pa_class, NULL AS pa_page_id, '.
121
                'NULL AS pa_page_revision';
122
            $conditions['paJoin'] = "LEFT JOIN $pageAssessmentsTable ON rev_page = pa_page_id";
123
            $conditions['revPageGroupBy'] = 'GROUP BY rev_page';
124
        }
125
126
        $sql = "SELECT * FROM (".
127
                    $this->getPagesCreatedInnerSql($project, $conditions, $deleted, $start, $end)."
128
                ) a ".
129
                "ORDER BY rev_timestamp DESC
130
                ".(!empty($limit) ? "LIMIT $limit OFFSET $offset" : '');
131
132
        $result = $this->executeQuery($sql, $project, $user, $namespace, $start, $end)->fetchAll();
133
134
        // Cache and return.
135
        return $this->setCache($cacheKey, $result);
136
    }
137
138
    /**
139
     * Get SQL fragments for the namespace and redirects,
140
     * to be used in self::getPagesCreatedInnerSql().
141
     * @param string|int $namespace Namespace ID or 'all'.
142
     * @param string $redirects One of 'noredirects', 'onlyredirects' or blank for both.
143
     * @return string[] With keys 'namespaceRev', 'namespaceArc' and 'redirects'
144
     */
145
    private function getNamespaceRedirectAndDeletedPagesConditions($namespace, string $redirects): array
146
    {
147
        $conditions = [
148
            'namespaceArc' => '',
149
            'namespaceRev' => '',
150
            'redirects' => '',
151
        ];
152
153
        if ('all' !== $namespace) {
154
            $conditions['namespaceRev'] = " AND page_namespace = '".intval($namespace)."' ";
155
            $conditions['namespaceArc'] = " AND ar_namespace = '".intval($namespace)."' ";
156
        }
157
158
        if ('onlyredirects' == $redirects) {
159
            $conditions['redirects'] = " AND page_is_redirect = '1' ";
160
        } elseif ('noredirects' == $redirects) {
161
            $conditions['redirects'] = " AND page_is_redirect = '0' ";
162
        }
163
164
        return $conditions;
165
    }
166
167
    /**
168
     * Inner SQL for getting or counting pages created by the user.
169
     * @param Project $project
170
     * @param string[] $conditions Conditions for the SQL, must include 'paSelects',
171
     *     'paSelectsArchive', 'paJoin', 'whereRev', 'whereArc', 'namespaceRev', 'namespaceArc',
172
     *     'redirects' and 'revPageGroupBy'.
173
     * @param string $deleted One of 'live', 'deleted' or blank for both.
174
     * @param string $start Start date in a format accepted by strtotime()
175
     * @param string $end End date in a format accepted by strtotime()
176
     * @param bool $count Omit unneeded columns from the SELECT clause.
177
     * @return string Raw SQL.
178
     */
179
    private function getPagesCreatedInnerSql(
180
        Project $project,
181
        array $conditions,
182
        string $deleted,
183
        string $start = '',
184
        string $end = '',
185
        bool $count = false
186
    ): string {
187
        $pageTable = $project->getTableName('page');
188
        $revisionTable = $project->getTableName('revision');
189
        $archiveTable = $project->getTableName('archive');
190
        $logTable = $project->getTableName('logging', 'logindex');
191
192
        // Only SELECT things that are needed, based on whether or not we're doing a COUNT.
193
        $revSelects = "DISTINCT page_namespace AS `namespace`, 'rev' AS `type`, page_title, page_is_redirect";
194
        if (false === $count) {
195
            $revSelects .= ", page_len, rev_timestamp, rev_len, rev_id, NULL AS `recreated` ";
196
        }
197
198
        [$revCondBegin, $revCondEnd] = $this->getRevTimestampConditions($start, $end);
199
        [$arCondBegin, $arCondEnd] = $this->getRevTimestampConditions($start, $end, '', true);
200
201
        $revisionsSelect = "
202
            SELECT $revSelects ".$conditions['paSelects']."
203
            FROM $pageTable
204
            JOIN $revisionTable ON page_id = rev_page ".
205
            $conditions['paJoin']."
206
            WHERE ".$conditions['whereRev']."
207
                AND rev_parent_id = '0'".
208
                $conditions['namespaceRev'].
209
                $conditions['redirects'].
210
                $revCondBegin.
211
                $revCondEnd.
212
            $conditions['revPageGroupBy'];
213
214
        // Only SELECT things that are needed, based on whether or not we're doing a COUNT.
215
        $arSelects = "ar_namespace AS `namespace`, 'arc' AS `type`, ar_title AS page_title, '0' AS page_is_redirect";
216
        if (false === $count) {
217
            $arSelects .= ", NULL AS page_len, MIN(ar_timestamp) AS rev_timestamp, ".
218
                "ar_len AS rev_len, ar_rev_id AS rev_id, EXISTS(
219
                    SELECT 1 FROM $pageTable
220
                    WHERE page_namespace = ar_namespace
221
                    AND page_title = ar_title
222
                ) AS `recreated`";
223
        }
224
225
        $archiveSelect = "
226
            SELECT $arSelects ".$conditions['paSelectsArchive']."
227
            FROM $archiveTable
228
            LEFT JOIN $logTable ON log_namespace = ar_namespace AND log_title = ar_title
229
                AND log_user = ar_user AND (log_action = 'move' OR log_action = 'move_redir')
230
                AND log_type = 'move'
231
            WHERE ".$conditions['whereArc']."
232
                AND ar_parent_id = '0' ".
233
                $conditions['namespaceArc']."
234
                AND log_action IS NULL
235
                $arCondBegin
236
                $arCondEnd
237
            GROUP BY ar_namespace, ar_title";
238
239
        if ('live' == $deleted) {
240
            return $revisionsSelect;
241
        } elseif ('deleted' == $deleted) {
242
            return $archiveSelect;
243
        }
244
245
        return "($revisionsSelect) UNION ($archiveSelect)";
246
    }
247
248
    /**
249
     * Get the number of pages the user created by assessment.
250
     * @param Project $project
251
     * @param User $user
252
     * @param int|string $namespace
253
     * @param string $redirects
254
     * @param string $start Start date in a format accepted by strtotime()
255
     * @param string $end End date in a format accepted by strtotime()
256
     * @return array Keys are the assessment class, values are the counts.
257
     */
258
    public function getAssessmentCounts(
259
        Project $project,
260
        User $user,
261
        $namespace,
262
        string $redirects,
263
        string $start = '',
264
        string $end = ''
265
    ): array {
266
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_pages_created_assessments');
267
        if ($this->cache->hasItem($cacheKey)) {
268
            return $this->cache->getItem($cacheKey)->get();
269
        }
270
271
        $pageTable = $project->getTableName('page');
272
        $revisionTable = $project->getTableName('revision');
273
        $pageAssessmentsTable = $project->getTableName('page_assessments');
274
275
        $conditions = array_merge(
276
            $this->getNamespaceRedirectAndDeletedPagesConditions($namespace, $redirects),
277
            $this->getUserConditions($project, $user, '' !== $start.$end)
278
        );
279
        [$revCondBegin, $revCondEnd] = $this->getRevTimestampConditions($start, $end);
280
281
        $sql = "SELECT pa_class AS `class`, COUNT(pa_class) AS `count` FROM (
282
                    SELECT DISTINCT page_id, IFNULL(pa_class, '') AS pa_class
283
                    FROM $pageTable
284
                    JOIN $revisionTable ON page_id = rev_page
285
                    LEFT JOIN $pageAssessmentsTable ON rev_page = pa_page_id
286
                    WHERE ".$conditions['whereRev']."
287
                    AND rev_parent_id = '0'".
288
                    $conditions['namespaceRev'].
289
                    $conditions['redirects'].
290
                    $revCondBegin.
291
                    $revCondEnd."
292
                    GROUP BY page_id
293
                ) a
294
                GROUP BY pa_class";
295
296
        $resultQuery = $this->executeProjectsQuery($sql);
297
298
        $assessments = [];
299
        while ($result = $resultQuery->fetch()) {
300
            $class = '' == $result['class'] ? '' : $result['class'];
301
            $assessments[$class] = $result['count'];
302
        }
303
304
        // Cache and return.
305
        return $this->setCache($cacheKey, $assessments);
306
    }
307
}
308