Completed
Push — master ( 2472c5...a814e8 )
by mw
35:03
created

PropertySpecificationLookup   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 454
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 97.96%

Importance

Changes 0
Metric Value
dl 0
loc 454
ccs 144
cts 147
cp 0.9796
rs 6.8
c 0
b 0
f 0
wmc 55
lcom 1
cbo 12

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A resetCacheBy() 0 3 1
A getLanguageCode() 0 3 1
A setLanguageCode() 0 3 1
B getFieldListBy() 0 23 4
A getPreferredPropertyLabelBy() 0 19 3
B getPropertyFromDisplayTitle() 0 27 3
B hasUniquenessConstraintBy() 0 23 4
A getExternalFormatterUriBy() 0 15 3
B getAllowedPatternBy() 0 23 4
B getAllowedValuesBy() 0 23 4
A getDisplayPrecisionBy() 0 16 3
A getDisplayUnitsBy() 0 17 4
B getPropertyDescriptionBy() 0 36 6
B getPredefinedPropertyDescription() 0 27 4
A findLocalPropertyDescription() 0 16 2
A findPreferredPropertyLabel() 0 16 2
B findTextValueByLanguage() 0 24 5

How to fix   Complexity   

Complex Class

Complex classes like PropertySpecificationLookup often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PropertySpecificationLookup, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SMW;
4
5
use SMW\Query\DescriptionFactory;
6
use Onoi\Cache\Cache;
7
use SMW\Message;
8
use SMWDIBlob as DIBlob;
9
use SMWQuery as Query;
10
11
/**
12
 * This class should be accessed via ApplicationFactory::getPropertySpecificationLookup
13
 * to ensure a singleton instance.
14
 *
15
 * @license GNU GPL v2+
16
 * @since 2.4
17
 *
18
 * @author mwjames
19
 */
20
class PropertySpecificationLookup {
21
22
	const POOLCACHE_ID = 'property.specification.lookup';
23
24
	/**
25
	 * @var CachedPropertyValuesPrefetcher
26
	 */
27
	private $cachedPropertyValuesPrefetcher;
28
29
	/**
30
	 * @var string
31
	 */
32
	private $languageCode = 'en';
33
34
	/**
35
	 * @var Cache
36
	 */
37
	private $intermediaryMemoryCache;
38
39
	/**
40
	 * @since 2.4
41
	 *
42
	 * @param CachedPropertyValuesPrefetcher $cachedPropertyValuesPrefetcher
43
	 * @param Cache $intermediaryMemoryCache
44
	 */
45 243
	public function __construct( CachedPropertyValuesPrefetcher $cachedPropertyValuesPrefetcher, Cache $intermediaryMemoryCache ) {
46 243
		$this->cachedPropertyValuesPrefetcher = $cachedPropertyValuesPrefetcher;
47 243
		$this->intermediaryMemoryCache = $intermediaryMemoryCache;
48 243
	}
49
50
	/**
51
	 * @since 2.4
52
	 */
53 158
	public function resetCacheBy( DIWikiPage $subject ) {
54 158
		$this->cachedPropertyValuesPrefetcher->resetCacheBy( $subject );
55 158
	}
56
57
	/**
58
	 * @since 2.4
59
	 *
60
	 * @param string
61
	 */
62
	public function getLanguageCode() {
63
		return $this->languageCode;
64
	}
65
66
	/**
67
	 * @since 2.4
68
	 *
69
	 * @param string $languageCode
70
	 */
71 233
	public function setLanguageCode( $languageCode ) {
72 233
		$this->languageCode = Localizer::asBCP47FormattedLanguageCode( $languageCode );
73 233
	}
74
75
	/**
76
	 * @since 2.5
77
	 *
78
	 * @param DIProperty $property
79
	 *
80
	 * @return false|DataItem
81
	 */
82
	public function getFieldListBy( DIProperty $property ) {
83 232
84
		$fieldList = false;
85 232
		$key = 'list:'. $property->getKey();
86 232
87
		// Guard against high frequency lookup
88
		if ( $this->intermediaryMemoryCache->contains( $key ) ) {
89 232
			return $this->intermediaryMemoryCache->fetch( $key );
90 203
		}
91
92
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
93 201
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
94 201
			new DIProperty( '_LIST' )
95
		);
96
97
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
98 201
			$fieldList = end( $dataItems );
99
		}
