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

src/DataValues/MonolingualTextValue.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SMW\DataValues;
4
5
use SMW\ApplicationFactory;
6
use SMW\DataValueFactory;
7
use SMW\DataValues\ValueFormatters\DataValueFormatter;
8
use SMW\DataValues\ValueParsers\MonolingualTextValueParser;
9
use SMW\DIProperty;
10
use SMW\DIWikiPage;
11
use SMW\Localizer;
12
use SMW\StringCondition;
13
use SMWContainerSemanticData as ContainerSemanticData;
14
use SMWDataItem as DataItem;
15
use SMWDataValue as DataValue;
16
use SMWDIContainer as DIContainer;
17
use SMWDIBlob as DIBlob;
18
19
/**
20
 * MonolingualTextValue requires two components, a language code and a
21
 * text.
22
 *
23
 * A text `foo@en` is expected to be invoked with a BCP47 language
24
 * code tag and a language dependent text component.
25
 *
26
 * Internally, the value is stored as container object that represents
27
 * the language code and text as separate entities in order to be queried
28
 * individually.
29
 *
30
 * External output representation depends on the context (wiki, html)
31
 * whether the language code is omitted or not.
32
 *
33
 * @license GNU GPL v2+
34
 * @since 2.4
35
 *
36
 * @author mwjames
37
 */
38
class MonolingualTextValue extends AbstractMultiValue {
39
40
	/**
41
	 * @var DIProperty[]|null
42
	 */
43
	private static $properties = null;
44
45
	/**
46
	 * @var MonolingualTextValueParser
47
	 */
48
	private $monolingualTextValueParser = null;
49
50
	/**
51
	 * @param string $typeid
52
	 */
53 29
	public function __construct( $typeid = '' ) {
54 29
		parent::__construct( '_mlt_rec' );
55 29
	}
56
57
	/**
58
	 * @see AbstractMultiValue::setFieldProperties
59
	 *
60
	 * @param DIProperty[] $properties
61
	 */
62
	public function setFieldProperties( array $properties ) {
63
		// Keep the interface while the properties for this type
64
		// are fixed.
65
	}
66
67
	/**
68
	 * @see AbstractMultiValue::getProperties
69
	 *
70
	 * @param DIProperty[] $properties
71
	 */
72
	public function getProperties() {
73
		self::$properties;
74
	}
75
76
	/**
77
	 * @since 2.5
78
	 *
79
	 * @param $userValue
80
	 * @param string $languageCode
81
	 *
82
	 * @return string
83
	 */
84 1
	public function getTextWithLanguageTag( $text, $languageCode ) {
85 1
		return $text . '@' . Localizer::asBCP47FormattedLanguageCode( $languageCode );
86
	}
87
88
	/**
89
	 * @see DataValue::parseUserValue
90
	 * @note called by DataValue::setUserValue
91
	 *
92
	 * @param string $userValue
93
	 */
94 26
	protected function parseUserValue( $userValue ) {
95
96 26
		list( $text, $languageCode ) = $this->getValuesFromString( $userValue );
97
98 26
		$languageCodeValue = $this->newLanguageCodeValue( $languageCode );
99
100
		if (
101 26
			( $languageCode !== '' && $languageCodeValue->getErrors() !== array() ) ||
102 26
			( $languageCode === '' && $this->isEnabledFeature( SMW_DV_MLTV_LCODE ) ) ) {
103 3
			$this->addError( $languageCodeValue->getErrors() );
104 3
			return;
105
		}
106
107 23
		$dataValues = array();
108
109 23
		foreach ( $this->getPropertyDataItems() as $property ) {
110
111
			if (
112 23
				( $languageCode === '' && $property->getKey() === '_LCODE' ) ||
113 23
				( $text === '' && $property->getKey() === '_TEXT' ) ) {
114 1
				continue;
115
			}
116
117 23
			$value = $text;
118
119 23
			if ( $property->getKey() === '_LCODE' ) {
120 22
				$value = $languageCode;
121
			}
122
123 23
			$dataValue = DataValueFactory::getInstance()->newDataValueByProperty(
124
				$property,
125
				$value,
126 23
				false,
127 23
				$this->m_contextPage
128
			);
129
130 23
			$this->addError( $dataValue->getErrors() );
131
132 23
			$dataValues[] = $dataValue;
133
		}
134
135
		// Generate a hash from the normalized representation so that foo@en being
136
		// the same as foo@EN independent of a user input
137 23
		$containerSemanticData = $this->newContainerSemanticData( $text . '@' . $languageCode );
138
139 23
		foreach ( $dataValues as $dataValue ) {
140 23
			$containerSemanticData->addDataValue( $dataValue );
141
		}
142
143 23
		$this->m_dataitem = new DIContainer( $containerSemanticData );
144
145
		// Composite sortkey is to ensure that Store::getPropertyValues can
146
		// apply sorting during value selection
147 23
		$this->m_dataitem->addCompositeSortKey( implode( ';', array( $text, $languageCode ) ) );
148 23
	}
149
150
	/**
151
	 * @note called by MonolingualTextValueDescriptionDeserializer::deserialize
152
	 * and MonolingualTextValue::parseUserValue
153
	 *
154
	 * No explicit check is made on the validity of a language code and is
155
	 * expected to be done before calling this method.
156
	 *
157
	 * @since 2.4
158
	 *
159
	 * @param string $userValue
160
	 *
161
	 * @return array
162
	 */
163 26
	public function getValuesFromString( $userValue ) {
164 26
		return $this->getValueParser()->parse( $userValue );
165
	}
166
167
	/**
168
	 * @see DataValue::loadDataItem
169
	 *
170
	 * @param DataItem $dataItem
171
	 *
172
	 * @return boolean
173
	 */
174 14
	protected function loadDataItem( DataItem $dataItem ) {
175
176 14
		if ( $dataItem->getDIType() === DataItem::TYPE_CONTAINER ) {
177
			$this->m_dataitem = $dataItem;
178
			return true;
179 14
		} elseif ( $dataItem->getDIType() === DataItem::TYPE_WIKIPAGE ) {
180 14
			$semanticData = new ContainerSemanticData( $dataItem );
181 14
			$semanticData->copyDataFrom( ApplicationFactory::getInstance()->getStore()->getSemanticData( $dataItem ) );
182 14
			$this->m_dataitem = new DIContainer( $semanticData );
183 14
			return true;
184
		}
185
186 3
		return false;
187
	}
188
189
	/**
190
	 * @see DataValue::getShortWikiText
191
	 */
192 16
	public function getShortWikiText( $linker = null ) {
193 16
		return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_SHORT, $linker );
194
	}
