Passed
Pull Request — master (#125)
by MusikAnimal
03:53
created

EditCounterRepository::getRevisions()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 53
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 28
nc 4
nop 3
dl 0
loc 53
rs 8.9849
c 0
b 0
f 0

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
 * This file contains only the EditCounterRepository class.
4
 */
5
6
namespace Xtools;
7
8
use DateInterval;
9
use DateTime;
10
use Mediawiki\Api\SimpleRequest;
11
12
/**
13
 * An EditCounterRepository is responsible for retrieving edit count information from the
14
 * databases and API. It doesn't do any post-processing of that information.
15
 * @codeCoverageIgnore
16
 */
17
class EditCounterRepository extends Repository
18
{
19
20
    /**
21
     * Get data about revisions, pages, etc.
22
     * @param Project $project The project.
23
     * @param User $user The user.
24
     * @returns string[] With keys: 'deleted', 'live', 'total', 'first', 'last', '24h', '7d', '30d',
25
     * '365d', 'small', 'large', 'with_comments', and 'minor_edits', ...
26
     */
27
    public function getPairData(Project $project, User $user)
28
    {
29
        // Set up cache.
30
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_pairdata');
31
        if ($this->cache->hasItem($cacheKey)) {
32
            return $this->cache->getItem($cacheKey)->get();
33
        }
34
35
        // Prepare the queries and execute them.
36
        $archiveTable = $this->getTableName($project->getDatabaseName(), 'archive');
37
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
38
        $queries = "
39
40
            -- Revision counts.
41
            (SELECT 'deleted' AS `key`, COUNT(ar_id) AS val FROM $archiveTable
42
                WHERE ar_user = :userId
43
            ) UNION (
44
            SELECT 'live' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
45
                WHERE rev_user = :userId
46
            ) UNION (
47
            SELECT 'day' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
48
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(), INTERVAL 1 DAY)
49
            ) UNION (
50
            SELECT 'week' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
51
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(), INTERVAL 1 WEEK)
52
            ) UNION (
53
            SELECT 'month' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
54
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
55
            ) UNION (
56
            SELECT 'year' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
57
                WHERE rev_user = :userId AND rev_timestamp >= DATE_SUB(NOW(), INTERVAL 1 YEAR)
58
            ) UNION (
59
            SELECT 'with_comments' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
60
                WHERE rev_user = :userId AND rev_comment != ''
61
            ) UNION (
62
            SELECT 'minor' AS `key`, COUNT(rev_id) AS val FROM $revisionTable
63
                WHERE rev_user = :userId AND rev_minor_edit = 1
64
65
            -- Dates.
66
            ) UNION (
67
            SELECT 'first' AS `key`, rev_timestamp AS `val` FROM $revisionTable
68
                WHERE rev_user = :userId ORDER BY rev_timestamp ASC LIMIT 1
69
            ) UNION (
70
            SELECT 'last' AS `key`, rev_timestamp AS `date` FROM $revisionTable
71
                WHERE rev_user = :userId ORDER BY rev_timestamp DESC LIMIT 1
72
73
            -- Page counts.
74
            ) UNION (
75
            SELECT 'edited-live' AS `key`, COUNT(DISTINCT rev_page) AS `val`
76
                FROM $revisionTable
77
                WHERE rev_user = :userId
78
            ) UNION (
79
            SELECT 'edited-deleted' AS `key`, COUNT(DISTINCT ar_page_id) AS `val`
80
                FROM $archiveTable
81
                WHERE ar_user = :userId
82
            ) UNION (
83
            SELECT 'created-live' AS `key`, COUNT(DISTINCT rev_page) AS `val`
84
                FROM $revisionTable
85
                WHERE rev_user = :userId AND rev_parent_id = 0
86
            ) UNION (
87
            SELECT 'created-deleted' AS `key`, COUNT(DISTINCT ar_page_id) AS `val`
88
                FROM $archiveTable
89
                WHERE ar_user = :userId AND ar_parent_id = 0
90
            )
91
        ";
92
        $resultQuery = $this->getProjectsConnection()->prepare($queries);
93
        $userId = $user->getId($project);
94
        $resultQuery->bindParam("userId", $userId);
95
        $resultQuery->execute();
96
        $revisionCounts = [];
97
        while ($result = $resultQuery->fetch()) {
98
            $revisionCounts[$result['key']] = $result['val'];
99
        }
100
101
        // Cache for 10 minutes, and return.
102
        $cacheItem = $this->cache->getItem($cacheKey)
103
                ->set($revisionCounts)
104
                ->expiresAfter(new DateInterval('PT10M'));
105
        $this->cache->save($cacheItem);
106
107
        return $revisionCounts;
108
    }