100 201
101
		$this->intermediaryMemoryCache->save( $key, $fieldList );
102
103
		return $fieldList;
104
	}
105
106
	/**
107
	 * @since 2.5
108
	 *
109
	 * @param string $id
110 1
	 * @param string $languageCode
111
	 *
112 1
	 * @return string
113
	 */
114 1
	public function getPreferredPropertyLabelBy( $id, $languageCode = '' ) {
115 1
116 1
		$languageCode = $languageCode === '' ? $this->languageCode : $languageCode;
117
		$key = 'ppl:' . $languageCode  . ':'. $id;
118
119 1
		// Guard against high frequency lookup
120 1
		if ( ( $preferredPropertyLabel = $this->intermediaryMemoryCache->fetch( $key ) ) !== false ) {
121
			return $preferredPropertyLabel;
122 1
		}
123
124
		$preferredPropertyLabel = $this->findPreferredPropertyLabel(
125
			new DIProperty( str_replace( ' ', '_', $id ) ),
126 1
			$languageCode
127 1
		);
128
129
		$this->intermediaryMemoryCache->save( $key, $preferredPropertyLabel );
130
131
		return $preferredPropertyLabel;
132 1
	}
133
134
	/**
135
	 * @since 2.4
136
	 *
137
	 * @param string $displayTitle
138
	 *
139
	 * @return DIProperty|false
140
	 */
141
	public function getPropertyFromDisplayTitle( $displayTitle ) {
142
143
		$descriptionFactory = new DescriptionFactory();
144
145 4
		$description = $descriptionFactory->newSomeProperty(
146
			new DIProperty( '_DTITLE' ),
147 4
			$descriptionFactory->newValueDescription( new DIBlob( $displayTitle ) )
148 4
		);
149
150
		$query = new Query( $description );
151 4
		$query->setLimit( 1 );
152 3
153
		$dataItems = $this->cachedPropertyValuesPrefetcher->queryPropertyValuesFor(
154
			$query
155 4
		);
156 4
157 4
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
158
			$dataItem = end( $dataItems );
159
160 4
			// Cache results as a linked list attached to
161 4
			// the property so that it can be purged all together
162
163
			return new DIProperty( $dataItem->getDBKey() );
164 4
		}
165
166 4
		return false;
167
	}
168
169
	/**
170
	 * @since 2.4
171
	 *
172
	 * @param DIProperty $property
173
	 *
174
	 * @return boolean
175
	 */
176 2
	public function hasUniquenessConstraintBy( DIProperty $property ) {
177
178 2
		$hasUniquenessConstraint = false;
179
		$key = 'uc:'. $property->getKey();
180 2
181 2
		// Guard against high frequency lookup
182 2
		if ( $this->intermediaryMemoryCache->contains( $key ) ) {
183
			return $this->intermediaryMemoryCache->fetch( $key );
184
		}
185 2
186 2
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
187
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
188
			new DIProperty( '_PVUC' )
189 2
		);
190
191
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
192
			$hasUniquenessConstraint = end( $dataItems )->getBoolean();
193
		}
194
195
		$this->intermediaryMemoryCache->save( $key, $hasUniquenessConstraint );
196
197
		return $hasUniquenessConstraint;
198
	}
199 198
200
	/**
201 198
	 * @since 2.5
202 198
	 *
203
	 * @param DIProperty $property
204
	 *
205 198
	 * @return DataItem|null
206 163
	 */
207
	public function getExternalFormatterUriBy( DIProperty $property ) {
208
209 177
		$dataItem = null;
210 177
211 177
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
212
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
213
			new DIProperty( '_PEFU' )
214 177
		);
215 2
216
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
217
			$dataItem = end( $dataItems );
218 177
		}
219
220 177
		return $dataItem;
221
	}
222
223
	/**
224
	 * @since 2.4
225
	 *
226
	 * @param DIProperty $property
227
	 *
228
	 * @return string
229
	 */
