Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
CategoryManager
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 13
552
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
56
 hasNameParam
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasNoParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHighPriority
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMediumPriority
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLowPriority
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getNonePriority
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getVisibleCategories
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getInvisibleCategories
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isKnownCategory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCategoryName
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getCategoryIds
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getCategoryId
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
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 2 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 along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\Linter;
22
23use InvalidArgumentException;
24
25/**
26 * CategoryManager services: functions for lint error categories.
27 */
28class CategoryManager {
29
30    private const HIGH = 'high';
31    private const MEDIUM = 'medium';
32    private const LOW = 'low';
33    private const NONE = 'none';
34
35    /**
36     * Map of category names to their hardcoded
37     * numerical ids for use in the database
38     *
39     * @var int[]
40     */
41    private $categoryIds = [];
42
43    /**
44     * @var string[][]
45     */
46    private $categories = [
47        self::HIGH => [],
48        self::MEDIUM => [],
49        self::LOW => [],
50        self::NONE => [],
51    ];
52
53    /**
54     * @var bool[]
55     * @phan-var array<string,bool>
56     */
57    private $hasNameParam = [];
58
59    /**
60     * @var bool[]
61     * @phan-var array<string,bool>
62     */
63    private $hasNoParams = [];
64
65    /**
66     * Do not instantiate directly: use MediaWikiServices to fetch.
67     * @param array $linterCategories
68     */
69    public function __construct( array $linterCategories ) {
70        foreach ( $linterCategories as $name => $info ) {
71            if ( $info['enabled'] ) {
72                $this->categories[$info['priority']][] = $name;
73            }
74            if ( $info['has-name'] ?? false ) {
75                $this->hasNameParam[$name] = true;
76            }
77            if ( $info['no-params'] ?? false ) {
78                $this->hasNoParams[$name] = true;
79            }
80            if ( isset( $info['dbid'] ) ) {
81                if ( isset( $this->categoryIds[$name] ) ) {
82                    throw new InvalidArgumentException( "duplicate ID: $name" );
83                }
84                $this->categoryIds[$name] = $info['dbid'];
85            }
86        }
87
88        sort( $this->categories[self::HIGH] );
89        sort( $this->categories[self::MEDIUM] );
90        sort( $this->categories[self::LOW] );
91        sort( $this->categories[self::NONE] );
92    }
93
94    /**
95     * @param string $name
96     * @return bool
97     */
98    public function hasNameParam( $name ) {
99        return isset( $this->hasNameParam[$name] );
100    }
101
102    /**
103     * @param string $name
104     * @return bool
105     */
106    public function hasNoParams( $name ) {
107        return isset( $this->hasNoParams[$name] );
108    }
109
110    /**
111     * @return string[]
112     */
113    public function getHighPriority() {
114        return $this->categories[self::HIGH];
115    }
116
117    /**
118     * @return string[]
119     */
120    public function getMediumPriority() {
121        return $this->categories[self::MEDIUM];
122    }
123
124    /**
125     * @return string[]
126     */
127    public function getLowPriority() {
128        return $this->categories[self::LOW];
129    }
130
131    /**
132     * @return string[]
133     */
134    public function getNonePriority() {
135        return $this->categories[self::NONE];
136    }
137
138    /**
139     * Categories that are configured to be displayed to users
140     *
141     * @return string[]
142     */
143    public function getVisibleCategories() {
144        return array_merge(
145            $this->categories[self::HIGH],
146            $this->categories[self::MEDIUM],
147            $this->categories[self::LOW]
148        );
149    }
150
151    /**
152     * Categories that are configured to not be displayed to users
153     *
154     * @return string[]
155     */
156    public function getInvisibleCategories() {
157        return $this->categories[self::NONE];
158    }
159
160    /**
161     * Whether this category has a hardcoded id and can be
162     * inserted into the database
163     *
164     * @param string $name
165     * @return bool
166     */
167    public function isKnownCategory( $name ) {
168        return isset( $this->categoryIds[$name] );
169    }
170
171    /**
172     * @param int $id
173     * @return string
174     * @throws MissingCategoryException if we can't find the name for the id
175     */
176    public function getCategoryName( $id ) {
177        $flip = array_flip( $this->categoryIds );
178        if ( isset( $flip[$id] ) ) {
179            return $flip[$id];
180        }
181
182        throw new MissingCategoryException( "Could not find name for id $id" );
183    }
184
185    /**
186     * @param string[] $names
187     * @return int[]
188     */
189    public function getCategoryIds( array $names ) {
190        $result = [];
191        foreach ( $names as $name ) {
192            $result[$name] = $this->getCategoryId( $name );
193        }
194
195        return $result;
196    }
197
198    /**
199     * Get the int id for the category in lint_categories table
200     *
201     * @param string $name
202     * @param int|null $hint An optional hint, passed along from Parsoid.
203     *   If the hint contains a suggested category ID but the Linter
204     *   extension doesn't (yet) have one, use the ID from Parsoid's hint.
205     *   This allows decoupling the Parsoid deploy of a new category
206     *   from the corresponding Linter extension deploy.
207     * @return int
208     * @throws MissingCategoryException if we can't find the id for the name
209     *   and there is no hint from Parsoid
210     */
211    public function getCategoryId( $name, $hint = null ) {
212        if ( isset( $this->categoryIds[$name] ) ) {
213            return $this->categoryIds[$name];
214        }
215
216        // Use hint from Parsoid, if available.
217        if ( $hint !== null ) {
218            return $hint;
219        }
220
221        throw new MissingCategoryException( "Cannot find id for '$name'" );
222    }
223}