109
110
    /**
111
     * Get log totals for a user.
112
     * @param Project $project The project.
113
     * @param User $user The user.
114
     * @return integer[] Keys are "<log>-<action>" strings, values are counts.
115
     */
116
    public function getLogCounts(Project $project, User $user)
117
    {
118
        // Set up cache.
119
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_logcounts');
120
        if ($this->cache->hasItem($cacheKey)) {
121
            return $this->cache->getItem($cacheKey)->get();
122
        }
123
        $this->stopwatch->start($cacheKey, 'XTools');
124
125
        // Query.
126
        $loggingTable = $this->getTableName($project->getDatabaseName(), 'logging');
127
        $sql = "
128
        (SELECT CONCAT(log_type, '-', log_action) AS source, COUNT(log_id) AS value
129
            FROM $loggingTable
130
            WHERE log_user = :userId
131
            GROUP BY log_type, log_action
132
        )";
133
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
134
        $userId = $user->getId($project);
135
        $resultQuery->bindParam('userId', $userId);
136
        $resultQuery->execute();
137
        $results = $resultQuery->fetchAll();
138
        $logCounts = array_combine(
139
            array_map(function ($e) {
140
                return $e['source'];
141
            }, $results),
142
            array_map(function ($e) {
143
                return $e['value'];
144
            }, $results)
145
        );
146
147
        // Make sure there is some value for each of the wanted counts.
148
        $requiredCounts = [
149
            'thanks-thank',
150
            'review-approve',
151
            'newusers-create2',
152
            'newusers-byemail',
153
            'patrol-patrol',
154
            'block-block',
155
            'block-reblock',
156
            'block-unblock',
157
            'protect-protect',
158
            'protect-modify',
159
            'protect-unprotect',
160
            'rights-rights',
161
            'move-move',
162
            'delete-delete',
163
            'delete-revision',
164
            'delete-restore',
165
            'import-import',
166
            'import-interwiki',
167
            'import-upload',
168
            'upload-upload',
169
            'upload-overwrite',
170
        ];
171
        foreach ($requiredCounts as $req) {
172
            if (!isset($logCounts[$req])) {
173
                $logCounts[$req] = 0;
174
            }
175
        }
176
177
        // Add Commons upload count, if applicable.
178
        $logCounts['files_uploaded_commons'] = 0;
179
        if ($this->isLabs()) {
180
            $commons = ProjectRepository::getProject('commonswiki', $this->container);
181
            $userId = $user->getId($commons);
182
            if ($userId) {
183
                $sql = "SELECT COUNT(log_id) FROM commonswiki_p.logging_userindex
184
                    WHERE log_type = 'upload' AND log_action = 'upload' AND log_user = :userId";
185
                $resultQuery = $this->getProjectsConnection()->prepare($sql);
186
                $resultQuery->bindParam('userId', $userId);
187
                $resultQuery->execute();
188
                $logCounts['files_uploaded_commons'] = $resultQuery->fetchColumn();
189
            }
190
        }
191
192
        // Cache for 10 minutes, and return.
193
        $cacheItem = $this->cache->getItem($cacheKey)
194
            ->set($logCounts)
195
            ->expiresAfter(new DateInterval('PT10M'));
196
        $this->cache->save($cacheItem);
197
        $this->stopwatch->stop($cacheKey);
198
199
        return $logCounts;
200
    }
201
202
    /**
203
     * Get data for all blocks set on the given user.
204
     * @param Project $project
205
     * @param User $user
206
     * @return array
207
     */
