Passed
Push — master ( a1ed3f...a64a0e )
by
unknown
05:21
created

TopEditsRepository::getContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the TopEditsRepository class.
4
 */
5
6
namespace Xtools;
7
8
use Symfony\Component\DependencyInjection\Container;
9
10
/**
11
 * TopEditsRepository is responsible for retrieving data from the database
12
 * about the top-edited pages of a user. It doesn't do any post-processing
13
 * of that information.
14
 * @codeCoverageIgnore
15
 */
16
class TopEditsRepository extends Repository
17
{
18
    /**
19
     * Expose the container to the TopEdits class.
20
     * @return Container
21
     */
22
    public function getContainer()
23
    {
24
        return $this->container;
25
    }
26
27
    /**
28
     * Get the top edits by a user in a single namespace.
29
     * @param Project $project
30
     * @param User $user
31
     * @param int $namespace Namespace ID.
32
     * @param int $limit Number of edits to fetch.
33
     * @return string[] page_namespace, page_title, page_is_redirect,
34
     *   count (number of edits), assessment (page assessment).
35
     */
36
    public function getTopEditsNamespace(Project $project, User $user, $namespace = 0, $limit = 100)
37
    {
38
        // Set up cache.
39
        $cacheKey = $this->getCacheKey(func_get_args(), 'topedits_ns');
40
        if ($this->cache->hasItem($cacheKey)) {
41
            return $this->cache->getItem($cacheKey)->get();
42
        }
43
44
        $pageTable = $this->getTableName($project->getDatabaseName(), 'page');
45
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
46
47
        $hasPageAssessments = $this->isLabs() && $project->hasPageAssessments() && $namespace === 0;
48
        $paTable = $this->getTableName($project->getDatabaseName(), 'page_assessments');
49
        $paSelect = $hasPageAssessments
50
            ?  ", (
51
                    SELECT pa_class
52
                    FROM $paTable
53
                    WHERE pa_page_id = page_id
54
                    AND pa_class != 'Unknown'
55
                    LIMIT 1
56
                ) AS pa_class"
57
            : '';
58
59
        $sql = "SELECT page_namespace, page_title, page_is_redirect, COUNT(page_title) AS count
60
                    $paSelect
61
                FROM $pageTable JOIN $revisionTable ON page_id = rev_page
62
                WHERE rev_user_text = :username
63
                AND page_namespace = :namespace
64
                GROUP BY page_namespace, page_title
65
                ORDER BY count DESC
66
                LIMIT $limit";
67
        $result = $this->executeProjectsQuery($sql, [
68
            'username' => $user->getUsername(),
69
            'namespace' => $namespace,
70
        ])->fetchAll();
71
72
        // Cache and return.
73
        return $this->setCache($cacheKey, $result);
74
    }
75
76
    /**
77
     * Get the top edits by a user across all namespaces.
78
     * @param Project $project
79
     * @param User $user
80
     * @param int $limit Number of edits to fetch.
81
     * @return string[] page_namespace, page_title, page_is_redirect,
82
     *   count (number of edits), assessment (page assessment).
83
     */
84
    public function getTopEditsAllNamespaces(Project $project, User $user, $limit = 10)
85
    {
86
        // Set up cache.
87
        $cacheKey = $this->getCacheKey(func_get_args(), 'topedits_all');
88
        if ($this->cache->hasItem($cacheKey)) {
89
            return $this->cache->getItem($cacheKey)->get();
90
        }
91
92
        $pageTable = $this->getTableName($project->getDatabaseName(), 'page');
93
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
94
        $hasPageAssessments = $this->isLabs() && $project->hasPageAssessments();
95
        $pageAssessmentsTable = $this->getTableName($project->getDatabaseName(), 'page_assessments');
96
        $paSelect = $hasPageAssessments
97
            ?  ", (
98
                    SELECT pa_class
99
                    FROM $pageAssessmentsTable
100
                    WHERE pa_page_id = e.page_id
101
                    LIMIT 1
102
                ) AS pa_class"
103
            : ', NULL as pa_class';
104
105
        $sql = "SELECT c.page_namespace, e.page_title, c.page_is_redirect, c.count $paSelect
106
                FROM
107
                (
108
                    SELECT b.page_namespace, b.page_is_redirect, b.rev_page, b.count
109
                        ,@rn := if(@ns = b.page_namespace, @rn + 1, 1) AS row_number
110
                        ,@ns := b.page_namespace AS dummy
111
                    FROM
112
                    (
113
                        SELECT page_namespace, page_is_redirect, rev_page, count(rev_page) AS count
114
                        FROM $revisionTable
115
                        JOIN $pageTable ON page_id = rev_page
116
                        WHERE rev_user_text = :username
117
                        GROUP BY page_namespace, rev_page
118
                    ) AS b
119
                    JOIN (SELECT @ns := NULL, @rn := 0) AS vars
120
                    ORDER BY b.page_namespace ASC, b.count DESC
121
                ) AS c
