Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
TranslatorActivityQuery
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 3
30
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 inLanguage
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
6
 inAllLanguages
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Statistics;
5
6use Config;
7use MediaWiki\User\ActorMigration;
8use Wikimedia\Rdbms\ILoadBalancer;
9
10/**
11 * Gathers translator activity from the database.
12 *
13 * @author Niklas Laxström
14 * @license GPL-2.0-or-later
15 * @since 2020.04
16 */
17class TranslatorActivityQuery {
18    public const USER_NAME = 0;
19    public const USER_TRANSLATIONS = 1;
20    public const USER_LAST_ACTIVITY = 2;
21    private Config $options;
22    private ILoadBalancer $loadBalancer;
23
24    public function __construct( Config $options, ILoadBalancer $loadBalancer ) {
25        $this->options = $options;
26        $this->loadBalancer = $loadBalancer;
27    }
28
29    /**
30     * Fetch the translators for a language
31     *
32     * @param string $code Language tag
33     * @return array<int,array<string|int|string>> Translation stats per user
34     */
35    public function inLanguage( string $code ): array {
36        $dbr = $this->loadBalancer->getConnection( DB_REPLICA, 'vslow' );
37
38        $actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
39
40        $res = $dbr->newSelectQueryBuilder()
41            ->select( [
42                'rev_user_text' => $actorQuery['fields']['rev_user_text'],
43                'lastedit' => 'MAX(rev_timestamp)',
44                'count' => 'COUNT(page_id)',
45            ] )
46            ->from( 'page' )
47            ->join( 'revision', null, 'page_id=rev_page' )
48            ->tables( $actorQuery['tables'] )
49            ->where( [
50                'page_title' . $dbr->buildLike( $dbr->anyString(), '/', $code ),
51                'page_namespace' => $this->options->get( 'TranslateMessageNamespaces' ),
52            ] )
53            ->groupBy( $actorQuery['fields']['rev_user_text'] )
54            ->orderBy( 'NULL' )
55            ->joinConds( $actorQuery['joins'] )
56            ->caller( __METHOD__ )
57            ->fetchResultSet();
58
59        $data = [];
60        foreach ( $res as $row ) {
61            // Warning: user names may be numbers that get cast to ints in array keys
62            $data[] = [
63                self::USER_NAME => $row->rev_user_text,
64                self::USER_TRANSLATIONS => (int)$row->count,
65                self::USER_LAST_ACTIVITY => $row->lastedit,
66            ];
67        }
68
69        return $data;
70    }
71
72    /**
73     * Fetch the translators for all languages.
74     *
75     * This is faster than doing each language separately.
76     *
77     * @return array<string,array<int,array<string|int|string>>> Map of language tags to
78     * translation stats per user
79     */
80    public function inAllLanguages(): array {
81        $dbr = $this->loadBalancer->getConnection( DB_REPLICA, 'vslow' );
82
83        $actorQuery = ActorMigration::newMigration()->getJoin( 'rev_user' );
84
85        $res = $dbr->newSelectQueryBuilder()
86            ->select( [
87                'rev_user_text' => $actorQuery['fields']['rev_user_text'],
88                'lang' => 'substring_index(page_title, \'/\', -1)',
89                'lastedit' => 'MAX(rev_timestamp)',
90                'count' => 'COUNT(page_id)',
91            ] )
92            ->from( 'page' )
93            ->join( 'revision', null, 'page_id=rev_page' )
94            ->tables( $actorQuery['tables'] )
95            ->where( [
96                'page_title' . $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() ),
97                'page_namespace' => $this->options->get( 'TranslateMessageNamespaces' ),
98            ] )
99            ->groupBy( [ 'lang', $actorQuery['fields']['rev_user_text'] ] )
100            ->orderBy( 'NULL' )
101            ->joinConds( $actorQuery['joins'] )
102            ->caller( __METHOD__ )
103            ->fetchResultSet();
104
105        $data = [];
106        foreach ( $res as $row ) {
107            // Warning: user names may be numbers that get cast to ints in array keys
108            $data[$row->lang][] = [
109                self::USER_NAME => $row->rev_user_text,
110                self::USER_TRANSLATIONS => (int)$row->count,
111                self::USER_LAST_ACTIVITY => $row->lastedit,
112            ];
113        }
114
115        return $data;
116    }
117}