Passed
Push — master ( 16bc58...e2c4be )
by MusikAnimal
05:53
created

ArticleInfoRepository   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 69
dl 0
loc 166
rs 10
c 0
b 0
f 0
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getTransclusionData() 0 31 3
A getTopEditorsByEditCount() 0 49 3
A getBotData() 0 31 2
A getLogEvents() 0 19 2
1
<?php
2
/**
3
 * This file contains only the ArticleInfoRepository class.
4
 */
5
6
declare(strict_types = 1);
7
8
namespace AppBundle\Repository;
9
10
use AppBundle\Model\Page;
11
use Doctrine\DBAL\Driver\Statement;
12
13
/**
14
 * ArticleInfoRepository is responsible for retrieving data about a single
15
 * article on a given wiki.
16
 * @codeCoverageIgnore
17
 */
18
class ArticleInfoRepository extends Repository
19
{
20
    /**
21
     * Get the number of edits made to the page by bots or former bots.
22
     * @param Page $page
23
     * @param false|int $start
24
     * @param false|int $end
25
     * @return Statement resolving with keys 'count', 'username' and 'current'.
26
     */
27
    public function getBotData(Page $page, $start, $end): Statement
28
    {
29
        $cacheKey = $this->getCacheKey(func_get_args(), 'page_botdata');
30
        if ($this->cache->hasItem($cacheKey)) {
31
            return $this->cache->getItem($cacheKey)->get();
32
        }
33
34
        $project = $page->getProject();
35
        $revTable = $project->getTableName('revision');
36
        $userGroupsTable = $project->getTableName('user_groups');
37
        $userFormerGroupsTable = $project->getTableName('user_former_groups');
38
        $actorTable = $project->getTableName('actor');
39
40
        $datesConditions = $this->getDateConditions($start, $end);
41
42
        $sql = "SELECT COUNT(DISTINCT(rev_id)) AS count, actor_name AS username, '1' AS current
43
                FROM $revTable
44
                JOIN $actorTable ON actor_id = rev_actor
45
                LEFT JOIN $userGroupsTable ON actor_user = ug_user
46
                WHERE rev_page = :pageId AND ug_group = 'bot' $datesConditions
47
                GROUP BY actor_user
48
                UNION
49
                SELECT COUNT(DISTINCT(rev_id)) AS count, actor_name AS username, '0' AS current
50
                FROM $revTable
51
                JOIN $actorTable ON actor_id = rev_actor
52
                LEFT JOIN $userFormerGroupsTable ON actor_user = ufg_user
53
                WHERE rev_page = :pageId AND ufg_group = 'bot' $datesConditions
54
                GROUP BY actor_user";
55
56
        $result = $this->executeProjectsQuery($sql, ['pageId' => $page->getId()]);
57
        return $this->setCache($cacheKey, $result);
58
    }
59
60
    /**
61
     * Get prior deletions, page moves, and protections to the page.
62
     * @param Page $page
63
     * @param false|int $start
64
     * @param false|int $end
65
     * @return string[] each entry with keys 'log_action', 'log_type' and 'timestamp'.
66
     */
67
    public function getLogEvents(Page $page, $start, $end): array
68
    {
69
        $cacheKey = $this->getCacheKey(func_get_args(), 'page_logevents');
70
        if ($this->cache->hasItem($cacheKey)) {
71
            return $this->cache->getItem($cacheKey)->get();
72
        }
73
        $loggingTable = $page->getProject()->getTableName('logging', 'logindex');
74
75
        $datesConditions = $this->getDateConditions($start, $end, '', 'log_timestamp');
76
77
        $sql = "SELECT log_action, log_type, log_timestamp AS 'timestamp'
78
                FROM $loggingTable
79
                WHERE log_namespace = '" . $page->getNamespace() . "'
80
                AND log_title = :title AND log_timestamp > 1 $datesConditions
81
                AND log_type IN ('delete', 'move', 'protect', 'stable')";
82
        $title = str_replace(' ', '_', $page->getTitle());
83
84
        $result = $this->executeProjectsQuery($sql, ['title' => $title])->fetchAll();
85
        return $this->setCache($cacheKey, $result);
86
    }
87
88
    /**
89
     * Get the number of categories, templates, and files that are on the page.
90
     * @param Page $page
91
     * @return array With keys 'categories', 'templates' and 'files'.
92
     */
93
    public function getTransclusionData(Page $page): array
94
    {
95
        $cacheKey = $this->getCacheKey(func_get_args(), 'page_transclusions');
96
        if ($this->cache->hasItem($cacheKey)) {
97
            return $this->cache->getItem($cacheKey)->get();
98
        }
99
100
        $categorylinksTable = $page->getProject()->getTableName('categorylinks');
101
        $templatelinksTable = $page->getProject()->getTableName('templatelinks');
102
        $imagelinksTable = $page->getProject()->getTableName('imagelinks');
103
        $sql = "(
104
                    SELECT 'categories' AS `key`, COUNT(*) AS val
105
                    FROM $categorylinksTable
106
                    WHERE cl_from = :pageId
107
                ) UNION (
108
                    SELECT 'templates' AS `key`, COUNT(*) AS val
109
                    FROM $templatelinksTable
110
                    WHERE tl_from = :pageId
111
                ) UNION (
112
                    SELECT 'files' AS `key`, COUNT(*) AS val
113
                    FROM $imagelinksTable
114
                    WHERE il_from = :pageId
115
                )";
116
        $resultQuery = $this->executeProjectsQuery($sql, ['pageId' => $page->getId()]);
117
        $transclusionCounts = [];
118
119
        while ($result = $resultQuery->fetch()) {
120
            $transclusionCounts[$result['key']] = (int)$result['val'];
121
        }
122
123
        return $this->setCache($cacheKey, $transclusionCounts);
124
    }
