Passed
Push — master ( 9c530b...98dfb9 )
by MusikAnimal
06:42
created

PagesRepository::getUserConditions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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