230 206
	public function getAllowedPatternBy( DIProperty $property ) {
231
232 206
		$allowsPattern = '';
233 206
		$key = 'ap:'. $property->getKey();
234
235
		// Guard against high frequency lookup
236 206
		if ( $this->intermediaryMemoryCache->contains( $key ) ) {
237 174
			return $this->intermediaryMemoryCache->fetch( $key );
238
		}
239
240 185
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
241 185
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
242 185
			new DIProperty( '_PVAP' )
243
		);
244
245 185
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
246 5
			$allowsPattern = end( $dataItems )->getString();
247
		}
248
249 185
		$this->intermediaryMemoryCache->save( $key, $allowsPattern );
250
251 185
		return $allowsPattern;
252
	}
253
254
	/**
255
	 * @since 2.4
256
	 *
257
	 * @param DIProperty $property
258
	 *
259
	 * @return integer|false
260
	 */
261 40
	public function getAllowedValuesBy( DIProperty $property ) {
262
263 40
		$allowsValues = array();
264
		$key = 'al:'. $property->getKey();
265 40
266 40
		// Guard against high frequency lookup
267 40
		if ( $this->intermediaryMemoryCache->contains( $key ) ) {
268
			return $this->intermediaryMemoryCache->fetch( $key );
269
		}
270 40
271 4
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
272 4
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
273
			new DIProperty( '_PVAL' )
274
		);
275 40
276
		if ( is_array( $dataItems ) && $dataItems !== array() ) {
277
			$allowsValues = $dataItems;
278
		}
279
280
		$this->intermediaryMemoryCache->save( $key, $allowsValues );
281
282
		return $allowsValues;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $allowsValues; (array) is incompatible with the return type documented by SMW\PropertySpecificatio...kup::getAllowedValuesBy of type integer|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
283
	}
284
285 18
	/**
286
	 * @since 2.4
287 18
	 *
288
	 * @param DIProperty $property
289 18
	 *
290 18
	 * @return integer|false
291 18
	 */
292
	public function getDisplayPrecisionBy( DIProperty $property ) {
293
294 18
		$displayPrecision = false;
295 6
296 6
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
297
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
298
			new DIProperty( '_PREC' )
299
		);
300 18
301
		if ( $dataItems !== false && $dataItems !== array() ) {
302
			$dataItem = end( $dataItems );
303
			$displayPrecision = abs( (int)$dataItem->getNumber() );
304
		}
305
306
		return $displayPrecision;
307
	}
308
309
	/**
310
	 * @since 2.4
311
	 *
312
	 * @param DIProperty $property
313
	 *
314
	 * @return array
315
	 */
316
	public function getDisplayUnitsBy( DIProperty $property ) {
317
318 66
		$units = array();
319
320
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
321 66
			$property->getCanonicalDiWikiPage(),
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getPropertyValues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
322 66
			new DIProperty( '_UNIT' )
323
		);
324 66
325
		if ( $dataItems !== false && $dataItems !== array() ) {
326 66
			foreach ( $dataItems as $dataItem ) {
327 66
				$units = array_merge( $units, preg_split( '/\s*,\s*/u', $dataItem->getString() ) );
328
			}
329
		}
330 66
331 51
		return $units;
332
	}
333
334 65
	/**
335
	 * We try to cache anything to avoid unnecessary store connections or DB
336
	 * lookups. For cases where a property was changed, the EventDipatcher will
337
	 * receive a 'property.specification.change' event (emitted as soon as the content of
338
	 * a property page was altered) with PropertySpecificationLookup::resetCacheBy
339
	 * being invoked to remove the cache entry for that specific property.
340
	 *
341
	 * @since 2.4
342 65
	 *
343 14
	 * @param DIProperty $property
344
	 * @param mixed|null $linker
345
	 * @param string $languageCode
346 65
	 *
347
	 * @return string
348 65
	 */