195
196
	/**
197
	 * @see DataValue::getShortHTMLText
198
	 */
199
	public function getShortHTMLText( $linker = null ) {
200
		return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_SHORT, $linker );
201
	}
202
203
	/**
204
	 * @see DataValue::getLongWikiText
205
	 */
206
	public function getLongWikiText( $linker = null ) {
207
		return $this->getDataValueFormatter()->format( DataValueFormatter::WIKI_LONG, $linker );
208
	}
209
210
	/**
211
	 * @see DataValue::getLongHTMLText
212
	 */
213
	public function getLongHTMLText( $linker = null ) {
214
		return $this->getDataValueFormatter()->format( DataValueFormatter::HTML_LONG, $linker );
215
	}
216
217
	/**
218
	 * @see DataValue::getWikiValue
219
	 */
220 5
	public function getWikiValue() {
221 5
		return $this->getDataValueFormatter()->format( DataValueFormatter::VALUE );
222
	}
223
224
	/**
225
	 * @since 2.4
226
	 * @note called by AbstractRecordValue::getPropertyDataItems
227
	 *
228
	 * @return DIProperty[]
229
	 */
230 24
	public function getPropertyDataItems() {
231
232 24
		if ( self::$properties !== null && self::$properties !== array() ) {
233 23
			return self::$properties;
234
		}
235
236 1
		foreach ( array( '_TEXT', '_LCODE' ) as  $id ) {
237 1
			self::$properties[] = new DIProperty( $id );
238
		}
239
240 1
		return self::$properties;
0 ignored issues
show
Bug Compatibility introduced by
The expression self::$properties; of type null|SMW\DIProperty[] adds the type SMW\DIProperty[] to the return on line 240 which is incompatible with the return type declared by the abstract method SMW\DataValues\AbstractM...e::getPropertyDataItems of type SMW\DataValues\DIProperty[]|null.
Loading history...
241
	}
