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
|
|||
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 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.