349
	public function getPropertyDescriptionBy( DIProperty $property, $linker = null, $languageCode = '' ) {
350
351
		// Take the linker into account (Special vs. in page rendering etc.)
352 65
		$languageCode = $languageCode === '' ? $this->languageCode : $languageCode;
353
		$key = '--pdesc:' . $languageCode . ':' . ( $linker === null ? '0' : '1' );
354
355 14
		$blobStore = $this->cachedPropertyValuesPrefetcher->getBlobStore();
356
357 14
		$container = $blobStore->read(
358 14
			$this->cachedPropertyValuesPrefetcher->getRootHashFrom( $property->getCanonicalDiWikiPage() )
0 ignored issues
show
Bug introduced by
It seems like $property->getCanonicalDiWikiPage() can be null; however, getRootHashFrom() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
359
		);
360 14
361 14
		if ( $container->has( $key ) ) {
362
			return $container->get( $key );
363
		}
364 14
365 1
		$localPropertyDescription = $this->findLocalPropertyDescription(
366
			$property,
367
			$linker,
368 14
			$languageCode
369
		);
370
371
		// If a local property description wasn't available for a predefined property
372 14
		// the try to find a system translation
373
		if ( trim( $localPropertyDescription ) === '' && !$property->isUserDefined() ) {
374 14
			$localPropertyDescription = $this->getPredefinedPropertyDescription( $property, $linker, $languageCode );
375 14
		}
376 14
377
		$container->set( $key, $localPropertyDescription );
378
379
		$blobStore->save(
380 14
			$container
381
		);
382
383 65
		return $localPropertyDescription;
384
	}
385 65
386 65
	private function getPredefinedPropertyDescription( $property, $linker, $languageCode ) {
387
388 65
		$description = '';
389 65
		$key = $property->getKey();
390
391
		if ( ( $msgKey = PropertyRegistry::getInstance()->findPropertyDescriptionMsgKeyById( $key ) ) === '' ) {
392
			$msgKey = 'smw-pa-property-predefined' . strtolower( $key );
393 65
		}
394 6
395
		if ( !Message::exists( $msgKey ) ) {
396
			return $description;
397 65
		}
398
399
		$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
400 201
			$property
401
		);
402 201
403 201
		$label = $dataValue->getFormattedLabel();
404
405 201
		$message = Message::get(
406 201
			array( $msgKey, $label ),
407
			$linker === null ? Message::ESCAPED : Message::PARSE,
408
			$languageCode
409
		);
410 201
411 3
		return $message;
412
	}
413
414 201
	private function findLocalPropertyDescription( $property, $linker, $languageCode ) {
415
416
		$text = '';
417 204
		$descriptionProperty = new DIProperty( '_PDESC' );
418
419 204
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
420 203
			$property->getCanonicalDiWikiPage(),
421
			$descriptionProperty
422
		);
423 8
424
		if ( ( $dataValue = $this->findTextValueByLanguage( $dataItems, $descriptionProperty, $languageCode ) ) !== null ) {
425 8
			$text = $dataValue->getShortWikiText( $linker );
426
		}
427
428
		return $text;
429
	}
430
431
	private function findPreferredPropertyLabel( $property, $languageCode ) {
432 8
433
		$text = '';
434 8
		$preferredProperty = new DIProperty( '_PPLB' );
435 8
436
		$dataItems = $this->cachedPropertyValuesPrefetcher->getPropertyValues(
437
			$property->getCanonicalDiWikiPage(),
438
			$preferredProperty
439 1
		);
440
441
		if ( ( $dataValue = $this->findTextValueByLanguage( $dataItems, $preferredProperty, $languageCode ) ) !== null ) {
442
			$text = $dataValue->getShortWikiText();
443
		}
444
445
		return $text;
446
	}
447
448
	private function findTextValueByLanguage( $dataItems, $property, $languageCode ) {
449
450
		if ( $dataItems === null || $dataItems === array() ) {
451
			return null;
452
		}
453
454
		foreach ( $dataItems as $dataItem ) {
455
456
			$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
457
				$dataItem,
458
				$property
459
			);
460
461
			// Here a MonolingualTextValue was retunred therefore the method
462
			// can be called without validation
463
			$dv = $dataValue->getTextValueByLanguage( $languageCode );
464
465
			if ( $dv !== null ) {
466
				return $dv;
467
			}
468
		}
469
470
		return null;
471
	}
472
473
}
474