Completed
Push — master ( 14d2bd...06e609 )
by mw
81:37 queued 59:24
created

storage/SQLStore/SMW_Sql3StubSemanticData.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\DataTypeRegistry;
4
use SMW\DIProperty;
5
use SMW\DIWikiPage;
6
use SMW\StoreFactory;
7
8
/**
9
 * This class provides a subclass of SMWSemanticData that can store
10
 * prefetched values from SMW's SQL stores, and unstub this data on demand when
11
 * it is accessed.
12
 *
13
 * @since 1.8
14
 * @author Markus Krötzsch
15
 *
16
 * @ingroup SMWStore
17
 */
18
class SMWSql3StubSemanticData extends SMWSemanticData {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
19
20
	/**
21
	 * The store object.
22
	 *
23
	 * @since 1.8
24
	 *
25
	 * @var SMWSQLStore3
26
	 */
27
	protected $store;
28
29
	/**
30
	 * Stub property data that is not part of $mPropVals and $mProperties
31
	 * yet. Entries use property keys as keys. The value is an array of
32
	 * DBkey-arrays that define individual datavalues. The stubs will be
33
	 * set up when first accessed.
34
	 *
35
	 * @since 1.8
36
	 *
37
	 * @var array
38
	 */
39
	protected $mStubPropVals = array();
40
41
	/**
42
	 * SMWDIWikiPage object that is the subject of this container.
43
	 * Subjects that are null are used to represent "internal objects"
44
	 * only.
45
	 *
46
	 * @since 1.8
47
	 *
48
	 * @var SMWDIWikiPage
49
	 */
50
	protected $mSubject;
51
52
	/**
53
	 * Whether SubSemanticData have been requested and added
54
	 *
55
	 * @var boolean
56
	 */
57
	private $subSemanticDataInitialized = false;
58
59
	/**
60
	 * Constructor.
61
	 *
62
	 * @since 1.8
63
	 *
64
	 * @param SMWDIWikiPage $subject to which this data refers
65
	 * @param SMWSQLStore3 $store (the parent store)
66
	 * @param boolean $noDuplicates stating if duplicate data should be avoided
67
	 */
68 231
	public function __construct( SMWDIWikiPage $subject, SMWSQLStore3 $store, $noDuplicates = true ) {
69 231
		$this->store = $store;
70 231
		parent::__construct( $subject, $noDuplicates );
71 231
	}
72
73
	/**
74
	 * Required to support php-serialization
75
	 *
76
	 * @since 2.3
77
	 *
78
	 * @return array
79
	 */
80 216
	public function __sleep() {
81 216
		return array( 'mSubject', 'mPropVals', 'mProperties', 'subSemanticData', 'mStubPropVals' );
82
	}
83
84
	/**
85
	 * @since 2.3
86
	 *
87
	 * @return array
88
	 */
89 1
	public function __wakeup() {
90 1
		$this->store = StoreFactory::getStore( 'SMW\SQLStore\SQLStore' );
91 1
	}
92
93
	/**
94
	 * Create a new SMWSql3StubSemanticData object that holds the data of a
95
	 * given SMWSemanticData object. Array assignments create copies in PHP
96
	 * so the arrays are distinct in input and output object. The object
97
	 * references are copied as references in a shallow way. This is
98
	 * sufficient as the data items used there are immutable.
99
	 *
100
	 * @since 1.8
101
	 *
102
	 * @param $semanticData SMWSemanticData
103
	 * @param SMWSQLStore3 $store
104
	 *
105
	 * @return SMWSql3StubSemanticData
106
	 */
107 227
	public static function newFromSemanticData( SMWSemanticData $semanticData, SMWSQLStore3 $store ) {
108 227
		$result = new SMWSql3StubSemanticData( $semanticData->getSubject(), $store );
109 227
		$result->mPropVals = $semanticData->mPropVals;
110 227
		$result->mProperties = $semanticData->mProperties;
111 227
		$result->mHasVisibleProps = $semanticData->mHasVisibleProps;
112 227
		$result->mHasVisibleSpecs = $semanticData->mHasVisibleSpecs;
113 227
		$result->stubObject = $semanticData->stubObject;
114 227
		return $result;
115
	}
116
117
	/**
118
	 * Get the array of all properties that have stored values.
119
	 *
120
	 * @since 1.8
121
	 *
122
	 * @return array of SMWDIProperty objects
123
	 */
124 189
	public function getProperties() {
125 189
		$this->unstubProperties();
126 189
		return parent::getProperties();
127
	}
128
129
	/**
130
	 * Get the array of all stored values for some property.
131
	 *
132
	 * @since 1.8
133
	 *
134
	 * @param DIProperty $property
135
	 *
136
	 * @return array of SMWDataItem
137
	 */
138 223
	public function getPropertyValues( DIProperty $property ) {
139 223
		if ( $property->isInverse() ) { // we never have any data for inverses
140 1
			return array();
141
		}
142
143 223
		if ( array_key_exists( $property->getKey(), $this->mStubPropVals ) ) {
144
			// Not catching exception here; the
145 188
			$this->unstubProperty( $property->getKey(), $property );
146 188
			$propertyTypeId = $property->findPropertyTypeID();
147 188
			$propertyDiId = DataTypeRegistry::getInstance()->getDataItemId( $propertyTypeId );
148
149 188
			foreach ( $this->mStubPropVals[$property->getKey()] as $dbkeys ) {
150
				try {
151 188
					$diHandler = $this->store->getDataItemHandlerForDIType( $propertyDiId );
152 188
					$di = $diHandler->dataItemFromDBKeys( $dbkeys );
153
154 188
					if ( $this->mNoDuplicates ) {
155 162
						$this->mPropVals[$property->getKey()][$di->getHash()] = $di;
156
					} else {
157 188
						$this->mPropVals[$property->getKey()][] = $di;
158
					}
159 188
				} catch ( SMWDataItemException $e ) {
160
					// ignore data
161
				}
162
			}
163
164 188
			unset( $this->mStubPropVals[$property->getKey()] );
165
		}
166
167 223
		return parent::getPropertyValues( $property );
168
	}
169
170
	/**
171
	 * @see SemanticData::getSubSemanticData
172
	 *
173
	 * @note SubSemanticData are added only on request to avoid unnecessary DB
174
	 * transactions
175
	 *
176
	 * @since 2.0
177
	 */
178 184
	public function getSubSemanticData() {
179
180 184
		if ( $this->subSemanticDataInitialized ) {
181 101
			return parent::getSubSemanticData();
182
		}
183
184 183
		$this->subSemanticDataInitialized = true;
185
186 183
		foreach ( $this->getProperties() as $property ) {
187
188
			// #619 Do not resolve subobjects for redirects
189 182
			if ( !DataTypeRegistry::getInstance()->isSubDataType( $property->findPropertyTypeID() ) || $this->isRedirect() ) {
190 182
				continue;
191
			}
192
193 98
			$this->addSubSemanticDataToInternalCache( $property );
194
		}
195
196 183
		return parent::getSubSemanticData();
197
	}
198
199
	/**
200
	 * @see SemanticData::hasSubSemanticData
201
	 *
202
	 * @note This method will initialize SubSemanticData first if it wasn't done
203
	 * yet to ensure data consistency
204
	 *
205
	 * @since 2.0
206
	 */
207 99
	public function hasSubSemanticData( $subobjectName = null ) {
208
209 99
		if ( !$this->subSemanticDataInitialized ) {
210 3
			$this->getSubSemanticData();
211
		}
212
213 99
		return parent::hasSubSemanticData( $subobjectName );
214
	}
215
216
	/**
217
	 * Remove a value for a property identified by its SMWDataItem object.
218
	 * This method removes a property-value specified by the property and
219
	 * dataitem. If there are no more property-values for this property it
220
	 * also removes the property from the mProperties.
221
	 *
222
	 * @note There is no check whether the type of the given data item
223
	 * agrees with the type of the property. Since property types can
224
	 * change, all parts of SMW are prepared to handle mismatched data item
225
	 * types anyway.
226
	 *
227
	 * @param $property SMWDIProperty
228
	 * @param $dataItem SMWDataItem
229
	 *
230
	 * @since 1.8
231
	 */
232 2
	public function removePropertyObjectValue( DIProperty $property, SMWDataItem $dataItem ) {
233 2
		$this->unstubProperties();
234 2
		$this->getPropertyValues( $property );
235 2
		parent::removePropertyObjectValue($property, $dataItem);
236 2
	}
237
238
	/**
239
	 * Return true if there are any visible properties.
240
	 *
241
	 * @since 1.8
242
	 *
243
	 * @return boolean
244
	 */
245 8
	public function hasVisibleProperties() {
246 8
		$this->unstubProperties();
247 8
		return parent::hasVisibleProperties();
248
	}
249
250
	/**
251
	 * Return true if there are any special properties that can
252
	 * be displayed.
253
	 *
254
	 * @since 1.8
255
	 *
256
	 * @return boolean
257
	 */
258 8
	public function hasVisibleSpecialProperties() {
259 8
		$this->unstubProperties();
260 8
		return parent::hasVisibleSpecialProperties();
261
	}
262
263
	/**
264
	 * Add data in abbreviated form so that it is only expanded if needed.
265
	 * The property key is the DB key (string) of a property value, whereas
266
	 * valuekeys is an array of DBkeys for the added value that will be
267
	 * used to initialize the value if needed at some point. If there is
268
	 * only one valuekey, a single string can be used.
269
	 *
270
	 * @since 1.8
271
	 * @param string $propertyKey
272
	 * @param array|string $valueKeys
273
	 */
274 215
	public function addPropertyStubValue( $propertyKey, $valueKeys ) {
275 215
		$this->mStubPropVals[$propertyKey][] = $valueKeys;
276 215
	}
277
278
	/**
279
	 * Delete all data other than the subject.
280
	 *
281
	 * @since 1.8
282
	 */
283 231
	public function clear() {
284 231
		$this->mStubPropVals = array();
285 231
		parent::clear();
286 231
	}
287
288
	/**
289
	 * Process all mProperties that have been added as stubs.
290
	 * Associated data may remain in stub form.
291
	 *
292
	 * @since 1.8
293
	 */
294 189
	protected function unstubProperties() {
295 189
		foreach ( $this->mStubPropVals as $pkey => $values ) { // unstub property values only, the value lists are still kept as stubs
296
			try {
297 185
				$this->unstubProperty( $pkey );
298 185
			} catch ( SMWDataItemException $e ) {
299
				// Likely cause: a property name from the DB is no longer valid.
300
				// Do nothing; we could unset the data, but it will never be
301
				// unstubbed anyway if there is no valid property DI for it.
302
			}
303
		}
304 189
	}
305
306
	/**
307
	 * Unstub a single property from the stub data array. If available, an
308
	 * existing object for that property might be provided, so we do not
309
	 * need to make a new one. It is not checked if the object matches the
310
	 * property name.
311
	 *
312
	 * @since 1.8
313
	 *
314
	 * @param string $propertyKey
315
	 * @param SMWDIProperty $diProperty if available
316
	 * @throws SMWDataItemException if property key is not valid
317
	 * 	and $diProperty is null
318
	 */
319 190
	protected function unstubProperty( $propertyKey, $diProperty = null ) {
320 190
		if ( !array_key_exists( $propertyKey, $this->mProperties ) ) {
321 85
			if ( is_null( $diProperty ) ) {
322 81
				$diProperty = new DIProperty( $propertyKey, false );
323
			}
324
325 85
			$this->mProperties[$propertyKey] = $diProperty;
326
327 85
			if ( !$diProperty->isUserDefined() ) {
328 85
				if ( $diProperty->isShown() ) {
329 34
					$this->mHasVisibleSpecs = true;
330 85
					$this->mHasVisibleProps = true;
331
				}
332
			} else {
333 32
				$this->mHasVisibleProps = true;
334
			}
335
		}
336 190
	}
337
338 98
	protected function isRedirect() {
339 98
		return $this->store->getObjectIds()->checkIsRedirect( $this->mSubject );
340
	}
341
342 98
	private function addSubSemanticDataToInternalCache( DIProperty $property ) {
343
344 98
		foreach ( $this->getPropertyValues( $property ) as $value ) {
345 98
			if ( $value instanceof DIWikiPage && $value->getSubobjectName() !== '' && !$this->hasSubSemanticData( $value->getSubobjectName() ) ) {
346 98
				$this->addSubSemanticData( $this->store->getSemanticData( $value ) );
347
			}
348
		}
349 98
	}
350
351
}
352