Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
58.62% |
51 / 87 |
|
73.33% |
11 / 15 |
CRAP | |
0.00% |
0 / 1 |
ZPersistentObject | |
58.62% |
51 / 87 |
|
73.33% |
11 / 15 |
88.59 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
getDefinition | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
2 | |||
isValid | |
57.14% |
8 / 14 |
|
0.00% |
0 / 1 |
10.86 | |||
getZValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
validateZMultilingualStringFieldLength | |
92.31% |
12 / 13 |
|
0.00% |
0 / 1 |
6.02 | |||
validateDescriptionLength | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
validateLabelLength | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getZid | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getInnerZObject | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getInternalZType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLabels | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLabel | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
getAliases | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getDescriptions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getDescription | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
3.02 |
1 | <?php |
2 | /** |
3 | * WikiLambda generic ZPersistentObject class |
4 | * |
5 | * @file |
6 | * @ingroup Extensions |
7 | * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt |
8 | * @license MIT |
9 | */ |
10 | |
11 | namespace MediaWiki\Extension\WikiLambda\ZObjects; |
12 | |
13 | use MediaWiki\Context\IContextSource; |
14 | use MediaWiki\Extension\WikiLambda\Registry\ZLangRegistry; |
15 | use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry; |
16 | use MediaWiki\Extension\WikiLambda\ZObjectUtils; |
17 | use MediaWiki\Language\Language; |
18 | use MediaWiki\MediaWikiServices; |
19 | use MessageLocalizer; |
20 | |
21 | class ZPersistentObject extends ZObject { |
22 | |
23 | /** @var array */ |
24 | protected $data = []; |
25 | |
26 | /** |
27 | * Construct a ZPersistentObject instance |
28 | * |
29 | * @param ZObject $zid ZString representing the Zid that identifies this ZPersistentObject |
30 | * @param ZObject $value ZObject to be wrapped in this ZPersistentObject |
31 | * @param ZObject $label ZMultiLingualString that contains this ZPersistentObject's label |
32 | * @param ZObject|null $aliases ZMultiLingualStringSet with this ZPersistentObject's aliases or null |
33 | * @param ZObject|null $description ZMultiLingualString that contains this ZPersistentObject's description |
34 | */ |
35 | public function __construct( $zid, $value, $label, $aliases = null, $description = null ) { |
36 | $aliases ??= new ZMultiLingualStringSet( [] ); |
37 | $description ??= new ZMultiLingualString( [] ); |
38 | $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ID ] = $zid; |
39 | $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_VALUE ] = $value; |
40 | $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_LABEL ] = $label; |
41 | $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ALIASES ] = $aliases; |
42 | $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_DESCRIPTION ] = $description; |
43 | } |
44 | |
45 | /** |
46 | * @inheritDoc |
47 | */ |
48 | public static function getDefinition(): array { |
49 | return [ |
50 | 'type' => [ |
51 | 'type' => ZTypeRegistry::Z_REFERENCE, |
52 | 'value' => ZTypeRegistry::Z_PERSISTENTOBJECT, |
53 | ], |
54 | 'keys' => [ |
55 | ZTypeRegistry::Z_PERSISTENTOBJECT_ID => [ |
56 | 'type' => ZTypeRegistry::Z_STRING, |
57 | 'required' => true, |
58 | ], |
59 | ZTypeRegistry::Z_PERSISTENTOBJECT_VALUE => [ |
60 | 'type' => ZTypeRegistry::Z_OBJECT, |
61 | 'required' => true, |
62 | ], |
63 | ZTypeRegistry::Z_PERSISTENTOBJECT_LABEL => [ |
64 | 'type' => ZTypeRegistry::Z_MULTILINGUALSTRING, |
65 | 'required' => true, |
66 | ], |
67 | ZTypeRegistry::Z_PERSISTENTOBJECT_ALIASES => [ |
68 | 'type' => ZTypeRegistry::Z_MULTILINGUALSTRINGSET, |
69 | 'required' => false, |
70 | ], |
71 | ZTypeRegistry::Z_PERSISTENTOBJECT_DESCRIPTION => [ |
72 | 'type' => ZTypeRegistry::Z_MULTILINGUALSTRING, |
73 | 'required' => false, |
74 | ], |
75 | ], |
76 | ]; |
77 | } |
78 | |
79 | /** |
80 | * @inheritDoc |
81 | */ |
82 | public function isValid(): bool { |
83 | if ( !( $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ID ] instanceof ZString ) ) { |
84 | return false; |
85 | } |
86 | $zid = $this->getZid(); |
87 | if ( !ZObjectUtils::isValidOrNullZObjectReference( $zid ) ) { |
88 | return false; |
89 | } |
90 | if ( !( $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_VALUE ] instanceof ZObject ) ) { |
91 | return false; |
92 | } |
93 | if ( !( $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_LABEL ] instanceof ZMultiLingualString ) ) { |
94 | return false; |
95 | } |
96 | if ( !( $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ALIASES ] instanceof ZMultiLingualStringSet ) ) { |
97 | return false; |
98 | } |
99 | if ( !( $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_DESCRIPTION ] instanceof ZMultiLingualString ) ) { |
100 | return false; |
101 | } |
102 | return true; |
103 | } |
104 | |
105 | /** |
106 | * Get the generic content of the inner ZObject wrapped by this ZPersistentObject. |
107 | * |
108 | * @return mixed The generic content of the ZObject wrapped by this ZPersistentObject. |
109 | */ |
110 | public function getZValue() { |
111 | return $this->getInnerZObject()->getZValue(); |
112 | } |
113 | |
114 | /** |
115 | * Validate the length of a field in the ZMultilingualString of this ZPersistentObject. |
116 | * The field is validated for each language in the ZMultilingualString. |
117 | * |
118 | * @param string $fieldName The name of the field to validate |
119 | * @param int $length The maximum length of the field |
120 | * @param MessageLocalizer|null $context The context of the action operation, for localisation of messages |
121 | * @return array An array of invalid languages |
122 | */ |
123 | private function validateZMultilingualStringFieldLength( $fieldName, $length, $context = null ) { |
124 | // If we have context available as IContextSource, get user language to localize language names |
125 | $userLang = ( $context instanceof IContextSource ) ? $context->getLanguage()->getCode() : null; |
126 | |
127 | // used to go from LANG_CODE -> LANG_NAME |
128 | // TODO (T362246): Dependency-inject |
129 | $services = MediaWikiServices::getInstance(); |
130 | $zLangRegistry = ZLangRegistry::singleton(); |
131 | $invalidLanguages = []; |
132 | |
133 | // Ensure the field exists and is a valid object with getValueAsList method |
134 | if ( !isset( $this->data[$fieldName] ) || !method_exists( $this->data[$fieldName], 'getValueAsList' ) ) { |
135 | // Handle the case where the field is not present or is not valid |
136 | return $invalidLanguages; |
137 | } |
138 | |
139 | $fieldValues = $this->data[$fieldName]->getValueAsList(); |
140 | foreach ( $fieldValues as $lang => $value ) { |
141 | if ( strlen( $value ) > $length ) { |
142 | // get the language name from the language code |
143 | $langCode = $zLangRegistry->getLanguageCodeFromZid( $lang ); |
144 | $langTitle = $services->getLanguageNameUtils()->getLanguageName( $langCode, $userLang ); |
145 | $invalidLanguages[] = $langTitle; |
146 | } |
147 | } |
148 | return $invalidLanguages; |
149 | } |
150 | |
151 | /** |
152 | * Validates the length of the description field for a persistent object. |
153 | * |
154 | * @param int $length The maximum length allowed for the description. |
155 | * @param MessageLocalizer|null $context The context of the action operation, for localisation of messages |
156 | * @return array An array of invalid languages |
157 | */ |
158 | public function validateDescriptionLength( $length, $context = null ) { |
159 | return $this->validateZMultilingualStringFieldLength( |
160 | ZTypeRegistry::Z_PERSISTENTOBJECT_DESCRIPTION, $length, $context ); |
161 | } |
162 | |
163 | /** |
164 | * Validates the length of the label field for a persistent object. |
165 | * |
166 | * @param int $length The maximum length allowed for the label. |
167 | * @param MessageLocalizer|null $context The context of the action operation, for localisation of messages |
168 | * @return array An array of invalid languages |
169 | */ |
170 | public function validateLabelLength( $length, $context = null ) { |
171 | return $this->validateZMultilingualStringFieldLength( |
172 | ZTypeRegistry::Z_PERSISTENTOBJECT_LABEL, $length, $context ); |
173 | } |
174 | |
175 | /** |
176 | * Get the Zid that identifies this ZPersistentObject. |
177 | * |
178 | * @return string The persisted (or null) ZID |
179 | */ |
180 | public function getZid(): string { |
181 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ID ]->getZValue(); |
182 | } |
183 | |
184 | /** |
185 | * Get the inner ZObject wrapped by this ZPersistentObject. |
186 | * |
187 | * @return ZObject The inner ZObject wrapped by this ZPersistentObject |
188 | */ |
189 | public function getInnerZObject(): ZObject { |
190 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_VALUE ]; |
191 | } |
192 | |
193 | /** |
194 | * Get the type Zid of the ZObject wrapped by this ZPersistentObject. |
195 | * TODO (T296822): The type can also be a function call. |
196 | * |
197 | * @return string The type of the internal ZObject |
198 | */ |
199 | public function getInternalZType(): string { |
200 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_VALUE ]->getZType(); |
201 | } |
202 | |
203 | /** |
204 | * Get the ZMultilingualString that contains the label of this ZPersistentObject. |
205 | * |
206 | * @return ZMultilingualString The mulilingual string object with the label |
207 | */ |
208 | public function getLabels(): ZMultilingualString { |
209 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_LABEL ]; |
210 | } |
211 | |
212 | /** |
213 | * Get the label for a given Language (or its fallback). |
214 | * |
215 | * @param Language $language Language in which to provide the label. |
216 | * @param bool $defaultToEnglish |
217 | * @return ?string |
218 | */ |
219 | public function getLabel( $language, $defaultToEnglish = false ): ?string { |
220 | if ( $defaultToEnglish ) { |
221 | return $this->getLabels() |
222 | ->buildStringForLanguage( $language ) |
223 | ->fallbackWithEnglish() |
224 | ->getString(); |
225 | } |
226 | return $this->getLabels()->getStringForLanguage( $language ); |
227 | } |
228 | |
229 | /** |
230 | * Get the ZMultilingualStringSet that contains the aliases for this ZPersistentObject. |
231 | * |
232 | * @return ZMultilingualStringSet The mulilingual stringset object with the aliases |
233 | */ |
234 | public function getAliases(): ZMultiLingualStringSet { |
235 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_ALIASES ]; |
236 | } |
237 | |
238 | /** |
239 | * Get the ZMultilingualString that contains the description of this ZPersistentObject. |
240 | * |
241 | * @return ?ZMultilingualString The mulilingual string object with the description |
242 | */ |
243 | public function getDescriptions(): ?ZMultilingualString { |
244 | return $this->data[ ZTypeRegistry::Z_PERSISTENTOBJECT_DESCRIPTION ]; |
245 | } |
246 | |
247 | /** |
248 | * Get the description for a given Language (or its fallback). |
249 | * |
250 | * @param Language $language Language in which to provide the description. |
251 | * @param bool $defaultToEnglish |
252 | * @return ?string |
253 | */ |
254 | public function getDescription( $language, $defaultToEnglish = false ): ?string { |
255 | if ( !$this->getDescriptions() ) { |
256 | return null; |
257 | } |
258 | if ( $defaultToEnglish ) { |
259 | return $this->getDescriptions() |
260 | ->buildStringForLanguage( $language ) |
261 | ->fallbackWithEnglish() |
262 | ->getString(); |
263 | } |
264 | return $this->getDescriptions()->getStringForLanguage( $language ); |
265 | } |
266 | } |