Completed
Push — master ( 5d1976...30add5 )
by mw
13s
created

includes/datavalues/SMW_DV_Record.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
use SMW\DataValueFactory;
4
5
/**
6
 * SMWDataValue implements the handling of small sets of property-value pairs.
7
 * The declaration of Records in SMW uses the order of values to encode the
8
 * property that should be used, so the user only needs to enter a list of
9
 * values. Internally, however, the property-value assignments are not stored
10
 * with a particular order; they will only be ordered for display, following
11
 * the declaration. This is why it is not supported to have Records using the
12
 * same property for more than one value.
13
 *
14
 * The class uses SMWDIContainer objects to return its inner state. See the
15
 * documentation for SMWDIContainer for details on how this "pseudo" data
16
 * encapsulated many property assignments. Such data is stored internally
17
 * like a page with various property-value assignments. Indeed, record values
18
 * can be created from SMWDIWikiPage objects (the missing information will
19
 * be fetched from the store).
20
 *
21
 * @todo Enforce limitation of maximal number of values.
22
 * @todo Enforce uniqueness of properties in declaration.
23
 * @todo Complete internationalisation.
24
 *
25
 * @author Markus Krötzsch
26
 * @ingroup SMWDataValues
27
 */
28
class SMWRecordValue extends SMWDataValue {
29
30
	/// cache for properties for the fields of this data value
31
	protected $m_diProperties = null;
32
33
	/**
34
	 * @since 2.3
35
	 *
36
	 * @return DIProperty[]|null
37
	 */
38 1
	public function getProperties() {
39 1
		return $this->m_diProperties;
40
	}
41
42
	/**
43
	 * @since 2.3
44
	 *
45
	 * @param string $value
46
	 *
47
	 * @return array
48
	 */
49 22
	public function getValuesFromString( $value ) {
50
		// #664 / T17732
51 22
		$value = str_replace( "\;", "-3B", $value );
52
53
		// Bug 21926 / T23926
54
		// Values that use html entities are encoded with a semicolon
55 22
		$value = htmlspecialchars_decode( $value, ENT_QUOTES );
56
57 22
		return preg_split( '/[\s]*;[\s]*/u', trim( $value ) );
58
	}
59
60 18
	protected function parseUserValue( $value ) {
61
62 18
		if ( $value === '' ) {
63
			$this->addError( wfMessage( 'smw_novalues' )->text() );
64
			return;
65
		}
66
67 18
		if ( is_null( $this->m_contextPage ) ) {
68 8
			$semanticData = SMWContainerSemanticData::makeAnonymousContainer();
69 8
			$semanticData->skipAnonymousCheck();
70
		} else {
71 14
			$subobjectName = '_' . hash( 'md4', $value, false ); // md4 is probably fastest of PHP's hashes
72 14
			$subject = new SMWDIWikiPage( $this->m_contextPage->getDBkey(),
73 14
				$this->m_contextPage->getNamespace(), $this->m_contextPage->getInterwiki(),
74
				$subobjectName );
75 14
			$semanticData = new SMWContainerSemanticData( $subject );
76
		}
77
78 18
		$values = $this->getValuesFromString( $value );
79 18
		$valueIndex = 0; // index in value array
80 18
		$propertyIndex = 0; // index in property list
81 18
		$empty = true;
82
83 18
		foreach ( $this->getPropertyDataItems() as $diProperty ) {
84
85 18
			if ( !array_key_exists( $valueIndex, $values ) || $this->getErrors() !== array() ) {
86 1
				break; // stop if there are no values left
87
			}
88
89 18
			$values[$valueIndex] = str_replace( "-3B", ";", $values[$valueIndex] );
90
91
			// generating the DVs:
92 18
			if ( ( $values[$valueIndex] === '' ) || ( $values[$valueIndex] == '?' ) ) { // explicit omission
93 1
				$valueIndex++;
94
			} else {
95 18
				$dataValue = DataValueFactory::getInstance()->newPropertyObjectValue(
96
					$diProperty,
97 18
					$values[$valueIndex],
98 18
					false,
99 18
					$this->getContextPage()
100
				);
101
102 18
				if ( $dataValue->isValid() ) { // valid DV: keep
103 18
					$semanticData->addPropertyObjectValue( $diProperty, $dataValue->getDataItem() );
104
105 18
					$valueIndex++;
106 18
					$empty = false;
107
				} elseif ( ( count( $values ) - $valueIndex ) == ( count( $this->m_diProperties ) - $propertyIndex ) ) {
108
					$semanticData->addPropertyObjectValue( $diProperty, $dataValue->getDataItem() );
109
					$this->addError( $dataValue->getErrors() );
110
					++$valueIndex;
111
				}
112
			}
113 18
			++$propertyIndex;
114
		}
115
116 18
		if ( $empty && $this->getErrors() === array()  ) {
117
			$this->addError( wfMessage( 'smw_novalues' )->text() );
118
		}
119
120 18
		$this->m_dataitem = new SMWDIContainer( $semanticData );
121 18
	}
122
123
	/**
124
	 * @see SMWDataValue::loadDataItem()
125
	 * @param $dataitem SMWDataItem
126
	 * @return boolean
127
	 */
128 5
	protected function loadDataItem( SMWDataItem $dataItem ) {
129 5
		if ( $dataItem->getDIType() == SMWDataItem::TYPE_CONTAINER ) {
130
			$this->m_dataitem = $dataItem;
131
			return true;
132 5
		} elseif ( $dataItem->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
133 5
			$semanticData = new SMWContainerSemanticData( $dataItem );
0 ignored issues
show
$dataItem of type object<SMWDataItem> is not a sub-type of object<SMW\DIWikiPage>. It seems like you assume a child class of the class SMWDataItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
134 5
			$semanticData->copyDataFrom( \SMW\ApplicationFactory::getInstance()->getStore()->getSemanticData( $dataItem ) );
135 5
			$this->m_dataitem = new SMWDIContainer( $semanticData );
136 5
			return true;
137
		} else {
138 1
			return false;
139
		}
140
	}
141
142 6
	public function getShortWikiText( $linked = null ) {
143 6
		if ( $this->m_caption !== false ) {
144
			return $this->m_caption;
145
		}
146 6
		return $this->makeOutputText( 0, $linked );
147
	}
148
149
	public function getShortHTMLText( $linker = null ) {
150
		if ( $this->m_caption !== false ) {
151
			return $this->m_caption;
152
		}
153
		return $this->makeOutputText( 1, $linker );
154
	}
155
156
	public function getLongWikiText( $linked = null ) {
157
		return $this->makeOutputText( 2, $linked );
158
	}
159
160
	public function getLongHTMLText( $linker = null ) {
161
		return $this->makeOutputText( 3, $linker );
162
	}
163
164 9
	public function getWikiValue() {
165 9
		return $this->makeOutputText( 4 );
166
	}
167
168
	/// @todo Allowed values for multi-valued properties are not supported yet.
169 18
	protected function checkAllowedValues() {
170 18
	}
171
172
	/**
173
	 * Make sure that the content is reset in this case.
174
	 * @todo This is not a full reset yet (the case that property is changed after a value
175
	 * was set does not occur in the normal flow of things, hence this has low priority).
176
	 */
177 14
	public function setProperty( SMWDIProperty $property ) {
178 14
		parent::setProperty( $property );
179 14
		$this->m_diProperties = null;
180 14
	}
181
182
	/**
183
	 * @since 2.1
184
	 *
185
	 * @param SMWDIProperty[] $properties
186
	 */
187 8
	public function setFieldProperties( array $properties ) {
188 8
		foreach ( $properties as $property ) {
189 8
			if ( $property instanceof SMWDIProperty ) {
190 8
				$this->m_diProperties[] = $property;
191
			}
192
		}
193 8
	}
194
195
////// Additional API for value lists
196
197
	/**
198
	 * @deprecated as of 1.6, use getDataItems instead
199
	 *
200
	 * @return array of SMWDataItem
201
	 */
202
	public function getDVs() {
203
		return $this->getDataItems();
204
	}
205
206
	/**
207
	 * Create a list (array with numeric keys) containing the datavalue
208
	 * objects that this SMWRecordValue object holds. Values that are not
209
	 * present are set to null. Note that the first index in the array is
210
	 * 0, not 1.
211
	 *
212
	 * @since 1.6
213
	 *
214
	 * @return array of SMWDataItem
215
	 */
216 8
	public function getDataItems() {
217 8
		if ( $this->isValid() ) {
218 8
			$result = array();
219 8
			$index = 0;
220 8
			foreach ( $this->getPropertyDataItems() as $diProperty ) {
221 8
				$values = $this->getDataItem()->getSemanticData()->getPropertyValues( $diProperty );
222 8
				if ( count( $values ) > 0 ) {
223 8
					$result[$index] = reset( $values );
224
				} else {
225
					$result[$index] = null;
226
				}
227 8
				$index += 1;
228
			}
229 8
			return $result;
230
		} else {
231 6
			return array();
232
		}
233
	}
234
235
	/**
236
	 * Return the array (list) of properties that the individual entries of
237
	 * this datatype consist of.
238
	 *
239
	 * @since 1.6
240
	 *
241
	 * @todo I18N for error message.
242
	 *
243
	 * @return array of SMWDIProperty
244
	 */
245 22
	public function getPropertyDataItems() {
246 22
		if ( is_null( $this->m_diProperties ) ) {
247 14
			$this->m_diProperties = self::findPropertyDataItems( $this->m_property );
248
249 14
			if ( count( $this->m_diProperties ) == 0 ) { // TODO internalionalize
250 6
				$this->addError( 'The list of properties to be used for the data fields has not been specified properly.' );
251
			}
252
		}
253
254 22
		return $this->m_diProperties;
255
	}
256
257
	/**
258
	 * Return the array (list) of properties that the individual entries of
259
	 * this datatype consist of.
260
	 *
261
	 * @since 1.6
262
	 *
263
	 * @param $diProperty mixed null or SMWDIProperty object for which to retrieve the types
264
	 *
265
	 * @return array of SMWDIProperty
266
	 */
267 14
	public static function findPropertyDataItems( $diProperty ) {
268 14
		if ( !is_null( $diProperty ) ) {
269 14
			$propertyDiWikiPage = $diProperty->getDiWikiPage();
270
271 14
			if ( !is_null( $propertyDiWikiPage ) ) {
272 14
				$listDiProperty = new SMW\DIProperty( '_LIST' );
273 14
				$dataItems = \SMW\ApplicationFactory::getInstance()->getStore()->getPropertyValues( $propertyDiWikiPage, $listDiProperty );
274
275 14
				if ( count( $dataItems ) == 1 ) {
276 14
					$propertyListValue = new SMWPropertyListValue( '__pls' );
277 14
					$propertyListValue->setDataItem( reset( $dataItems ) );
278
279 14
					if ( $propertyListValue->isValid() ) {
280 14
						return $propertyListValue->getPropertyDataItems();
281
					}
282
				}
283
			}
284
		}
285
286 6
		return array();
287
	}
288
289
////// Internal helper functions
290
291 11
	protected function makeOutputText( $type = 0, $linker = null ) {
292 11
		if ( !$this->isValid() ) {
293
			return ( ( $type == 0 ) || ( $type == 1 ) ) ? '' : $this->getErrorText();
294
		}
295
296 11
		$result = '';
297 11
		$i = 0;
298 11
		foreach ( $this->getPropertyDataItems() as $propertyDataItem ) {
299 11
			if ( $i == 1 ) {
300 11
				$result .= ( $type == 4 ) ? '; ' : ' (';
301 11
			} elseif ( $i > 1 ) {
302 1
				$result .= ( $type == 4 ) ? '; ' : ', ';
303
			}
304 11
			++$i;
305 11
			$propertyValues = $this->m_dataitem->getSemanticData()->getPropertyValues( $propertyDataItem ); // combining this with next line violates PHP strict standards
306 11
			$dataItem = reset( $propertyValues );
307 11
			if ( $dataItem !== false ) {
308 11
				$dataValue = DataValueFactory::getInstance()->newDataItemValue( $dataItem, $propertyDataItem );
309 11
				$result .= $this->makeValueOutputText( $type, $dataValue, $linker );
310
			} else {
311 11
				$result .= '?';
312
			}
313
		}
314 11
		if ( ( $i > 1 ) && ( $type != 4 ) ) {
315 6
			$result .= ')';
316
		}
317
318 11
		return $result;
319
	}
320
321 11
	protected function makeValueOutputText( $type, $dataValue, $linker ) {
322
		switch ( $type ) {
323 11
			case 0:
324 6
			return $dataValue->getShortWikiText( $linker );
325 9
			case 1:
326
			return $dataValue->getShortHTMLText( $linker );
327 9
			case 2:
328
			return $dataValue->getShortWikiText( $linker );
329 9
			case 3:
330
			return $dataValue->getShortHTMLText( $linker );
331 9
			case 4:
332 9
			return str_replace( ";", "\;", $dataValue->getWikiValue() );
333
		}
334
	}
335
336
}
337
338