Passed
Push — master ( 980a19...125389 )
by MusikAnimal
05:36
created

PageAssessments::getClassFromAssessment()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.3073

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 3
nop 1
dl 0
loc 26
ccs 10
cts 13
cp 0.7692
crap 5.3073
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the PageAssessments class.
4
 */
5
6
namespace Xtools;
7
8
/**
9
 * A PageAssessments is responsible for handling logic around
10
 * processing page assessments of a given set of Pages on a Project.
11
 * @see https://www.mediawiki.org/wiki/Extension:PageAssessments
12
 */
13
class PageAssessments extends Model
14
{
15
    /** Namespaces in which there may be page assessments. */
16
    const SUPPORTED_NAMESPACES = [0, 4, 6, 10, 14, 100, 108, 118];
17
18
    /** @var Project The Project we're dealing with. */
19
    protected $project;
20
21
    /** @var array The assessments config. */
22
    protected $config;
23
24
    /**
25
     * Create a new PageAssessments.
26
     * @param Project $project
27
     */
28 113
    public function __construct(Project $project)
29
    {
30 113
        $this->project = $project;
31 113
    }
32
33
    /**
34
     * Get page assessments configuration for the Project and cache in static variable.
35
     * @return string[]|false As defined in config/assessments.yml, or false if none exists.
36
     */
37 4
    public function getConfig()
38
    {
39 4
        if (!isset($this->config)) {
40 4
            return $this->config = $this->getRepository()->getConfig($this->project);
41
        }
42
43 3
        return $this->config;
44
    }
45
46
    /**
47
     * Is the given namespace supported in Page Assessments?
48
     * @param  int $nsId Namespace ID.
49
     * @return bool
50
     */
51 2
    public function isSupportedNamespace($nsId)
52
    {
53 2
        return $this->isEnabled() && in_array($nsId, self::SUPPORTED_NAMESPACES);
54
    }
55
56
    /**
57
     * Does this project support page assessments?
58
     * @return bool
59
     */
60 2
    public function isEnabled()
61
    {
62 2
        return (bool)$this->getConfig();
63
    }
64
65
    /**
66
     * Does this project have importance ratings through Page Assessments?
67
     * @return bool
68
     */
69 1
    public function hasImportanceRatings()
70
    {
71 1
        $config = $this->getConfig();
72 1
        return isset($config['importance']);
73
    }
74
75
    /**
76
     * Get the image URL of the badge for the given page assessment.
77
     * @param string $class Valid classification for project, such as 'Start', 'GA', etc.
78
     * @param bool $filenameOnly Get only the filename, not the URL.
79
     * @return string URL to image.
80
     */
81 2
    public function getBadgeURL($class, $filenameOnly = false)
82
    {
83 2
        $config = $this->getConfig();
84
85 2
        if (isset($config['class'][$class])) {
86 2
            $url = 'https://upload.wikimedia.org/wikipedia/commons/'.$config['class'][$class]['badge'];
87 1
        } elseif (isset($config['class']['Unknown'])) {
88 1
            $url = 'https://upload.wikimedia.org/wikipedia/commons/'.$config['class']['Unknown']['badge'];
89
        } else {
90
            $url = "";
91
        }
92
93 2
        if ($filenameOnly) {
94 1
            $parts = explode('/', $url);
95 1
            return end($parts);
96
        }
97
98 2
        return $url;
99
    }
100
101
    /**
102
     * Get the single overall assessment of the given page.
103
     * @param Page $page
104
     * @return string[] With keys 'value' and 'badge'.
105
     * @todo Add option to get ORES prediction.
106
     */
107
    public function getAssessment(Page $page)
108
    {
109
        if (!$this->isEnabled() || !$this->isSupportedNamespace($page->getNamespace())) {
110
            return false;
111
        }
112
113
        $data = $this->getRepository()->getAssessments($page, true);
114
115
        if (isset($data[0])) {
116
            return $this->getClassFromAssessment($data[0]);
117
        }
118
119
        // 'Unknown' class.
120
        return $this->getClassFromAssessment(['class' => '']);
121
    }
122
123
    /**
124
     * Get assessments for the given Page.
125
     * @param Page $page
126
     * @return string[]|false `false` if unsupported, or array in the format of:
127
     *         [
128
     *             'assessment' => 'C', // overall assessment
129
     *             'wikiprojects' => [
130
     *                 'Biography' => [
131
     *                     'assessment' => 'C',
132
     *                     'badge' => 'url',
133
     *                 ],
134
     *                 ...
135
     *             ],
136
     *             'wikiproject_prefix' => 'Wikipedia:WikiProject_',
137
     *         ]
138
     * @todo Add option to get ORES prediction.
139
     */
140 1
    public function getAssessments(Page $page)
141
    {
142 1
        if (!$this->isEnabled() || !$this->isSupportedNamespace($page->getNamespace())) {
143
            return false;
144
        }
145
146 1
        $config = $this->getConfig();
147 1
        $data = $this->getRepository()->getAssessments($page);
148
149
        // Set the default decorations for the overall quality assessment.
150
        // This will be replaced with the first valid class defined for any WikiProject.
151 1
        $overallQuality = $config['class']['Unknown'];
152 1
        $overallQuality['value'] = '???';
153 1
        $overallQuality['badge'] = $this->getBadgeURL($overallQuality['badge']);
154
155 1
        $decoratedAssessments = [];
156
157
        // Go through each raw assessment data from the database, and decorate them
158
        // with the colours and badges as retrieved from the XTools assessments config.
159 1
        foreach ($data as $assessment) {
160 1
            $assessment['class'] = $this->getClassFromAssessment($assessment);
161
162 1
            if ($overallQuality['value'] === '???') {
163 1
                $overallQuality = $assessment['class'];
164
            }
165
166 1
            $assessment['importance'] = $this->getImportanceFromAssessment($assessment);
167
168 1
            $decoratedAssessments[$assessment['wikiproject']] = $assessment;
169
        }
170
171
        // Don't shown 'Unknown' assessment outside of the mainspace.
172 1
        if ($page->getNamespace() !== 0 && $overallQuality['value'] === '???') {
173
            return false;
174
        }
175
176
        return [
177 1
            'assessment' => $overallQuality,
178 1
            'wikiprojects' => $decoratedAssessments,
179 1
            'wikiproject_prefix' => $config['wikiproject_prefix']
180
        ];
181
    }
182
183
    /**
184
     * Get the class attributes for the given class value,
185
     * as fetched from the config.
186
     * @param  string $classValue Such as 'FA', 'GA', 'Start', etc.
187
     * @return string[] Attributes as fetched from the XTools assessments config.
188
     */
189 1
    private function getClassAttrs($classValue)
190
    {
191 1
        return $this->getConfig()['class'][$classValue];
192
    }
193
194
    /**
195
     * Get the properties of the assessment class, including:
196
     *   'value' (class name in plain text),
197
     *   'color' (as hex RGB),
198
     *   'badge' (full URL to assessment badge),
199
     *   'category' (wiki path to related class category).
200
     * @param  array $assessment
201
     * @return array Decorated class assessment.
202
     */
203 1
    private function getClassFromAssessment($assessment)
204
    {
205 1
        $classValue = $assessment['class'];
206
207
        // Use ??? as the presented value when the class is unknown or is not defined in the config
208 1
        if ($classValue === 'Unknown' || $classValue === '' || !isset($this->getConfig()['class'][$classValue])) {
209
            return array_merge($this->getClassAttrs('Unknown'), [
210
                'value' => '???',
211
                'badge' => $this->getBadgeURL('Unknown'),
212
            ]);
213
        }
214
215
        // Known class.
216 1
        $classAttrs = $this->getClassAttrs($classValue);
217
        $class = [
218 1
            'value' => $classValue,
219 1
            'color' => $classAttrs['color'],
220 1
            'category' => $classAttrs['category'],
221
        ];
222
223
        // add full URL to badge icon
224 1
        if ($classAttrs['badge'] !== '') {
225 1
            $class['badge'] = $this->getBadgeURL($classValue);
226
        }
227
228 1
        return $class;
229
    }
230
231
    /**
232
     * Get the properties of the assessment importance, including:
233
     *   'value' (importance in plain text),
234
     *   'color' (as hex RGB),
235
     *   'weight' (integer, 0 is lowest importance),
236
     *   'category' (wiki path to the related importance category).
237
     * @param  array $assessment
238
     * @return array Decorated importance assessment.
239
     */
240 1
    private function getImportanceFromAssessment($assessment)
241
    {
242 1
        $importanceValue = $assessment['importance'];
243
244 1
        if ($importanceValue == '' && !isset($this->getConfig()['importance'])) {
245
            return null;
246
        }
247
248
        // Known importance level.
249 1
        $importanceUnknown = $importanceValue === 'Unknown' || $importanceValue === '';
250
251 1
        if ($importanceUnknown || !isset($this->getConfig()['importance'][$importanceValue])) {
252
            $importanceAttrs = $this->getConfig()['importance']['Unknown'];
253
254
            return array_merge($importanceAttrs, [
255
                'value' => '???',
256
                'category' => $importanceAttrs['category'],
257
            ]);
258
        } else {
259 1
            $importanceAttrs = $this->getConfig()['importance'][$importanceValue];
260
            return [
261 1
                'value' => $importanceValue,
262 1
                'color' => $importanceAttrs['color'],
263 1
                'weight' => $importanceAttrs['weight'], // numerical weight for sorting purposes
264 1
                'category' => $importanceAttrs['category'],
265
            ];
266
        }
267
    }
268
}
269