208 View Code Duplication
    public function getBlocksReceived(Project $project, User $user)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
    {
210
        $loggingTable = $this->getTableName($project->getDatabaseName(), 'logging', 'logindex');
211
        $sql = "SELECT log_action, log_timestamp, log_params FROM $loggingTable
212
                WHERE log_type = 'block'
213
                AND log_action IN ('block', 'reblock', 'unblock')
214
                AND log_timestamp > 0
215
                AND log_title = :username
216
                AND log_namespace = 2
217
                ORDER BY log_timestamp ASC";
218
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
219
        $username = str_replace(' ', '_', $user->getUsername());
220
        $resultQuery->bindParam('username', $username);
221
        $resultQuery->execute();
222
        return $resultQuery->fetchAll();
223
    }
224
225
    /**
226
     * Get a user's total edit count on all projects.
227
     * @see EditCounterRepository::globalEditCountsFromCentralAuth()
228
     * @see EditCounterRepository::globalEditCountsFromDatabases()
229
     * @param User $user The user.
230
     * @param Project $project The project to start from.
231
     * @return mixed[] Elements are arrays with 'project' (Project), and 'total' (int).
232
     */
233
    public function globalEditCounts(User $user, Project $project)
234
    {
235
        // Get the edit counts from CentralAuth or database.
236
        $editCounts = $this->globalEditCountsFromCentralAuth($user, $project);
237
        if ($editCounts === false) {
238
            $editCounts = $this->globalEditCountsFromDatabases($user, $project);
239
        }
240
241
        // Pre-populate all projects' metadata, to prevent each project call from fetching it.
242
        $project->getRepository()->getAll();
1 ignored issue
show
Bug introduced by
The method getAll() does not exist on Xtools\Repository. It seems like you code against a sub-type of Xtools\Repository such as Xtools\ProjectRepository. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

242
        $project->getRepository()->/** @scrutinizer ignore-call */ getAll();
Loading history...
243
244
        // Compile the output.
245
        $out = [];
246
        foreach ($editCounts as $editCount) {
247
            $out[] = [
248
                'project' => ProjectRepository::getProject($editCount['dbName'], $this->container),
249
                'total' => $editCount['total'],
250
            ];
251
        }
252
        return $out;
253
    }
254
255
    /**
256
     * Get a user's total edit count on one or more project.
257
     * Requires the CentralAuth extension to be installed on the project.
258
     *
259
     * @param User $user The user.
260
     * @param Project $project The project to start from.
261
     * @return mixed[] Elements are arrays with 'dbName' (string), and 'total' (int).
262
     */
263
    protected function globalEditCountsFromCentralAuth(User $user, Project $project)
264
    {
265
        // Set up cache and stopwatch.
266
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_globaleditcounts');
267
        if ($this->cache->hasItem($cacheKey)) {
268
            return $this->cache->getItem($cacheKey)->get();
269
        }
270
        $this->stopwatch->start($cacheKey, 'XTools');
271
272
        $this->log->debug(__METHOD__." Getting global edit counts from for ".$user->getUsername());
273
274
        // Load all projects, so it doesn't have to request metadata about each one as it goes.
275
        $project->getRepository()->getAll();
276
277
        $api = $this->getMediawikiApi($project);
278
        $params = [
279
            'meta' => 'globaluserinfo',
280
            'guiprop' => 'editcount|merged',
281
            'guiuser' => $user->getUsername(),
282
        ];
283
        $query = new SimpleRequest('query', $params);
284
        $result = $api->getRequest($query);
285
        if (!isset($result['query']['globaluserinfo']['merged'])) {
286
            return [];
287
        }
288
        $out = [];
289
        foreach ($result['query']['globaluserinfo']['merged'] as $result) {
290
            $out[] = [
291
                'dbName' => $result['wiki'],
292
                'total' => $result['editcount'],
293
            ];
294
        }
295
296
        // Cache for 10 minutes, and return.
297
        $cacheItem = $this->cache->getItem($cacheKey)
298
            ->set($out)
299
            ->expiresAfter(new DateInterval('PT10M'));
300
        $this->cache->save($cacheItem);
301
        $this->stopwatch->stop($cacheKey);
302
303
        return $out;
304
    }
