Completed
Push — master ( 2389d9...58d132 )
by Sam
02:47
created

EditCounterHelper::getRevisionCounts()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 79
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 79
rs 8.8701
c 0
b 0
f 0
cc 3
eloc 37
nc 3
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace AppBundle\Helper;
4
5
use DateInterval;
6
use Doctrine\DBAL\Connection;
7
use Exception;
8
use Psr\Cache\CacheItemPoolInterface;
9
use Symfony\Component\DependencyInjection\Container;
10
11
class EditCounterHelper
12
{
13
14
    /** @var Container */
15
    protected $container;
16
17
    /** @var Connection */
18
    protected $replicas;
19
20
    /** @var LabsHelper */
21
    protected $labsHelper;
22
23
    /** @var CacheItemPoolInterface */
24
    protected $cache;
25
26
    public function __construct(Container $container)
27
    {
28
        $this->container = $container;
29
        $this->replicas = $container->get('doctrine')->getManager('replicas')->getConnection();
30
        $this->labsHelper = $container->get('app.labs_helper');
31
        $this->cache = $container->get('cache.app');
32
    }
33
34
    /**
35
     * Get the ID of a user.
36
     * @param string $usernameOrIp The username or IP address.
37
     * @return integer The user's ID.
38
     */
39
    public function getUserId($usernameOrIp)
40
    {
41
        // Use cache if possible.
42
        $cacheItem = $this->cache->getItem('ec.usernameOrIp.' . $usernameOrIp);
43
        if ($cacheItem->isHit()) {
44
            return $cacheItem->get();
45
        }
46
47
        $userTable = $this->labsHelper->getTable('user');
48
        $sql = "SELECT user_id FROM $userTable WHERE user_name = :username LIMIT 1";
49
        $resultQuery = $this->replicas->prepare($sql);
50
        $resultQuery->bindParam("username", $usernameOrIp);
51
        $resultQuery->execute();
52
        $userId = (int)$resultQuery->fetchColumn();
53
54
        // Save to cache.
55
        $cacheItem->expiresAfter(new DateInterval('P7D'));
56
        $cacheItem->set($userId);
57
        $this->cache->save($cacheItem);
58
59
        return $userId;
60
    }
61
62
    /**
63
     * Get revision counts for the given user.
64
     * @param integer $userId The user's ID.
65
     * @returns string[] With keys: 'archived', 'total', 'first', 'last', '24h', '7d', '30d', and
66
     * '365d'.
67
     * @throws Exception
68
     */
69
    public function getRevisionCounts($userId)
70
    {
71
        // Prepare the query and execute
72
        $archiveTable = $this->labsHelper->getTable('archive');
73
        $revisionTable = $this->labsHelper->getTable('revision');
74
        $resultQuery = $this->replicas->prepare("
75
            (SELECT 'deleted' as source, COUNT(ar_id) AS value FROM $archiveTable
76
                WHERE ar_user = :userId)
77
            UNION
78
            (SELECT 'live' as source, COUNT(rev_id) AS value FROM $revisionTable
79
                WHERE rev_user = :userId)
80
            UNION
81
            (SELECT 'first' as source, rev_timestamp FROM $revisionTable
82
                WHERE rev_user = :userId ORDER BY rev_timestamp ASC LIMIT 1)
83
            UNION
84
            (SELECT 'last' as source, rev_timestamp FROM $revisionTable
85
                WHERE rev_user = :userId ORDER BY rev_timestamp DESC LIMIT 1)
86
            UNION
87
            (SELECT '24h' as source, COUNT(rev_id) as value FROM $revisionTable
88
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(),INTERVAL 24 HOUR))
89
            UNION
90
            (SELECT '7d' as source, COUNT(rev_id) as value FROM $revisionTable
91
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(),INTERVAL 7 DAY))
92
            UNION
93
            (SELECT '30d' as source, COUNT(rev_id) as value FROM $revisionTable
94
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(),INTERVAL 30 DAY))
95
            UNION
