Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
96.55% |
28 / 29 |
|
94.44% |
17 / 18 |
CRAP | |
0.00% |
0 / 1 |
ViolationMessage | |
96.55% |
28 / 29 |
|
94.44% |
17 / 18 |
19 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
2 | |||
getMessageKey | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getArguments | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withArgument | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
withEntityId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withEntityIdList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withItemIdSnakValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withItemIdSnakValueList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withDataValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withDataValueType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withInlineCode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withConstraintScope | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withConstraintScopeList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withPropertyScope | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withPropertyScopeList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withLanguage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
withLanguages | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
withMultilingualText | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Message; |
4 | |
5 | use DataValues\DataValue; |
6 | use DataValues\MultilingualTextValue; |
7 | use InvalidArgumentException; |
8 | use Wikibase\DataModel\Entity\EntityId; |
9 | use WikibaseQuality\ConstraintReport\ConstraintCheck\ItemIdSnakValue; |
10 | |
11 | /** |
12 | * A violation message of a constraint check. |
13 | * |
14 | * A ViolationMessage object is immutable: |
15 | * operations like {@link withEntityId} return a modified copy. |
16 | * |
17 | * @license GPL-2.0-or-later |
18 | */ |
19 | class ViolationMessage { |
20 | |
21 | /** |
22 | * @private |
23 | */ |
24 | public const MESSAGE_KEY_PREFIX = 'wbqc-violation-message-'; |
25 | |
26 | /** |
27 | * Argument type for a single entity ID. |
28 | * Value type: {@link EntityId} |
29 | */ |
30 | public const TYPE_ENTITY_ID = 'e'; |
31 | |
32 | /** |
33 | * Argument type for a list of entity IDs. |
34 | * Value type: {@link EntityId}[] |
35 | */ |
36 | public const TYPE_ENTITY_ID_LIST = 'E'; |
37 | |
38 | /** |
39 | * Argument type for an item ID, “unknown value”, or “no value”. |
40 | * Value type: {@link ItemIdSnakValue} |
41 | */ |
42 | public const TYPE_ITEM_ID_SNAK_VALUE = 'i'; |
43 | |
44 | /** |
45 | * Argument type for a list of item IDs, “unknown value”s, or “no value”s. |
46 | * Value type: {@link ItemIdSnakValue}[] |
47 | */ |
48 | public const TYPE_ITEM_ID_SNAK_VALUE_LIST = 'I'; |
49 | |
50 | /** |
51 | * Argument type for a single data value. |
52 | * Value type: {@link DataValue} |
53 | */ |
54 | public const TYPE_DATA_VALUE = 'v'; |
55 | |
56 | /** |
57 | * Argument type for a data value type, like "time" or "wikibase-entityid". |
58 | * (Not to be confused with a data type, like "time" or "wikibase-item".) |
59 | * Value type: string |
60 | */ |
61 | public const TYPE_DATA_VALUE_TYPE = 't'; |
62 | |
63 | /** |
64 | * Argument type for a short fragment of inline computer code. |
65 | * Value type: string |
66 | */ |
67 | public const TYPE_INLINE_CODE = 'c'; |
68 | |
69 | /** |
70 | * Argument type for a single constraint scope. |
71 | * Value type: string (one of the Context::TYPE_* constants) |
72 | */ |
73 | public const TYPE_CONSTRAINT_SCOPE = 's'; |
74 | |
75 | /** |
76 | * Argument type for a list of constraint scopes. |
77 | * Value type: string[] |
78 | */ |
79 | public const TYPE_CONSTRAINT_SCOPE_LIST = 'S'; |
80 | |
81 | /** |
82 | * Argument type for a single property scope. |
83 | * Value type: string (one of the Context::TYPE_* constants) |
84 | */ |
85 | public const TYPE_PROPERTY_SCOPE = 'p'; |
86 | |
87 | /** |
88 | * Argument type for a list of property scopes. |
89 | * Value type: string[] |
90 | */ |
91 | public const TYPE_PROPERTY_SCOPE_LIST = 'P'; |
92 | |
93 | /** |
94 | * Argument type for a language. |
95 | * Value type: string (language code) |
96 | */ |
97 | public const TYPE_LANGUAGE = 'l'; |
98 | |
99 | /** |
100 | * Argument type for list of languages. |
101 | * Value type: string[] (language codes) |
102 | */ |
103 | public const TYPE_LANGUAGE_LIST = 'L'; |
104 | |
105 | /** |
106 | * Argument type for a multilingual text value. |
107 | * Value type: {@link MultilingualTextValue} |
108 | */ |
109 | public const TYPE_MULTILINGUAL_TEXT = 'm'; |
110 | |
111 | /** |
112 | * @var string |
113 | */ |
114 | private $messageKeySuffix; |
115 | |
116 | /** |
117 | * @var array[] |
118 | */ |
119 | private $arguments; |
120 | |
121 | /** |
122 | * @param string $messageKey The full message key. Must start with 'wbqc-violation-message-'. |
123 | * (We require callers to specify the full message key |
124 | * so that it’s easy to search for code that produces a given message.) |
125 | * |
126 | * @throws InvalidArgumentException If the message key is invalid. |
127 | */ |
128 | public function __construct( |
129 | $messageKey |
130 | ) { |
131 | if ( strpos( $messageKey, self::MESSAGE_KEY_PREFIX ) !== 0 ) { |
132 | throw new InvalidArgumentException( |
133 | 'ViolationMessage key ⧼' . |
134 | $messageKey . |
135 | '⧽ should start with "' . |
136 | self::MESSAGE_KEY_PREFIX . |
137 | '".' |
138 | ); |
139 | } |
140 | |
141 | $this->messageKeySuffix = substr( $messageKey, strlen( self::MESSAGE_KEY_PREFIX ) ); |
142 | $this->arguments = []; |
143 | } |
144 | |
145 | /** |
146 | * Get the full message key of this message. |
147 | * @return string |
148 | */ |
149 | public function getMessageKey() { |
150 | return self::MESSAGE_KEY_PREFIX . $this->messageKeySuffix; |
151 | } |
152 | |
153 | /** |
154 | * Get the arguments to this message, |
155 | * a list of [ 'type' => self::TYPE_*, 'role' => Role::*, 'value' => $value ] elements. |
156 | * @return array[] |
157 | */ |
158 | public function getArguments() { |
159 | return $this->arguments; |
160 | } |
161 | |
162 | /** |
163 | * Note: usually you don’t want to use this function directly. |
164 | * |
165 | * @param string $type one of the self::TYPE_* constants |
166 | * @param string|null $role one of the Role::* constants |
167 | * @param mixed $value the value, which should match the $type |
168 | * @return ViolationMessage |
169 | */ |
170 | public function withArgument( $type, $role, $value ) { |
171 | $ret = clone $this; |
172 | $ret->arguments[] = [ 'type' => $type, 'role' => $role, 'value' => $value ]; |
173 | return $ret; |
174 | } |
175 | |
176 | /** |
177 | * Append a single entity ID to the message arguments. |
178 | * (This operation returns a modified copy, the original object is unchanged.) |
179 | * |
180 | * @param EntityId $entityId |
181 | * @param string|null $role one of the Role::* constants |
182 | * @return ViolationMessage |
183 | */ |
184 | public function withEntityId( EntityId $entityId, $role = null ) { |
185 | return $this->withArgument( self::TYPE_ENTITY_ID, $role, $entityId ); |
186 | } |
187 | |
188 | /** |
189 | * Append a list of entity IDs to the message arguments. |
190 | * (This operation returns a modified copy, the original object is unchanged.) |
191 | * |
192 | * This is not the same as appending the list elements individually with {@link withEntityId}! |
193 | * In the final message, this corresponds to |
194 | * one parameter for the number of list elements, |
195 | * one parameter with an HTML list of the list elements, |
196 | * and then one parameter per entity ID. |
197 | * |
198 | * @param EntityId[] $entityIdList |
199 | * @param string|null $role one of the Role::* constants |
200 | * @return ViolationMessage |
201 | */ |
202 | public function withEntityIdList( array $entityIdList, $role = null ) { |
203 | return $this->withArgument( self::TYPE_ENTITY_ID_LIST, $role, $entityIdList ); |
204 | } |
205 | |
206 | /** |
207 | * Append a single item ID, “unknown value”, or “no value” to the message arguments. |
208 | * (This operation returns a modified copy, the original object is unchanged.) |
209 | * |
210 | * @param ItemIdSnakValue $value |
211 | * @param string|null $role one of the Role::* constants |
212 | * @return ViolationMessage |
213 | */ |
214 | public function withItemIdSnakValue( ItemIdSnakValue $value, $role = null ) { |
215 | return $this->withArgument( self::TYPE_ITEM_ID_SNAK_VALUE, $role, $value ); |
216 | } |
217 | |
218 | /** |
219 | * Append a list of item IDs, “unknown value”s, or “no value”s to the message arguments. |
220 | * (This operation returns a modified copy, the original object is unchanged.) |
221 | * |
222 | * This is not the same as appending the list elements individually with {@link withItemIdSnakValue}! |
223 | * In the final message, this corresponds to |
224 | * one parameter for the number of list elements, |
225 | * one parameter with an HTML list of the list elements, |
226 | * and then one parameter per value. |
227 | * |
228 | * @param ItemIdSnakValue[] $valueList |
229 | * @param string|null $role one of the Role::* constants |
230 | * @return ViolationMessage |
231 | */ |
232 | public function withItemIdSnakValueList( array $valueList, $role = null ) { |
233 | return $this->withArgument( self::TYPE_ITEM_ID_SNAK_VALUE_LIST, $role, $valueList ); |
234 | } |
235 | |
236 | /** |
237 | * Append a single data value to the message arguments. |
238 | * (This operation returns a modified copy, the original object is unchanged.) |
239 | * |
240 | * @param DataValue $dataValue |
241 | * @param string|null $role one of the Role::* constants |
242 | * @return ViolationMessage |
243 | */ |
244 | public function withDataValue( DataValue $dataValue, $role = null ) { |
245 | return $this->withArgument( self::TYPE_DATA_VALUE, $role, $dataValue ); |
246 | } |
247 | |
248 | /** |
249 | * Append a single data value type, like "time" or "wikibase-entityid". |
250 | * (This operation returns a modified copy, the original object is unchanged.) |
251 | * |
252 | * Data value types should not be confused with data types, like "time" or "wikibase-item". |
253 | * For example, "wikibase-entityid" is the data value type |
254 | * used by the data types "wikibase-item" and "wikibase-property". |
255 | * |
256 | * @param string $dataValueType |
257 | * @param string|null $role one of the Role::* constants |
258 | * @return ViolationMessage |
259 | */ |
260 | public function withDataValueType( $dataValueType, $role = null ) { |
261 | return $this->withArgument( self::TYPE_DATA_VALUE_TYPE, $role, $dataValueType ); |
262 | } |
263 | |
264 | /** |
265 | * Append a single short fragment of inline computer code to the message arguments. |
266 | * (This operation returns a modified copy, the original object is unchanged.) |
267 | * |
268 | * @param string $code |
269 | * @param string|null $role one of the Role::* constants |
270 | * @return ViolationMessage |
271 | */ |
272 | public function withInlineCode( $code, $role = null ) { |
273 | return $this->withArgument( self::TYPE_INLINE_CODE, $role, $code ); |
274 | } |
275 | |
276 | /** |
277 | * Append a single constraint scope to the message arguments. |
278 | * (This operation returns a modified copy, the original object is unchanged.) |
279 | * |
280 | * @param string $scope one of the Context::TYPE_* constants |
281 | * @param string|null $role one of the Role::* constants |
282 | * @return ViolationMessage |
283 | */ |
284 | public function withConstraintScope( $scope, $role = null ) { |
285 | return $this->withArgument( self::TYPE_CONSTRAINT_SCOPE, $role, $scope ); |
286 | } |
287 | |
288 | /** |
289 | * Append a list of constraint scopes to the message arguments. |
290 | * (This operation returns a modified copy, the original object is unchanged.) |
291 | * |
292 | * @param string[] $scopeList Role::* constants |
293 | * @param string|null $role one of the Role::* constants |
294 | * @return ViolationMessage |
295 | */ |
296 | public function withConstraintScopeList( array $scopeList, $role = null ) { |
297 | return $this->withArgument( self::TYPE_CONSTRAINT_SCOPE_LIST, $role, $scopeList ); |
298 | } |
299 | |
300 | /** |
301 | * Append a single property scope to the message arguments. |
302 | * (This operation returns a modified copy, the original object is unchanged.) |
303 | * |
304 | * @param string $scope one of the Context::TYPE_* constants |
305 | * @param string|null $role one of the Role::* constants |
306 | * @return ViolationMessage |
307 | */ |
308 | public function withPropertyScope( $scope, $role = null ) { |
309 | return $this->withArgument( self::TYPE_PROPERTY_SCOPE, $role, $scope ); |
310 | } |
311 | |
312 | /** |
313 | * Append a list of property scopes to the message arguments. |
314 | * (This operation returns a modified copy, the original object is unchanged.) |
315 | * |
316 | * @param string[] $scopeList Role::* constants |
317 | * @param string|null $role one of the Role::* constants |
318 | * @return ViolationMessage |
319 | */ |
320 | public function withPropertyScopeList( array $scopeList, $role = null ) { |
321 | return $this->withArgument( self::TYPE_PROPERTY_SCOPE_LIST, $role, $scopeList ); |
322 | } |
323 | |
324 | /** |
325 | * Append a single language to the message arguments. |
326 | * (This operation returns a modified copy, the original object is unchanged.) |
327 | * |
328 | * One language argument corresponds to two params in the final message, |
329 | * one for the language name (autonym) and one for the language code. |
330 | * |
331 | * (Language arguments do not support roles.) |
332 | * |
333 | * @param string $languageCode |
334 | * @return ViolationMessage |
335 | */ |
336 | public function withLanguage( $languageCode ) { |
337 | return $this->withArgument( self::TYPE_LANGUAGE, null, $languageCode ); |
338 | } |
339 | |
340 | /** |
341 | * Append a single language to the message arguments. |
342 | * (This operation returns a modified copy, the original object is unchanged.) |
343 | * |
344 | * One language argument corresponds to two params in the final message, |
345 | * one for the language name (autonym) and one for the language code. |
346 | * |
347 | * (Language arguments do not support roles.) |
348 | * |
349 | * @param string[] $languageCodes |
350 | * @return ViolationMessage |
351 | */ |
352 | public function withLanguages( $languageCodes ) { |
353 | return $this->withArgument( self::TYPE_LANGUAGE_LIST, null, $languageCodes ); |
354 | } |
355 | |
356 | /** |
357 | * Append a multilingual text value to the message arguments. |
358 | * (This operation returns a modified copy, the original object is unchanged.) |
359 | * |
360 | * Note that multilingual text arguments can only be rendered for specific message keys |
361 | * (see {@link MultilingualTextViolationMessageRenderer} for details), |
362 | * but this method does not verify whether you’re using one of those message keys. |
363 | * |
364 | * @param MultilingualTextValue $text |
365 | * @param string|null $role one of the Role::* constants |
366 | * @return ViolationMessage |
367 | */ |
368 | public function withMultilingualText( MultilingualTextValue $text, $role = null ) { |
369 | return $this->withArgument( self::TYPE_MULTILINGUAL_TEXT, $role, $text ); |
370 | } |
371 | |
372 | } |