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