96
            (SELECT '365d' as source, COUNT(rev_id) as value FROM $revisionTable
97
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(),INTERVAL 365 DAY))
98
            UNION
99
            (SELECT 'small' AS source, COUNT(rev_id) AS value FROM $revisionTable
100
                WHERE rev_user = :userId AND rev_len < 20)
101
            UNION
102
            (SELECT 'large' AS source, COUNT(rev_id) AS value FROM $revisionTable
103
                WHERE rev_user = :userId AND rev_len > 1000)
104
            UNION
105
            (SELECT 'with_comments' AS source, COUNT(rev_id) AS value FROM $revisionTable
106
                WHERE rev_user = :userId AND rev_comment = '')
107
            UNION
108
            (SELECT 'minor_edits' AS source, COUNT(rev_id) AS value FROM $revisionTable
109
                WHERE rev_user = :userId AND rev_minor_edit = 1)
110
            ");
111
        $resultQuery->bindParam("userId", $userId);
112
        $resultQuery->execute();
113
        $results = $resultQuery->fetchAll();
114
115
        // Unknown user - This is a dirty hack that should be fixed.
116
        if (count($results) < 8) {
117
            throw new Exception("Unable to get all revision counts for user $userId");
118
        }
119
120
        $revisionCounts = array_combine(
121
            array_map(function ($e) {
122
                return $e['source'];
123
            }, $results),
124
            array_map(function ($e) {
125
                return $e['value'];
126
            }, $results)
127
        );
128
129
        // Count the number of days, accounting for when there's only one edit.
130
        $editingTimeInSeconds = ceil($revisionCounts['last'] - $revisionCounts['first']);
131
        $revisionCounts['days'] = $editingTimeInSeconds ? $editingTimeInSeconds/(60*60*24) : 1;
132
133
        // Format the first and last dates.
134
        $revisionCounts['first'] = date('Y-m-d H:i', strtotime($revisionCounts['first']));
135
        $revisionCounts['last'] = date('Y-m-d H:i', strtotime($revisionCounts['last']));
136
137
        // Sum deleted and live to make the total.
138
        $revisionCounts['total'] = $revisionCounts['deleted'] + $revisionCounts['live'];
139
        
140
        // Calculate the average number of live edits per day.
141
        $revisionCounts['avg_per_day'] = round(
142
            $revisionCounts['live'] / $revisionCounts['days'],
143
            3
144
        );
145
146
        return $revisionCounts;
147
    }
148
149
    /**
150
     *
151
     * @param $username
152
     * @return integer
153
     */
154
    public function getPageCounts($username, $totalRevisions)
