Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.30% covered (success)
96.30%
52 / 54
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ScoreFetcher
96.30% covered (success)
96.30%
52 / 54
83.33% covered (warning)
83.33%
5 / 6
14
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getScores
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 checkAndUpdateModels
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 checkModelVersion
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
4.18
 updateModelVersion
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 instance
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16
17namespace ORES\Services;
18
19use InvalidArgumentException;
20use MediaWiki\MediaWikiServices;
21use MediaWiki\Request\WebRequest;
22use ORES\ORESService;
23use ORES\ServiceScoreLookup;
24use Wikimedia\Rdbms\IConnectionProvider;
25
26class ScoreFetcher implements ServiceScoreLookup {
27
28    private IConnectionProvider $dbProvider;
29
30    public function __construct( IConnectionProvider $dbProvider ) {
31        $this->dbProvider = $dbProvider;
32    }
33
34    /**
35     * @see ServiceScoreLookup::getScores()
36     *
37     * @param int|int[] $revisions Single or multiple revision IDs
38     * @param string|string[]|null $models Single or multiple model names. If
39     * left empty, all configured models are queried.
40     * @param bool $precache either the request is made for precaching or not
41     * @param WebRequest|string[]|null $originalRequest
42     *
43     * @return array Results in the form returned by ORES API
44     */
45    public function getScores(
46        $revisions,
47        $models = null,
48        $precache = false,
49        $originalRequest = null
50    ) {
51        if ( !$models ) {
52            global $wgOresModels;
53            $models = array_keys( array_filter( $wgOresModels, static function ( $model ) {
54                return $model['enabled'];
55            } ) );
56        }
57
58        $params = [
59            'models' => implode( '|', (array)$models ),
60            'revids' => implode( '|', (array)$revisions ),
61        ];
62        if ( $precache === true ) {
63            $params['precache'] = true;
64        }
65
66        $wireData = ORESServices::getORESService()->request( $params, $originalRequest );
67
68        $wikiId = ORESService::getWikiID();
69        if ( array_key_exists( 'models', $wireData[$wikiId] ) ) {
70            $this->checkAndUpdateModels( $wireData[$wikiId]['models'] );
71        }
72
73        return $wireData[$wikiId]['scores'];
74    }
75
76    /**
77     * @param array[] $modelData Model information returned by the API
78     */
79    private function checkAndUpdateModels( array $modelData ) {
80        foreach ( $modelData as $model => $modelOutputs ) {
81            $responseVersion = $this->checkModelVersion( $model, $modelOutputs );
82            if ( $responseVersion !== null ) {
83                $this->updateModelVersion( $model, $responseVersion );
84            }
85        }
86    }
87
88    /**
89     * @param string $model API response
90     * @param array $modelOutputs
91     * @return null|string return null if the versions match, otherwise return
92     * the new model version to update to
93     */
94    public function checkModelVersion( $model, array $modelOutputs ) {
95        if ( !array_key_exists( 'version', $modelOutputs ) ) {
96            return null;
97        }
98
99        try {
100            $storageVersion = ORESServices::getModelLookup()->getModelVersion( $model );
101        } catch ( InvalidArgumentException $exception ) {
102            $storageVersion = null;
103        }
104
105        $responseVersion = $modelOutputs['version'];
106
107        if ( $storageVersion === $responseVersion ) {
108            return null;
109        }
110
111        return $responseVersion;
112    }
113
114    /**
115     * @param string $model
116     * @param string $responseVersion
117     */
118    public function updateModelVersion( $model, $responseVersion ) {
119        // TODO: Move to ModelStorage service
120        $dbw = $this->dbProvider->getPrimaryDatabase();
121        $dbw->newUpdateQueryBuilder()
122            ->update( 'ores_model' )
123            ->set( [ 'oresm_is_current' => 0 ] )
124            ->where( [
125                'oresm_name' => $model,
126                $dbw->expr( 'oresm_version', '!=', $responseVersion ),
127            ] )
128            ->caller( __METHOD__ )
129            ->execute();
130
131        $dbw->newInsertQueryBuilder()
132            ->insertInto( 'ores_model' )
133            ->row( [
134                'oresm_name' => $model,
135                'oresm_version' => $responseVersion,
136                'oresm_is_current' => 1,
137            ] )
138            ->onDuplicateKeyUpdate()
139            ->uniqueIndexFields( [ 'oresm_name', 'oresm_version' ] )
140            ->set( [
141                'oresm_is_current' => 1,
142            ] )
143            ->caller( __METHOD__ )
144            ->execute();
145    }
146
147    public static function instance() {
148        return new self( MediaWikiServices::getInstance()->getConnectionProvider() );
149    }
150
151}