305
306
    /**
307
     * Get total edit counts from all projects for this user.
308
     * @see EditCounterRepository::globalEditCountsFromCentralAuth()
309
     * @param User $user The user.
310
     * @param Project $project The project to start from.
311
     * @return mixed[] Elements are arrays with 'dbName' (string), and 'total' (int).
312
     */
313
    protected function globalEditCountsFromDatabases(User $user, Project $project)
314
    {
315
        $this->log->debug(__METHOD__." Getting global edit counts for ".$user->getUsername());
316
        $stopwatchName = 'globalRevisionCounts.'.$user->getUsername();
317
        $allProjects = $project->getRepository()->getAll();
318
        $topEditCounts = [];
319
        $username = $user->getUsername();
320
        foreach ($allProjects as $projectMeta) {
321
            $revisionTableName = $this->getTableName($projectMeta['dbName'], 'revision');
322
            $sql = "SELECT COUNT(rev_id) FROM $revisionTableName WHERE rev_user_text=:username";
323
            $stmt = $this->getProjectsConnection()->prepare($sql);
324
            $stmt->bindParam('username', $username);
325
            $stmt->execute();
326
            $total = (int)$stmt->fetchColumn();
327
            $topEditCounts[] = [
328
                'dbName' => $projectMeta['dbName'],
329
                'total' => $total,
330
            ];
331
            $this->stopwatch->lap($stopwatchName);
332
        }
333
        return $topEditCounts;
334
    }
335
336
    /**
337
     * Get the given user's total edit counts per namespace on the given project.
338
     * @param Project $project The project.
339
     * @param User $user The user.
340
     * @return integer[] Array keys are namespace IDs, values are the edit counts.
341
     */
342
    public function getNamespaceTotals(Project $project, User $user)
343
    {
344
        // Cache?
345
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_namespacetotals');
346
        $this->stopwatch->start($cacheKey, 'XTools');
347
        if ($this->cache->hasItem($cacheKey)) {
348
            return $this->cache->getItem($cacheKey)->get();
349
        }
350
351
        $userId = $user->getId($project);
352
353
        // Query.
354
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
355
        $pageTable = $this->getTableName($project->getDatabaseName(), 'page');
356
        $sql = "SELECT page_namespace, COUNT(rev_id) AS total
357
            FROM $pageTable p JOIN $revisionTable r ON (r.rev_page = p.page_id)
358
            WHERE r.rev_user = :id
359
            GROUP BY page_namespace";
360
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
361
        $resultQuery->bindParam(":id", $userId);
362
        $resultQuery->execute();
363
        $results = $resultQuery->fetchAll();
364
        $namespaceTotals = array_combine(array_map(function ($e) {
365
            return $e['page_namespace'];
366
        }, $results), array_map(function ($e) {
367
            return $e['total'];
368
        }, $results));
369
370
        // Cache and return.
371
        $cacheItem = $this->cache->getItem($cacheKey);
372
        $cacheItem->set($namespaceTotals);
373
        $cacheItem->expiresAfter(new DateInterval('PT15M'));
374
        $this->cache->save($cacheItem);
375
        $this->stopwatch->stop($cacheKey);
376
        return $namespaceTotals;
377
    }
378
379
    /**
380
     * Get revisions by this user.
381
     * @param Project[] $projects The projects.
382
     * @param User $user The user.
383
     * @param int $lim The maximum number of revisions to fetch from each project.
384
     * @return array|mixed
385
     */
386
    public function getRevisions($projects, User $user, $lim = 40)
