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