155
    {
156
        $resultQuery = $this->replicas->prepare("
157
            SELECT 'unique' as source, COUNT(distinct rev_page) as value
158
                FROM ".$this->labsHelper->getTable('revision')." where rev_user_text=:username
159
            UNION
160
            SELECT 'created-live' as source, COUNT(*) as value from ".$this->labsHelper->getTable('revision')."
161
                WHERE rev_user_text=:username and rev_parent_id=0
162
            UNION
163
            SELECT 'created-deleted' as source, COUNT(*) as value from "
164
                                                .$this->labsHelper->getTable('archive')."
165
                WHERE ar_user_text=:username and ar_parent_id=0
166
            UNION
167
            SELECT 'moved' as source, count(*) as value from ".$this->labsHelper->getTable('logging')."
168
                WHERE log_type='move' and log_action='move' and log_user_text=:username
169
            ");
170
        $resultQuery->bindParam("username", $username);
171
        $resultQuery->execute();
172
        $results = $resultQuery->fetchAll();
173
174
        $pageCounts = array_combine(
175
            array_map(function ($e) {
176
                return $e['source'];
177
            }, $results),
178
            array_map(function ($e) {
179
                return $e['value'];
180
            }, $results)
181
        );
182
183
        // Total created.
184
        $pageCounts['created'] = $pageCounts['created-live'] + $pageCounts['created-deleted'];
185
186
        // Calculate the average number of edits per page.
187
        $pageCounts['edits_per_page'] = 0;
188
        if ($pageCounts['unique'] && $totalRevisions) {
189
            $pageCounts['edits_per_page'] = round($totalRevisions / $pageCounts['unique'], 3);
190
        }
191
192
        return $pageCounts;
193
    }
194
195
    /**
196
     * Get log totals for a user.
197
     * @param integer $userId The user ID.
198
     * @return integer[] Keys are log-action string, values are counts.
199
     */
200
    public function getLogCounts($userId)
201
    {
202
        $sql = "SELECT CONCAT(log_type, '-', log_action) AS source, COUNT(log_id) AS value
203
            FROM ".$this->labsHelper->getTable('logging')."
204
            WHERE log_user = :userId
205
            GROUP BY log_type, log_action";
206
        $resultQuery = $this->replicas->prepare($sql);
207
        $resultQuery->bindParam('userId', $userId);
208
        $resultQuery->execute();
209
        $results = $resultQuery->fetchAll();
210
        $logCounts = array_combine(
211
            array_map(function ($e) {
212
                return $e['source'];
213
            }, $results),
214
            array_map(function ($e) {
215
                return $e['value'];
216
            }, $results)
217
        );
218
219
        // Make sure there is some value for each of the wanted counts.
220
        $requiredCounts = [
221
            'thanks-thank', 'review-approve', 'patrol-patrol','block-block', 'block-unblock',
222
            'protect-protect', 'protect-unprotect', 'delete-delete', 'delete-revision',
223
            'delete-restore', 'import-import', 'upload-upload', 'upload-overwrite',
224
        ];
225
        foreach ($requiredCounts as $req) {
226
            if (!isset($logCounts[$req])) {
227
                $logCounts[$req] = 0;
228
            }
229
        }
230
231
        // Merge approvals together.
232
        $logCounts['review-approve'] = $logCounts['review-approve'] +
233
            (!empty($logCounts['review-approve-a']) ? $logCounts['review-approve-a'] : 0) +
234
            (!empty($logCounts['review-approve-i']) ? $logCounts['review-approve-i'] : 0) +
235
            (!empty($logCounts['review-approve-ia']) ? $logCounts['review-approve-ia'] : 0);
236
237
        // Add Commons upload count, if applicable.
238
        $logCounts['files_uploaded_commons'] = 0;
239
        if ($this->labsHelper->isLabs()) {
240
            $sql = "SELECT COUNT(log_id) FROM commonswiki_p.logging_userindex
241
                WHERE log_type = 'upload' AND log_action = 'upload' AND log_user = :userId";
242
            $resultQuery = $this->replicas->prepare($sql);
243
            $resultQuery->bindParam('userId', $userId);
244
            $resultQuery->execute();
245
            $logCounts['files_uploaded_commons'] = $resultQuery->fetchColumn();
246
        }
247
248
        return $logCounts;
249
    }
250
251
    /**
252
     * Get the given user's total edit counts per namespace.
253
     * @param integer $userId The ID of the user.
254
     * @return integer[] Array keys are namespace IDs, values are the edit counts.
255
     */
256
    public function getNamespaceTotals($userId)
257
    {
258
        $sql = "SELECT page_namespace, count(rev_id) AS total
259
            FROM ".$this->labsHelper->getTable('revision') ." r
260
                JOIN ".$this->labsHelper->getTable('page')." p on r.rev_page = p.page_id
261
            WHERE r.rev_user = :id GROUP BY page_namespace";
262
        $resultQuery = $this->replicas->prepare($sql);
263
        $resultQuery->bindParam(":id", $userId);
264
        $resultQuery->execute();
265
        $results = $resultQuery->fetchAll();
266
        $namespaceTotals = array_combine(
267
            array_map(function ($e) {
268
                return $e['page_namespace'];
269
            }, $results),
270
            array_map(function ($e) {
271
                return $e['total'];
272
            }, $results)
273
        );
274
        return $namespaceTotals;
275
    }
276
}
277