387
    {
388
        // Check cache.
389
        $cacheKey = $this->getCacheKey('ec_globalcontribs.'.$user->getCacheKey().'.'.$lim);
390
        $this->stopwatch->start($cacheKey, 'XTools');
391
        if ($this->cache->hasItem($cacheKey)) {
392
            return $this->cache->getItem($cacheKey)->get();
393
        }
394
395
        // Assemble queries.
396
        $username = $user->getUsername();
397
        $queries = [];
398
        foreach ($projects as $project) {
399
            $revisionTable = $project->getTableName('revision');
400
            $pageTable = $project->getTableName('page');
401
            $sql = "SELECT
402
                    '".$project->getDatabaseName()."' AS project_name,
403
                    revs.rev_id AS id,
404
                    revs.rev_timestamp AS timestamp,
405
                    UNIX_TIMESTAMP(revs.rev_timestamp) AS unix_timestamp,
406
                    revs.rev_minor_edit AS minor,
407
                    revs.rev_deleted AS deleted,
408
                    revs.rev_len AS length,
409
                    (CAST(revs.rev_len AS SIGNED) - IFNULL(parentrevs.rev_len, 0)) AS length_change,
410
                    revs.rev_parent_id AS parent_id,
411
                    revs.rev_comment AS comment,
412
                    revs.rev_user_text AS username,
413
                    page.page_title,
414
                    page.page_namespace
415
                FROM $revisionTable AS revs
416
                    JOIN $pageTable AS page ON (rev_page = page_id)
417
                    LEFT JOIN $revisionTable AS parentrevs ON (revs.rev_parent_id = parentrevs.rev_id)
418
                WHERE revs.rev_user_text = :username
419
                ORDER BY revs.rev_timestamp DESC";
420
            if (is_numeric($lim)) {
421
                $sql .= " LIMIT $lim";
422
            }
423
            $queries[] = $sql;
424
        }
425
        $sql = "(\n" . join("\n) UNION (\n", $queries) . ")\n";
426
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
427
        $resultQuery->bindParam(":username", $username);
428
        $resultQuery->execute();
429
        $revisions = $resultQuery->fetchAll();
430
431
        // Cache this.
432
        $cacheItem = $this->cache->getItem($cacheKey);
433
        $cacheItem->set($revisions);
434
        $cacheItem->expiresAfter(new DateInterval('PT15M'));
435
        $this->cache->save($cacheItem);
436
437
        $this->stopwatch->stop($cacheKey);
438
        return $revisions;
439
    }
440
441
    /**
442
     * Get data for a bar chart of monthly edit totals per namespace.
443
     * @param Project $project The project.
444
     * @param User $user The user.
445
     * @return string[] [
446
     *                      [
447
     *                          'year' => <year>,
448
     *                          'month' => <month>,
449
     *                          'page_namespace' => <namespace>,
450
     *                          'count' => <count>,
451
     *                      ],
452
     *                      ...
453
     *                  ]
454
     */
455
    public function getMonthCounts(Project $project, User $user)
456
    {
457
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_monthcounts');
458
        $this->stopwatch->start($cacheKey, 'XTools');
459
        if ($this->cache->hasItem($cacheKey)) {
460
            return $this->cache->getItem($cacheKey)->get();
461
        }
462
463
        $username = $user->getUsername();
464
        $revisionTable = $project->getTableName('revision');
465
        $pageTable = $project->getTableName('page');
466
        $sql =
467
            "SELECT "
468
            . "     YEAR(rev_timestamp) AS `year`,"
469
            . "     MONTH(rev_timestamp) AS `month`,"
470
            . "     page_namespace,"
471
            . "     COUNT(rev_id) AS `count` "
472
            .  " FROM $revisionTable JOIN $pageTable ON (rev_page = page_id)"
473
            . " WHERE rev_user_text = :username"
474
            . " GROUP BY YEAR(rev_timestamp), MONTH(rev_timestamp), page_namespace";
475
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
476
        $resultQuery->bindParam(":username", $username);
477
        $resultQuery->execute();
478
        $totals = $resultQuery->fetchAll();
479
480
        $cacheItem = $this->cache->getItem($cacheKey);
481
        $cacheItem->expiresAfter(new DateInterval('PT10M'));
482
        $cacheItem->set($totals);
483
        $this->cache->save($cacheItem);
484
485
        $this->stopwatch->stop($cacheKey);
486
        return $totals;
487
    }
488
489
    /**
490
     * Get data for the timecard chart, with totals grouped by day and to the nearest two-hours.
491
     * @param Project $project
492
     * @param User $user
493
     * @return string[]
494
     */