122
                JOIN $pageTable e ON e.page_id = c.rev_page
123
                WHERE c.row_number < $limit";
124
        $result = $this->executeProjectsQuery($sql, [
125
            'username' => $user->getUsername(),
126
        ])->fetchAll();
127
128
        // Cache and return.
129
        return $this->setCache($cacheKey, $result);
130
    }
131
132
    /**
133
     * Get the top edits by a user to a single page.
134
     * @param Page $page
135
     * @param User $user
136
     * @return string[] Each row with keys 'id', 'timestamp', 'minor', 'length',
137
     *   'length_change', 'reverted', 'user_id', 'username', 'comment', 'parent_comment'
138
     */
139
    public function getTopEditsPage(Page $page, User $user)
140
    {
141
        // Set up cache.
142
        $cacheKey = $this->getCacheKey(func_get_args(), 'topedits_page');
143
        if ($this->cache->hasItem($cacheKey)) {
144
            return $this->cache->getItem($cacheKey)->get();
145
        }
146
147
        $results = $this->queryTopEditsPage($page, $user, true);
148
149
        // Now we need to get the most recent revision, since the childrevs stuff excludes it.
150
        $lastRev = $this->queryTopEditsPage($page, $user, false);
151
        if (empty($results) || $lastRev[0]['id'] !== $results[0]['id']) {
152
            $results = array_merge($lastRev, $results);
153
        }
154
155
        // Cache and return.
156
        return $this->setCache($cacheKey, $results);
157
    }
158
159
    /**
160
     * The actual query to get the top edits by the user to the page.
161
     * Because of the way the main query works, we aren't given the most recent revision,
162
     * so we have to call this twice, once with $childRevs set to true and once with false.
163
     * @param  Page    $page
164
     * @param  User    $user
165
     * @param  boolean $childRevs Whether to include child revisions.
166
     * @return string[] Each row with keys 'id', 'timestamp', 'minor', 'length',
167
     *   'length_change', 'reverted', 'user_id', 'username', 'comment', 'parent_comment'
168
     */
169
    private function queryTopEditsPage(Page $page, User $user, $childRevs = false)
170
    {
171
        $revTable = $this->getTableName($page->getProject()->getDatabaseName(), 'revision');
172
173
        if ($childRevs) {
174
            $childSelect = ', (CASE WHEN childrevs.rev_sha1 = parentrevs.rev_sha1 THEN 1 ELSE 0 END) AS reverted,
175
                    childrevs.rev_comment AS parent_comment';
176
            $childJoin = "LEFT JOIN $revTable AS childrevs ON (revs.rev_id = childrevs.rev_parent_id)";
177
            $childWhere = 'AND childrevs.rev_page = :pageid';
178
            $childLimit = '';
179
        } else {
180
            $childSelect = ', "" AS parent_comment, 0 AS reverted';
181
            $childJoin = '';
182
            $childWhere = '';
183
            $childLimit = 'LIMIT 1';
184
        }
185
186
        $sql = "SELECT
187
                    revs.rev_id AS id,
188
                    revs.rev_timestamp AS timestamp,
189
                    revs.rev_minor_edit AS minor,
190
                    revs.rev_len AS length,
191
                    (CAST(revs.rev_len AS SIGNED) - IFNULL(parentrevs.rev_len, 0)) AS length_change,
192
                    revs.rev_user AS user_id,
193
                    revs.rev_user_text AS username,
194
                    revs.rev_comment AS comment
195
                    $childSelect
196
                FROM $revTable AS revs
197
                LEFT JOIN $revTable AS parentrevs ON (revs.rev_parent_id = parentrevs.rev_id)
198
                $childJoin
199
                WHERE revs.rev_user_text = :username
200
                AND revs.rev_page = :pageid
201
                $childWhere
202
                ORDER BY revs.rev_timestamp DESC
203
                $childLimit";
204
205
        return $this->executeProjectsQuery($sql, [
206
            'pageid' => $page->getId(),
207
            'username' => $user->getUsername(),
208
        ])->fetchAll();
209
    }
210
211
    /**
212
     * Get the display titles of the given pages.
213
     * @param Project $project
214
     * @param  string[] $titles List of page titles.
215
     * @return string[] Keys are the original supplied titles, and values are the display titles.
216
     */
217
    public function getDisplayTitles(Project $project, $titles)
218
    {
219
        return PageRepository::displayTitles($project, $titles);
220
    }
221
}
222