125
126
    /**
127
     * Get the top editors to the page by edit count.
128
     * @param Page $page
129
     * @param false|int $start
130
     * @param false|int $end
131
     * @param int $limit
132
     * @param bool $noBots
133
     * @return array
134
     */
135
    public function getTopEditorsByEditCount(
136
        Page $page,
137
        $start = false,
138
        $end = false,
139
        int $limit = 20,
140
        bool $noBots = false
141
    ): array {
142
        $cacheKey = $this->getCacheKey(func_get_args(), 'page_topeditors');
143
        if ($this->cache->hasItem($cacheKey)) {
144
            return $this->cache->getItem($cacheKey)->get();
145
        }
146
147
        $project = $page->getProject();
148
        // Faster to use revision instead of revision_userindex in this case.
149
        $revTable = $project->getTableName('revision', '');
150
        $actorTable = $project->getTableName('actor');
151
152
        $dateConditions = $this->getDateConditions($start, $end);
153
154
        $sql = "SELECT actor_name AS username,
155
                    COUNT(rev_id) AS count,
156
                    SUM(rev_minor_edit) AS minor,
157
                    MIN(rev_timestamp) AS first_timestamp,
158
                    MIN(rev_id) AS first_revid,
159
                    MAX(rev_timestamp) AS latest_timestamp,
160
                    MAX(rev_id) AS latest_revid
161
                FROM $revTable
162
                JOIN $actorTable ON rev_actor = actor_id
163
                WHERE rev_page = :pageId $dateConditions";
164
165
        if ($noBots) {
166
            $userGroupsTable = $project->getTableName('user_groups');
167
            $sql .= "AND NOT EXISTS (
168
                         SELECT 1
169
                         FROM $userGroupsTable
170
                         WHERE ug_user = actor_user
171
                         AND ug_group = 'bot'
172
                     )";
173
        }
174
175
        $sql .= "GROUP BY actor_id
176
                 ORDER BY count DESC
177
                 LIMIT $limit";
178
179
        $result = $this->executeProjectsQuery($sql, [
180
            'pageId' => $page->getId(),
181
        ])->fetchAll();
182
183
        return $this->setCache($cacheKey, $result);
184
    }
185
}
186