495
    public function getTimeCard(Project $project, User $user)
496
    {
497
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_timecard');
498
        $this->stopwatch->start($cacheKey, 'XTools');
499
        if ($this->cache->hasItem($cacheKey)) {
500
            return $this->cache->getItem($cacheKey)->get();
501
        }
502
503
        $username = $user->getUsername();
504
        $hourInterval = 2;
505
        $xCalc = "ROUND(HOUR(rev_timestamp)/$hourInterval) * $hourInterval";
506
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
507
        $sql = "SELECT "
508
            . "     DAYOFWEEK(rev_timestamp) AS `y`, "
509
            . "     $xCalc AS `x`, "
510
            . "     COUNT(rev_id) AS `value` "
511
            . " FROM $revisionTable"
512
            . " WHERE rev_user_text = :username"
513
            . " GROUP BY DAYOFWEEK(rev_timestamp), $xCalc ";
514
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
515
        $resultQuery->bindParam(":username", $username);
516
        $resultQuery->execute();
517
        $totals = $resultQuery->fetchAll();
518
        // Scale the radii: get the max, then scale each radius.
519
        // This looks inefficient, but there's a max of 72 elements in this array.
520
        $max = 0;
521
        foreach ($totals as $total) {
522
            $max = max($max, $total['value']);
523
        }
524
        foreach ($totals as &$total) {
525
            $total['value'] = round($total['value'] / $max * 100);
526
        }
527
        $cacheItem = $this->cache->getItem($cacheKey);
528
        $cacheItem->expiresAfter(new DateInterval('PT10M'));
529
        $cacheItem->set($totals);
530
        $this->cache->save($cacheItem);
531
532
        $this->stopwatch->stop($cacheKey);
533
        return $totals;
534
    }
535
536
    /**
537
     * Get various data about edit sizes of the past 5,000 edits.
538
     * Will cache the result for 10 minutes.
539
     * @param Project $project The project.
540
     * @param User $user The user.
541
     * @return string[] Values with for keys 'average_size',
542
     *                  'small_edits' and 'large_edits'
543
     */
544
    public function getEditSizeData(Project $project, User $user)
545
    {
546
        // Set up cache.
547
        $cacheKey = $this->getCacheKey(func_get_args(), 'ec_editsizes');
548
        $this->stopwatch->start($cacheKey, 'XTools');
549
        if ($this->cache->hasItem($cacheKey)) {
550
            return $this->cache->getItem($cacheKey)->get();
551
        }
552
553
        // Prepare the queries and execute them.
554
        $revisionTable = $this->getTableName($project->getDatabaseName(), 'revision');
555
        $userId = $user->getId($project);
556
        $sql = "SELECT AVG(sizes.size) AS average_size,
557
                COUNT(CASE WHEN sizes.size < 20 THEN 1 END) AS small_edits,
558
                COUNT(CASE WHEN sizes.size > 1000 THEN 1 END) AS large_edits
559
                FROM (
560
                    SELECT (CAST(revs.rev_len AS SIGNED) - IFNULL(parentrevs.rev_len, 0)) AS size
561
                    FROM $revisionTable AS revs
562
                    LEFT JOIN $revisionTable AS parentrevs ON (revs.rev_parent_id = parentrevs.rev_id)
563
                    WHERE revs.rev_user = :userId
564
                    ORDER BY revs.rev_timestamp DESC
565
                    LIMIT 5000
566
                ) sizes";
567
        $resultQuery = $this->getProjectsConnection()->prepare($sql);
568
        $resultQuery->bindParam('userId', $userId);
569
        $resultQuery->execute();
570
        $results = $resultQuery->fetchAll()[0];
571
572
        // Cache for 10 minutes.
573
        $cacheItem = $this->cache->getItem($cacheKey);
574
        $cacheItem->set($results);
575
        $cacheItem->expiresAfter(new DateInterval('PT10M'));
576
        $this->cache->save($cacheItem);
577
578
        $this->stopwatch->stop($cacheKey);
579
        return $results;
580
    }
581
}
582