Passed
Push — master ( ff20a1...14633b )
by MusikAnimal
04:24
created

PagesRepository   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 120
dl 0
loc 278
rs 10
c 0
b 0
f 0
wmc 22

6 Methods

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