Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
91.13% |
267 / 293 |
|
72.22% |
13 / 18 |
CRAP | |
0.00% |
0 / 1 |
MediaInfoEntityStatementsView | |
91.13% |
267 / 293 |
|
72.22% |
13 / 18 |
53.89 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
getHtml | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
2 | |||
getHtmlContainerClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getStatementFormatValueCache | |
70.59% |
12 / 17 |
|
0.00% |
0 / 1 |
4.41 | |||
getSnakFormatValueCache | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
3 | |||
getValueFormatValueCache | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
getLayoutForProperty | |
100.00% |
48 / 48 |
|
100.00% |
1 / 1 |
3 | |||
createPropertyHeader | |
100.00% |
19 / 19 |
|
100.00% |
1 / 1 |
4 | |||
createFormattedDataValue | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
createStatementDiv | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
innerStatementDiv | |
60.47% |
26 / 43 |
|
0.00% |
0 / 1 |
8.22 | |||
renderSnakList | |
97.37% |
37 / 38 |
|
0.00% |
0 / 1 |
6 | |||
formatSnak | |
83.33% |
10 / 12 |
|
0.00% |
0 / 1 |
4.07 | |||
formatValue | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
formatEntityId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
statementsByPropertyId | |
95.45% |
21 / 22 |
|
0.00% |
0 / 1 |
5 | |||
getOrderedStatementsByProperty | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
4 | |||
addDefaultStatements | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | namespace Wikibase\MediaInfo\View; |
4 | |
5 | use DataValues\DataValue; |
6 | use DataValues\Serializers\DataValueSerializer; |
7 | use Exception; |
8 | use MediaWiki\Html\Html; |
9 | use MediaWiki\Output\OutputPage; |
10 | use OOUI\HtmlSnippet; |
11 | use OOUI\PanelLayout; |
12 | use OOUI\Tag; |
13 | use ValueFormatters\FormatterOptions; |
14 | use ValueFormatters\ValueFormatter; |
15 | use Wikibase\DataModel\Entity\EntityId; |
16 | use Wikibase\DataModel\Entity\EntityIdValue; |
17 | use Wikibase\DataModel\Entity\NumericPropertyId; |
18 | use Wikibase\DataModel\Serializers\SerializerFactory; |
19 | use Wikibase\DataModel\Snak\PropertyNoValueSnak; |
20 | use Wikibase\DataModel\Snak\PropertySomeValueSnak; |
21 | use Wikibase\DataModel\Snak\PropertyValueSnak; |
22 | use Wikibase\DataModel\Snak\Snak; |
23 | use Wikibase\DataModel\Snak\SnakList; |
24 | use Wikibase\DataModel\Snak\SnakObject; |
25 | use Wikibase\DataModel\Statement\Statement; |
26 | use Wikibase\DataModel\Statement\StatementList; |
27 | use Wikibase\Lib\Formatters\OutputFormatSnakFormatterFactory; |
28 | use Wikibase\Lib\Formatters\OutputFormatValueFormatterFactory; |
29 | use Wikibase\Lib\Formatters\SnakFormatter; |
30 | use Wikibase\Lib\Store\PropertyOrderProvider; |
31 | use Wikibase\MediaInfo\DataModel\MediaInfo; |
32 | use Wikibase\View\LocalizedTextProvider; |
33 | |
34 | /** |
35 | * Generates HTML to display the statements of a MediaInfo entity |
36 | * |
37 | * @license GPL-2.0-or-later |
38 | */ |
39 | class MediaInfoEntityStatementsView { |
40 | |
41 | private $propertyOrderProvider; |
42 | private $textProvider; |
43 | private $defaultPropertyIds; |
44 | private $snakFormatterFactory; |
45 | private $valueFormatterFactory; |
46 | private $serializerFactory; |
47 | private $languageCode; |
48 | private $properties; |
49 | |
50 | public const STATEMENTS_CUSTOM_TAG = 'mediaInfoViewStatements'; |
51 | |
52 | /** |
53 | * @param PropertyOrderProvider $propertyOrderProvider |
54 | * @param LocalizedTextProvider $textProvider |
55 | * @param NumericPropertyId[] $defaultPropertyIds Default values are displayed for these properties if |
56 | * we don't have values for them |
57 | * @param OutputFormatSnakFormatterFactory $snakFormatterFactory |
58 | * @param OutputFormatValueFormatterFactory $valueFormatterFactory |
59 | * @param SerializerFactory $serializerFactory |
60 | * @param string $languageCode |
61 | * @param string[] $properties Array of property IDs |
62 | */ |
63 | public function __construct( |
64 | PropertyOrderProvider $propertyOrderProvider, |
65 | LocalizedTextProvider $textProvider, |
66 | array $defaultPropertyIds, |
67 | OutputFormatSnakFormatterFactory $snakFormatterFactory, |
68 | OutputFormatValueFormatterFactory $valueFormatterFactory, |
69 | SerializerFactory $serializerFactory, |
70 | $languageCode, |
71 | $properties |
72 | ) { |
73 | OutputPage::setupOOUI(); |
74 | |
75 | $this->propertyOrderProvider = $propertyOrderProvider; |
76 | $this->textProvider = $textProvider; |
77 | $this->defaultPropertyIds = $defaultPropertyIds; |
78 | $this->snakFormatterFactory = $snakFormatterFactory; |
79 | $this->valueFormatterFactory = $valueFormatterFactory; |
80 | $this->serializerFactory = $serializerFactory; |
81 | $this->languageCode = $languageCode; |
82 | $this->properties = $properties; |
83 | } |
84 | |
85 | /** |
86 | * @param MediaInfo $entity |
87 | * @return string |
88 | */ |
89 | public function getHtml( MediaInfo $entity ) { |
90 | $statements = $this->statementsByPropertyId( $entity->getStatements() ); |
91 | |
92 | $html = ''; |
93 | foreach ( $statements as $propertyId => $statementArray ) { |
94 | $panel = $this->getLayoutForProperty( $propertyId, $statementArray ); |
95 | $html .= $panel->toString(); |
96 | } |
97 | |
98 | // Wrap the whole thing in a custom tag so we can manipulate its position on the page |
99 | // later on |
100 | return Html::rawElement( |
101 | self::STATEMENTS_CUSTOM_TAG, |
102 | [], |
103 | $html |
104 | ); |
105 | } |
106 | |
107 | public static function getHtmlContainerClass( $propertyIdString ) { |
108 | return 'wbmi-entityview-statementsGroup-' . str_replace( ':', '_', $propertyIdString ); |
109 | } |
110 | |
111 | /** |
112 | * @param Statement $statement |
113 | * @return array |
114 | */ |
115 | private function getStatementFormatValueCache( Statement $statement ) { |
116 | $results = []; |
117 | |
118 | $results = array_replace_recursive( |
119 | $results, |
120 | $this->getSnakFormatValueCache( $statement->getMainSnak() ) |
121 | ); |
122 | |
123 | foreach ( $statement->getQualifiers() as $qualifier ) { |
124 | $results = array_replace_recursive( |
125 | $results, |
126 | $this->getSnakFormatValueCache( $qualifier ) |
127 | ); |
128 | } |
129 | |
130 | foreach ( $statement->getReferences() as $reference ) { |
131 | foreach ( $reference->getSnaks() as $snak ) { |
132 | $results = array_replace_recursive( |
133 | $results, |
134 | $this->getSnakFormatValueCache( $snak ) |
135 | ); |
136 | } |
137 | } |
138 | |
139 | return $results; |
140 | } |
141 | |
142 | /** |
143 | * @param Snak $snak |
144 | * @return array |
145 | */ |
146 | private function getSnakFormatValueCache( Snak $snak ) { |
147 | $result = []; |
148 | |
149 | // format property |
150 | if ( $snak instanceof SnakObject ) { |
151 | $dataValue = new EntityIdValue( $snak->getPropertyId() ); |
152 | $result = array_replace_recursive( |
153 | $result, |
154 | $this->getValueFormatValueCache( |
155 | $dataValue, |
156 | [ |
157 | SnakFormatter::FORMAT_HTML, |
158 | SnakFormatter::FORMAT_PLAIN, |
159 | ] |
160 | ) |
161 | ); |
162 | } |
163 | |
164 | // format value |
165 | if ( $snak instanceof PropertyValueSnak ) { |
166 | $serializer = new DataValueSerializer(); |
167 | $serialized = $serializer->serialize( $snak->getDataValue() ); |
168 | |
169 | $data = json_encode( $serialized ); |
170 | $property = $snak->getPropertyId()->getSerialization(); |
171 | $html = $this->formatSnak( $snak, SnakFormatter::FORMAT_HTML ); |
172 | $plain = $this->formatSnak( $snak, SnakFormatter::FORMAT_PLAIN ); |
173 | |
174 | $result[$data][SnakFormatter::FORMAT_HTML][$this->languageCode][$property] = $html; |
175 | $result[$data][SnakFormatter::FORMAT_PLAIN][$this->languageCode][$property] = $plain; |
176 | } |
177 | |
178 | return $result; |
179 | } |
180 | |
181 | /** |
182 | * @param DataValue $value |
183 | * @param string[] $formats |
184 | * @return array |
185 | */ |
186 | private function getValueFormatValueCache( DataValue $value, $formats = [ SnakFormatter::FORMAT_PLAIN ] ) { |
187 | $result = []; |
188 | |
189 | $serializer = new DataValueSerializer(); |
190 | $serialized = $serializer->serialize( $value ); |
191 | |
192 | $data = json_encode( $serialized ); |
193 | foreach ( $formats as $format ) { |
194 | $result[$data][$format][$this->languageCode][''] = $this->formatValue( $value, $format ); |
195 | } |
196 | |
197 | return $result; |
198 | } |
199 | |
200 | /** |
201 | * @param string $propertyIdString |
202 | * @param Statement[] $statements |
203 | * @return PanelLayout |
204 | */ |
205 | private function getLayoutForProperty( $propertyIdString, array $statements ) { |
206 | $statementSerializer = $this->serializerFactory->newStatementSerializer(); |
207 | |
208 | $serializedStatements = []; |
209 | $formatValueCache = []; |
210 | |
211 | $itemsGroupDiv = new Tag( 'div' ); |
212 | $itemsGroupDiv->addClasses( [ 'wbmi-content-items-group' ] ); |
213 | foreach ( $statements as $statement ) { |
214 | $itemsGroupDiv->appendContent( $this->createStatementDiv( $statement ) ); |
215 | $serializedStatements[] = $statementSerializer->serialize( $statement ); |
216 | $formatValueCache = array_replace_recursive( |
217 | $formatValueCache, |
218 | $this->getStatementFormatValueCache( $statement ) |
219 | ); |
220 | } |
221 | |
222 | // Format main property (e.g. depicts). |
223 | if ( $statements ) { |
224 | $formatValueCache = array_replace_recursive( |
225 | $formatValueCache, |
226 | $this->getValueFormatValueCache( |
227 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable |
228 | new EntityIdValue( $statement->getPropertyId() ), |
229 | [ SnakFormatter::FORMAT_HTML ] |
230 | ) |
231 | ); |
232 | } |
233 | |
234 | $panelClasses = [ |
235 | 'wbmi-entityview-statementsGroup', |
236 | self::getHtmlContainerClass( $propertyIdString ), |
237 | ]; |
238 | |
239 | $panel = new PanelLayout( [ |
240 | 'classes' => $panelClasses, |
241 | 'id' => $propertyIdString, |
242 | 'scrollable' => false, |
243 | 'padded' => false, |
244 | 'expanded' => false, |
245 | 'framed' => true, |
246 | 'content' => [ |
247 | ( new Tag( 'div' ) ) |
248 | ->addClasses( [ 'wbmi-statements-widget' ] ) |
249 | ->appendContent( |
250 | $this->createPropertyHeader( $propertyIdString ), |
251 | $itemsGroupDiv |
252 | ), |
253 | ] |
254 | ] ); |
255 | $panel->setAttributes( |
256 | [ |
257 | 'data-property' => $propertyIdString, |
258 | 'data-statements' => json_encode( $serializedStatements ), |
259 | 'data-formatvalue' => json_encode( $formatValueCache ), |
260 | ] |
261 | ); |
262 | return $panel; |
263 | } |
264 | |
265 | private function createPropertyHeader( $propertyIdString ) { |
266 | $propertyId = new NumericPropertyId( $propertyIdString ); |
267 | |
268 | $propertyTitle = $this->createFormattedDataValue( |
269 | new HtmlSnippet( $this->formatEntityId( $propertyId, SnakFormatter::FORMAT_HTML ) ) |
270 | ); |
271 | |
272 | /* |
273 | * Here's quite an odd way to render a title... |
274 | * We want to keep this place mostly generic, so that it doesn't |
275 | * really matter what property we're dealing with. `Depicts` (or |
276 | * any other) is not different from the next. |
277 | * However, it looks like we (may) want to have specific titles |
278 | * (https://phabricator.wikimedia.org/T216757 asks for one for |
279 | * depicts on commons) |
280 | * Instead of hardcoding this, let's just see if a message exist |
281 | * that uses the descriptive name that was used for the property |
282 | * ID in extension.json: for a property { depicts: P1 }, we'll |
283 | * see if we can find an image with i18n key |
284 | * wikibasemediainfo-statements-title-depicts, and if so, display |
285 | * a title. If not, no title... This allows any wiki to set up |
286 | * any property/statement group with any title, or none at all. |
287 | */ |
288 | $name = array_search( $propertyIdString, $this->properties ); |
289 | // possible messages include: |
290 | // wikibasemediainfo-statements-title-depicts |
291 | $message = wfMessage( 'wikibasemediainfo-statements-title-' . ( $name ?: '' ) ); |
292 | if ( $name !== false && $message->exists() ) { |
293 | $title = new Tag( 'h3' ); |
294 | $title->addClasses( [ 'wbmi-statements-title' ] ); |
295 | $title->appendContent( $message->text() ); |
296 | |
297 | $propertyTitle->prependContent( $title ); |
298 | } |
299 | |
300 | $header = new Tag( 'div' ); |
301 | $header->addClasses( [ 'wbmi-statement-header' ] ); |
302 | $header->appendContent( |
303 | ( new Tag( 'div' ) ) |
304 | ->addClasses( [ 'wbmi-entity-data' ] ) |
305 | ->appendContent( $propertyTitle ) |
306 | ); |
307 | |
308 | return $header; |
309 | } |
310 | |
311 | /** |
312 | * @param string $formattedValue |
313 | * @return Tag |
314 | */ |
315 | private function createFormattedDataValue( $formattedValue ) { |
316 | // Wrap value in a <bdi> tag (bi-directional isolate) so that things |
317 | // like coordinate strings (with both numerical and non-numerical |
318 | // symbols) do not get mangled when flipped to RTL |
319 | $bdi = new Tag( 'bdi' ); |
320 | $bdi->appendContent( $formattedValue ); |
321 | |
322 | $label = new Tag( 'h4' ); |
323 | $label->addClasses( [ 'wbmi-entity-label' ] ); |
324 | $label->appendContent( $bdi ); |
325 | |
326 | $tag = new Tag( 'div' ); |
327 | $tag->addClasses( [ 'wbmi-entity-title' ] ); |
328 | $tag->appendContent( $label ); |
329 | |
330 | return $tag; |
331 | } |
332 | |
333 | private function createStatementDiv( Statement $statement ) { |
334 | $div = new Tag( 'div' ); |
335 | $div->appendContent( $this->innerStatementDiv( $statement ) ); |
336 | $div->addClasses( [ 'wbmi-item', 'wbmi-item-read' ] ); |
337 | return $div; |
338 | } |
339 | |
340 | private function innerStatementDiv( Statement $statement ) { |
341 | $mainSnak = $statement->getMainSnak(); |
342 | |
343 | $statementDiv = new Tag( 'div' ); |
344 | $statementDiv->addClasses( [ 'wbmi-item-container' ] ); |
345 | |
346 | $guid = $statement->getGuid(); |
347 | if ( $guid !== null ) { |
348 | $statementDiv->setAttributes( [ 'data-guid' => $guid ] ); |
349 | } |
350 | |
351 | $mainSnakDiv = new Tag( 'div' ); |
352 | $mainSnakDiv->addClasses( [ 'wbmi-entity-header' ] ); |
353 | $mainSnakDiv->appendContent( |
354 | ( new Tag( 'div' ) ) |
355 | ->addClasses( [ 'wbmi-entity-data' ] ) |
356 | ->appendContent( |
357 | $this->createFormattedDataValue( |
358 | new HtmlSnippet( $this->formatSnak( $mainSnak, SnakFormatter::FORMAT_HTML ) ) |
359 | ) |
360 | ) |
361 | ); |
362 | |
363 | $statementDiv->appendContent( $mainSnakDiv ); |
364 | |
365 | $qualifiers = $statement->getQualifiers(); |
366 | if ( count( $qualifiers ) > 0 ) { |
367 | $qualifiersContainer = new Tag( 'div' ); |
368 | $qualifiersContainer->addClasses( [ 'wbmi-item-qualifiers' ] ); |
369 | $qualifiersContainer->appendContent( $this->renderSnakList( $qualifiers ) ); |
370 | |
371 | $statementDiv->appendContent( $qualifiersContainer ); |
372 | } |
373 | |
374 | $referenceList = $statement->getReferences(); |
375 | if ( count( $referenceList ) > 0 ) { |
376 | $referencesContainer = new Tag( 'div' ); |
377 | $referencesContainer->addClasses( [ 'wbmi-item-references' ] ); |
378 | |
379 | foreach ( $referenceList as $reference ) { |
380 | $snakList = $reference->getSnaks(); |
381 | if ( count( $snakList ) > 0 ) { |
382 | $referenceSnaklist = new Tag( 'div' ); |
383 | $referenceSnaklist->addClasses( [ 'wbmi-snaklist' ] ); |
384 | $referencesContainer->appendContent( $referenceSnaklist ); |
385 | |
386 | $referenceTitle = new Tag( 'h5' ); |
387 | $referenceTitle->addClasses( [ 'wbmi-snaklist-title' ] ); |
388 | $referenceTitle->appendContent( |
389 | wfMessage( 'wikibasemediainfo-statements-item-reference' )->escaped() |
390 | ); |
391 | $referenceSnaklist->appendContent( $referenceTitle ); |
392 | |
393 | // @phan-suppress-next-line PhanTypeMismatchArgumentSuperType |
394 | $referenceSnaklist->appendContent( $this->renderSnakList( $snakList ) ); |
395 | } |
396 | } |
397 | |
398 | $statementDiv->appendContent( $referencesContainer ); |
399 | } |
400 | |
401 | return $statementDiv; |
402 | } |
403 | |
404 | private function renderSnakList( SnakList $snakList ) { |
405 | $propertyOrder = $this->propertyOrderProvider->getPropertyOrder(); |
406 | if ( $propertyOrder === null ) { |
407 | $snakList->orderByProperty(); |
408 | } else { |
409 | $propertyIds = array_flip( $propertyOrder ); |
410 | ksort( $propertyIds ); |
411 | $snakList->orderByProperty( |
412 | array_values( $propertyIds ) |
413 | ); |
414 | } |
415 | |
416 | $snakDivs = []; |
417 | |
418 | /** @var Snak $snak */ |
419 | foreach ( $snakList as $snak ) { |
420 | $formattedProperty = ''; |
421 | if ( $snak instanceof SnakObject ) { |
422 | $formattedProperty = $this->formatEntityId( $snak->getPropertyId(), SnakFormatter::FORMAT_HTML ); |
423 | } |
424 | |
425 | $formattedValue = $this->formatSnak( $snak, SnakFormatter::FORMAT_HTML ); |
426 | $formattedValueTag = new Tag( 'span' ); |
427 | $formattedValueTag->addClasses( [ 'wbmi-snak-value--value' ] ); |
428 | $formattedValueTag->appendContent( new HtmlSnippet( $formattedValue ) ); |
429 | |
430 | $separator = new Tag( 'span' ); |
431 | $separator->addClasses( [ 'wbmi-snak-value-separator' ] ); |
432 | $separator->appendContent( $this->textProvider->get( 'colon-separator' ) ); |
433 | |
434 | $snakValueDiv = new Tag( 'div' ); |
435 | $snakValueDiv->addClasses( [ 'wbmi-snak-value' ] ); |
436 | $snakValueDiv->appendContent( |
437 | new HtmlSnippet( $formattedProperty ), |
438 | // if we have both a property & a value, add a separator |
439 | $formattedProperty && $formattedValue ? $separator : '', |
440 | $formattedValueTag |
441 | ); |
442 | |
443 | $snakDiv = new Tag( 'div' ); |
444 | $snakDiv->addClasses( [ 'wbmi-snak' ] ); |
445 | $snakDiv->appendContent( $snakValueDiv ); |
446 | |
447 | $snakDivs[] = $snakDiv; |
448 | } |
449 | |
450 | $snakListDiv = new Tag( 'div' ); |
451 | $snakListDiv->addClasses( [ 'wbmi-snaklist-content' ] ); |
452 | $snakListDiv->appendContent( ...$snakDivs ); |
453 | |
454 | $snakListContainer = new Tag( 'div' ); |
455 | $snakListContainer->addClasses( [ 'wbmi-snaklist-container' ] ); |
456 | $snakListContainer->appendContent( $snakListDiv ); |
457 | |
458 | return $snakListContainer; |
459 | } |
460 | |
461 | /** |
462 | * @param Snak $snak |
463 | * @param string $format |
464 | * @return string |
465 | */ |
466 | private function formatSnak( Snak $snak, $format = SnakFormatter::FORMAT_PLAIN ) { |
467 | if ( $snak instanceof PropertyNoValueSnak ) { |
468 | return wfMessage( 'wikibasemediainfo-filepage-statement-no-value' )->escaped(); |
469 | } |
470 | |
471 | if ( $snak instanceof PropertySomeValueSnak ) { |
472 | return wfMessage( 'wikibasemediainfo-filepage-statement-some-value' )->escaped(); |
473 | } |
474 | |
475 | $formatter = $this->snakFormatterFactory->getSnakFormatter( |
476 | $format, |
477 | new FormatterOptions( [ ValueFormatter::OPT_LANG => $this->languageCode ] ) |
478 | ); |
479 | |
480 | try { |
481 | $formatted = $formatter->formatSnak( $snak ); |
482 | |
483 | // if there are any links inside the formatted content, make them open in a new window |
484 | return preg_replace( '/<a/', '<a target="_blank"', $formatted ); |
485 | } catch ( Exception $e ) { |
486 | return wfMessage( 'wikibasemediainfo-filepage-statement-invalid-value' )->escaped(); |
487 | } |
488 | } |
489 | |
490 | /** |
491 | * @param DataValue $value |
492 | * @param string $format |
493 | * @return string |
494 | */ |
495 | private function formatValue( DataValue $value, $format = SnakFormatter::FORMAT_PLAIN ) { |
496 | $formatter = $this->valueFormatterFactory->getValueFormatter( |
497 | $format, |
498 | new FormatterOptions( [ ValueFormatter::OPT_LANG => $this->languageCode ] ) |
499 | ); |
500 | |
501 | $formatted = $formatter->formatValue( $value ); |
502 | |
503 | // if there are any links inside the formatted content, make them open in a new window |
504 | return preg_replace( '/<a/', '<a target="_blank"', $formatted ); |
505 | } |
506 | |
507 | /** |
508 | * @param EntityId $entityId |
509 | * @param string $format |
510 | * @return string |
511 | */ |
512 | private function formatEntityId( EntityId $entityId, $format = SnakFormatter::FORMAT_PLAIN ) { |
513 | return $this->formatValue( new EntityIdValue( $entityId ), $format ); |
514 | } |
515 | |
516 | /** |
517 | * Gather statements into an array with property ids (ordered by $this->propertyOrderProvider) |
518 | * as keys, and arrays of statements pertaining to those property ids (ordered by rank) as |
519 | * values |
520 | * |
521 | * @param StatementList $statementList |
522 | * @return array[] |
523 | */ |
524 | private function statementsByPropertyId( StatementList $statementList ) { |
525 | $statementsByProperty = $this->getOrderedStatementsByProperty( $statementList ); |
526 | |
527 | $propertyOrder = $this->propertyOrderProvider->getPropertyOrder(); |
528 | |
529 | if ( !$propertyOrder ) { |
530 | return $statementsByProperty; |
531 | } |
532 | |
533 | $ordered = []; |
534 | $unordered = []; |
535 | |
536 | foreach ( $statementsByProperty as $propertyId => $statements ) { |
537 | if ( isset( $propertyOrder[$propertyId] ) ) { |
538 | $ordered[$propertyOrder[$propertyId]] = [ |
539 | 'propertyId' => $propertyId, |
540 | 'statements' => $statements |
541 | ]; |
542 | } else { |
543 | $unordered[] = [ |
544 | 'propertyId' => $propertyId, |
545 | 'statements' => $statements |
546 | ]; |
547 | } |
548 | } |
549 | |
550 | ksort( $ordered ); |
551 | $orderedButNotIndexed = array_merge( $ordered, $unordered ); |
552 | $orderedAndIndexed = []; |
553 | foreach ( $orderedButNotIndexed as $statementArray ) { |
554 | $orderedAndIndexed[ $statementArray[ 'propertyId' ] ] = $statementArray[ 'statements' ]; |
555 | } |
556 | return $orderedAndIndexed; |
557 | } |
558 | |
559 | /** |
560 | * Returns array with property ids as keys and arrays of statements as elements. The arrays |
561 | * of statements are ordered by rank. |
562 | * |
563 | * @param StatementList $statementList |
564 | * @return array[] |
565 | */ |
566 | private function getOrderedStatementsByProperty( StatementList $statementList ) { |
567 | $statementsByPropertyAndRank = []; |
568 | foreach ( $statementList as $statement ) { |
569 | $propertyId = $statement->getPropertyId()->getSerialization(); |
570 | if ( !isset( $statementsByPropertyAndRank[$propertyId] ) ) { |
571 | $statementsByPropertyAndRank[$propertyId] = [ |
572 | Statement::RANK_PREFERRED => [], |
573 | Statement::RANK_NORMAL => [], |
574 | Statement::RANK_DEPRECATED => [], |
575 | ]; |
576 | } |
577 | $rank = $statement->getRank(); |
578 | $statementsByPropertyAndRank[$propertyId][$rank][] = $statement; |
579 | } |
580 | |
581 | $statementsByProperty = []; |
582 | foreach ( $statementsByPropertyAndRank as $propertyId => $array ) { |
583 | $statementsByProperty[$propertyId] = array_merge( |
584 | $array[Statement::RANK_PREFERRED], |
585 | $array[Statement::RANK_NORMAL], |
586 | $array[Statement::RANK_DEPRECATED] |
587 | ); |
588 | } |
589 | |
590 | $statementsByProperty = $this->addDefaultStatements( $statementsByProperty ); |
591 | |
592 | return $statementsByProperty; |
593 | } |
594 | |
595 | private function addDefaultStatements( $statementsByProperty ) { |
596 | foreach ( $this->defaultPropertyIds as $propertyId ) { |
597 | if ( !isset( $statementsByProperty[ $propertyId->getSerialization() ] ) ) { |
598 | $statementsByProperty[ $propertyId->getSerialization() ] = []; |
599 | } |
600 | } |
601 | return $statementsByProperty; |
602 | } |
603 | |
604 | } |