242
243
	/**
244
	 * @since 2.4
245
	 *
246
	 * {@inheritDoc}
247
	 */
248 2
	public function getDataItems() {
249 2
		return parent::getDataItems();
250
	}
251
252
	/**
253
	 * @since 2.4
254
	 *
255
	 * @param string $languageCode
256
	 *
257
	 * @return DataValue|null
258
	 */
259 10
	public function getTextValueByLanguage( $languageCode ) {
260
261 10
		if ( ( $list = $this->toArray() ) === array() ) {
262
			return null;
263
		}
264
265 10
		if ( $list['_LCODE'] !== Localizer::asBCP47FormattedLanguageCode( $languageCode ) ) {
266 3
			return null;
267
		}
268
269 9
		if ( $list['_TEXT'] === '' ) {
270
			return null;
271
		}
272
273 9
		$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
274 9
			new DIBlob( $list['_TEXT'] ),
275 9
			new DIProperty( '_TEXT' )
276
		);
277
278 9
		return $dataValue;
279
	}
280
281
	/**
282
	 * @since 2.5
283
	 *
284
	 * @return array
285
	 */
286 14
	public function toArray() {
287
288 14
		if ( !$this->isValid() || $this->getDataItem() === array() ) {
289
			return array();
290
		}
291
292 14
		$semanticData = $this->getDataItem()->getSemanticData();
293
294
		$list = array(
295 14
			'_TEXT'  => '',
296
			'_LCODE' => ''
297
		);
298
299 14
		$dataItems = $semanticData->getPropertyValues( new DIProperty( '_TEXT' ) );
300 14
		$dataItem = reset( $dataItems );
301
302 14
		if ( $dataItem !== false  ) {
303 14
			$list['_TEXT'] = $dataItem->getString();
304
		}
305
306 14
		$dataItems = $semanticData->getPropertyValues( new DIProperty( '_LCODE' ) );
307 14
		$dataItem = reset( $dataItems );
308
309 14
		if ( $dataItem !== false ) {
310 14
			$list['_LCODE'] = $dataItem->getString();
311
		}
312
313 14
		return $list;
314
	}
315
316
	/**
317
	 * @since 2.5
318
	 *
319
	 * @return string
320
	 */
321 1
	public function toString() {
322
323 1
		if ( !$this->isValid() || $this->getDataItem() === array() ) {
324
			return '';
325
		}
326
327 1
		$list = $this->toArray();
328
329 1
		return $list['_TEXT'] . '@' . $list['_LCODE'];
330
	}
331
332 23
	private function newContainerSemanticData( $value ) {
333
334 23
		if ( $this->m_contextPage === null ) {
335 6
			$containerSemanticData = ContainerSemanticData::makeAnonymousContainer();
336 6
			$containerSemanticData->skipAnonymousCheck();
337
		} else {
338 17
			$subobjectName = '_ML' . md5( $value );
339
340 17
			$subject = new DIWikiPage(
341 17
				$this->m_contextPage->getDBkey(),
342 17
				$this->m_contextPage->getNamespace(),
343 17
				$this->m_contextPage->getInterwiki(),
344
				$subobjectName
345
			);
346
347 17
			$containerSemanticData = new ContainerSemanticData( $subject );
348
		}
349
350 23
		return $containerSemanticData;
351
	}
352
353 26
	private function newLanguageCodeValue( $languageCode ) {
354
355 26
		$languageCodeValue = new LanguageCodeValue();
356
357 26
		if ( $this->m_property !== null ) {
358 17
			$languageCodeValue->setProperty( $this->m_property );
359
		}
360
361 26
		$languageCodeValue->setUserValue( $languageCode );
362
363 26
		return $languageCodeValue;
364
	}
365
366 26
	private function getValueParser() {
367
368 26
		if ( $this->monolingualTextValueParser === null ) {
369 26
			$this->monolingualTextValueParser = ValueParserFactory::getInstance()->newMonolingualTextValueParser();
370
		}
371
372 26
		return $this->monolingualTextValueParser;
373
	}
374
375
}
376