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

storage/SQLStore/SMW_SQLStore3_Readers.php (2 issues)

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\DIWikiPage;
5
use SMW\SQLStore\TableDefinition;
6
7
/**
8
 * Class to provide all basic read methods for SMWSQLStore3.
9
 *
10
 * @author Markus Krötzsch
11
 * @author Jeroen De Dauw
12
 * @author Nischay Nahata
13
 *
14
 * @since 1.8
15
 * @ingroup SMWStore
16
 */
17
class SMWSQLStore3Readers {
18
19
	/**
20
	 * The store used by this store reader
21
	 *
22
	 * @since 1.8
23
	 * @var SMWSQLStore3
24
	 */
25
	private $store;
26
27
	/**
28
	 *  >0 while getSemanticData runs, used to prevent nested calls from clearing the cache
29
	 * while another call runs and is about to fill it with data
30
	 *
31
	 * @var int
32
	 */
33
	private static $in_getSemanticData = 0;
34
35 6
	public function __construct( SMWSQLStore3 $parentStore ) {
36 6
		$this->store = $parentStore;
37 6
	}
38
39
	/**
40
	 * @see SMWStore::getSemanticData()
41
	 * @since 1.8
42
	 *
43
	 * @param DIWikiPage $subject
44
	 * @param string[]|bool $filter
45
	 */
46 223
	public function getSemanticData( DIWikiPage $subject, $filter = false ) {
47
48
		// *** Find out if this subject exists ***//
49 223
		$sortKey = '';
50
51 223
		$sid = $this->store->smwIds->getSMWPageIDandSort(
52 223
			$subject->getDBkey(),
53 223
			$subject->getNamespace(),
54 223
			$subject->getInterwiki(),
55 223
			$subject->getSubobjectName(),
56
			$sortKey,
57 223
			true,
58 223
			true
59
		);
60
61
		// Ensures that a cached item to contain an expected sortKey when
62
		// for example the ID was just created and the sortKey from the DB
63
		// is empty otherwise the DB wins over the invoked sortKey
64 223
		if ( !$sortKey ) {
65 218
			$sortKey = $subject->getSortKey();
66
		}
67
68 223
		$subject->setSortKey( $sortKey );
69
70 223
		if ( $sid == 0 ) {
71
			// We consider redirects for getting $sid,
72
			// so $sid == 0 also means "no redirects".
73 218
			return new SMWSemanticData( $subject );
74
		}
75
76 215
		$propertyTableHashes = $this->store->smwIds->getPropertyTableHashes( $sid );
77
78 215
		foreach ( $this->store->getPropertyTables() as $tid => $proptable ) {
79 215
			if ( !array_key_exists( $proptable->getName(), $propertyTableHashes ) ) {
80 215
				continue;
81
			}
82
83 205
			if ( $filter !== false ) {
84 3
				$relevant = false;
85 3
				foreach ( $filter as $typeId ) {
86 3
					$diType = DataTypeRegistry::getInstance()->getDataItemId( $typeId );
87 3
					$relevant = $relevant || ( $proptable->getDiType() == $diType );
88 3
					if ( $relevant ) {
89 3
						break;
90
					}
91
				}
92 3
				if ( !$relevant ) {
93 3
					continue;
94
				}
95
			}
96
97 205
			$this->getSemanticDataFromTable( $sid, $subject, $proptable );
98
		}
99
100
		// Note: the sortkey is always set but belongs to no property table,
101
		// hence no entry in $this->store->m_sdstate[$sid] is made.
102 215
		self::$in_getSemanticData++;
103 215
		$this->initSemanticDataCache( $sid, $subject );
104 215
		$this->store->m_semdata[$sid]->addPropertyStubValue( '_SKEY', array( '', $sortKey ) );
105 215
		self::$in_getSemanticData--;
106
107 215
		return $this->store->m_semdata[$sid];
108
	}
109
110
	/**
111
	 * Helper method to make sure there is a cache entry for the data about
112
	 * the given subject with the given ID.
113
	 *
114
	 * @todo The management of this cache should be revisited.
115
	 *
116
	 * @since 1.8
117
	 *
118
	 * @param int $subjectId
119
	 * @param DIWikiPage $subject
120
	 */
121 219
	private function initSemanticDataCache( $subjectId, DIWikiPage $subject ) {
122
123
		// *** Prepare the cache ***//
124 219
		if ( !array_key_exists( $subjectId, $this->store->m_semdata ) ) { // new cache entry
125 120
			$this->store->m_semdata[$subjectId] = new SMWSql3StubSemanticData( $subject, $this->store, false );
126 120
			$this->store->m_sdstate[$subjectId] = array();
127
		}
128
129
		// Issue #622
130
		// If a redirect was cached preceding this request and points to the same
131
		// subject id ensure that in all cases the requested subject matches with
132
		// the selected DB id
133 219
		if ( $this->store->m_semdata[$subjectId]->getSubject()->getHash() !== $subject->getHash() ) {
134 24
			$this->store->m_semdata[$subjectId] = new SMWSql3StubSemanticData( $subject, $this->store, false );
135 24
			$this->store->m_sdstate[$subjectId] = array();
136
		}
137
138 219
		if ( ( count( $this->store->m_semdata ) > 20 ) && ( self::$in_getSemanticData == 1 ) ) {
139
			// prevent memory leak;
140
			// It is not so easy to find the sweet spot between cache size and performance gains (both memory and time),
141
			// The value of 20 was chosen by profiling runtimes for large inline queries and heavily annotated pages.
142
			// However, things might have changed in the meantime ...
143 15
			$this->store->m_semdata = array( $subjectId => $this->store->m_semdata[$subjectId] );
144 15
			$this->store->m_sdstate = array( $subjectId => $this->store->m_sdstate[$subjectId] );
145
		}
146 219
	}
147
148
	/**
149
	 * Fetch the data storder about one subject in one particular table.
150
	 *
151
	 * @param integer $sid
152
	 * @param DIWikiPage $subject
153
	 * @param TableDefinition $proptable
154
	 *
155
	 * @return SMWSemanticData
156
	 */
157 209
	private function getSemanticDataFromTable( $sid, DIWikiPage $subject, TableDefinition $proptable ) {
158
		// Do not clear the cache when called recursively.
159 209
		self::$in_getSemanticData++;
160
161 209
		$this->initSemanticDataCache( $sid, $subject );
162
163 209
		if ( array_key_exists( $proptable->getName(), $this->store->m_sdstate[$sid] ) ) {
164 205
			self::$in_getSemanticData--;
165 205
			return $this->store->m_semdata[$sid];
166
		}
167
168
		// *** Read the data ***//
169 101
		$data = $this->fetchSemanticData( $sid, $subject, $proptable );
170 101
		foreach ( $data as $d ) {
171 51
			$this->store->m_semdata[$sid]->addPropertyStubValue( reset( $d ), end( $d ) );
172
		}
173 101
		$this->store->m_sdstate[$sid][$proptable->getName()] = true;
174
175 101
		self::$in_getSemanticData--;
176 101
		return $this->store->m_semdata[$sid];
177
	}
178
179
	/**
180
	 * @see SMWStore::getPropertyValues
181
	 *
182
	 * @todo Retrieving all sortkeys (values for _SKEY with $subject null)
183
	 * is not supported. An empty array will be given.
184
	 *
185
	 * @since 1.8
186
	 *
187
	 * @param $subject mixed DIWikiPage or null
188
	 * @param $property SMWDIProperty
189
	 * @param $requestOptions SMWRequestOptions
190
	 *
191
	 * @return SMWDataItem[]
192
	 */
193 183
	public function getPropertyValues( $subject, SMWDIProperty $property, $requestOptions = null ) {
194
195 183
		if ( $property->isInverse() ) { // inverses are working differently
196 3
			$noninverse = new SMW\DIProperty( $property->getKey(), false );
197 3
			$result = $this->getPropertySubjects( $noninverse, $subject, $requestOptions );
198 183
		} elseif ( !is_null( $subject ) ) { // subject given, use semantic data cache
199 183
			$sid = $this->store->smwIds->getSMWPageID( $subject->getDBkey(),
200 183
				$subject->getNamespace(), $subject->getInterwiki(),
201 183
				$subject->getSubobjectName(), true );
202 183
			if ( $sid == 0 ) {
203 152
				$result = array();
204 159
			} elseif ( $property->getKey() == '_SKEY' ) {
205 4
				$this->store->smwIds->getSMWPageIDandSort( $subject->getDBkey(),
206 4
				$subject->getNamespace(), $subject->getInterwiki(),
207 4
				$subject->getSubobjectName(), $sortKey, true );
208 4
				$sortKeyDi = new SMWDIBlob( $sortKey );
209 4
				$result = $this->store->applyRequestOptions( array( $sortKeyDi ), $requestOptions );
210
			} else {
211 159
				$propTableId = $this->store->findPropertyTableID( $property );
212 159
				$proptables =  $this->store->getPropertyTables();
213
214 159
				if ( !isset( $proptables[$propTableId] ) ) {
215
					return array();
216
				}
217
218 159
				$sd = $this->getSemanticDataFromTable( $sid, $subject, $proptables[$propTableId] );
219 183
				$result = $this->store->applyRequestOptions( $sd->getPropertyValues( $property ), $requestOptions );
220
			}
221
		} else { // no subject given, get all values for the given property
222 1
			$pid = $this->store->smwIds->getSMWPropertyID( $property );
223 1
			$tableid =  $this->store->findPropertyTableID( $property );
224
225 1
			if ( ( $pid == 0 ) || ( $tableid === '' ) ) {
226
				return array();
227
			}
228
229 1
			$proptables =  $this->store->getPropertyTables();
230 1
			$data = $this->fetchSemanticData( $pid, $property, $proptables[$tableid], false, $requestOptions );
231 1
			$result = array();
232 1
			$propertyTypeId = $property->findPropertyTypeID();
233 1
			$propertyDiId = DataTypeRegistry::getInstance()->getDataItemId( $propertyTypeId );
234
235 1
			foreach ( $data as $dbkeys ) {
236
				try {
237 1
					$diHandler = $this->store->getDataItemHandlerForDIType( $propertyDiId );
238 1
					$result[] = $diHandler->dataItemFromDBKeys( $dbkeys );
239 1
				} catch ( SMWDataItemException $e ) {
240
					// maybe type assignment changed since data was stored;
241
					// don't worry, but we can only drop the data here
242
				}
243
			}
244
		}
245
246
247 183
		return $result;
248
	}
249
250
	/**
251
	 * Helper function for reading all data for from a given property table
252
	 * (specified by an SMWSQLStore3Table object), based on certain
253
	 * restrictions. The function can filter data based on the subject (1)
254
	 * or on the property it belongs to (2) -- but one of those must be
255
	 * done. The Boolean $issubject is true for (1) and false for (2).
256
	 *
257
	 * In case (1), the first two parameters are taken to refer to a
258
	 * subject; in case (2) they are taken to refer to a property. In any
259
	 * case, the retrieval is limited to the specified $proptable. The
260
	 * parameters are an internal $id (of a subject or property), and an
261
	 * $object (being an DIWikiPage or SMWDIProperty). Moreover, when
262
	 * filtering by property, it is assumed that the given $proptable
263
	 * belongs to the property: if it is a table with fixed property, it
264
	 * will not be checked that this is the same property as the one that
265
	 * was given in $object.
266
	 *
267
	 * In case (1), the result in general is an array of pairs (arrays of
268
	 * size 2) consisting of a property key (string), and DB keys (array if
269
	 * many, string if one) from which a datvalue object for this value can
270
	 * be built. It is possible that some of the DB keys are based on
271
	 * internal objects; these will be represented by similar result arrays
272
	 * of (recursive calls of) fetchSemanticData().
273
	 *
274
	 * In case (2), the result is simply an array of DB keys (array)
275
	 * without the property keys. Container objects will be encoded with
276
	 * nested arrays like in case (1).
277
	 *
278
	 * @todo Maybe share DB handler; asking for it seems to take quite some
279
	 * time and we do not want to change it in one call.
280
	 *
281
	 * @param integer $id
282
	 * @param SMWDataItem $object
283
	 * @param TableDefinition $propTable
284
	 * @param boolean $isSubject
285
	 * @param SMWRequestOptions $requestOptions
286
	 *
287
	 * @return array
288
	 */
289 102
	private function fetchSemanticData( $id, SMWDataItem $object = null, TableDefinition $propTable, $isSubject = true, SMWRequestOptions $requestOptions = null ) {
290
		// stop if there is not enough data:
291
		// properties always need to be given as object,
292
		// subjects at least if !$proptable->idsubject
293 102
		if ( ( $id == 0 ) ||
294 102
			( is_null( $object ) && ( !$isSubject || !$propTable->usesIdSubject() ) ) ) {
295
				return array();
296
		}
297
298 102
		$result = array();
299 102
		$db = $this->store->getConnection();
300
301 102
		$diHandler = $this->store->getDataItemHandlerForDIType( $propTable->getDiType() );
302
303
		// ***  First build $from, $select, and $where for the DB query  ***//
304 102
		$from = $db->tableName( $propTable->getName() ); // always use actual table
305
306 102
		$select = '';
307 102
		$where  = '';
308
309 102
		if ( $isSubject ) { // restrict subject, select property
310 101
			$where .= ( $propTable->usesIdSubject() ) ? 's_id=' . $db->addQuotes( $id ) :
311 26
					  's_title=' . $db->addQuotes( $object->getDBkey() ) .
312 101
					  ' AND s_namespace=' . $db->addQuotes( $object->getNamespace() );
313 101
			if ( !$propTable->isFixedPropertyTable() ) { // select property name
314 66
				$from .= ' INNER JOIN ' . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . ' AS p ON p_id=p.smw_id';
315 101
				$select .= 'p.smw_title as prop';
316
			} // else: fixed property, no select needed
317 1
		} elseif ( !$propTable->isFixedPropertyTable() ) { // restrict property only
318 1
			$where .= 'p_id=' . $db->addQuotes( $id );
319
		}
320
321 102
		$valuecount = 0;
322
		// Don't use DISTINCT for value of one subject:
323 102
		$usedistinct = !$isSubject;
324
325 102
		$valueField = $diHandler->getIndexField();
326 102
		$labelField = $diHandler->getLabelField();
327 102
		$fields = $diHandler->getFetchFields();
328 102
		foreach ( $fields as $fieldname => $typeid ) { // select object column(s)
329 102
			if ( $typeid == 'p' ) { // get data from ID table
330 59
				$from .= ' INNER JOIN ' . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " AS o$valuecount ON $fieldname=o$valuecount.smw_id";
331 59
				$select .= ( ( $select !== '' ) ? ',' : '' ) .
332 59
					"$fieldname AS id$valuecount" .
333 59
					",o$valuecount.smw_title AS v$valuecount" .
334 59
					",o$valuecount.smw_namespace AS v" . ( $valuecount + 1 ) .
335 59
					",o$valuecount.smw_iw AS v" . ( $valuecount + 2 ) .
336 59
					",o$valuecount.smw_sortkey AS v" . ( $valuecount + 3 ) .
337 59
					",o$valuecount.smw_subobject AS v" . ( $valuecount + 4 );
338
339 59
				if ( $valueField == $fieldname ) {
340 59
					$valueField = "o$valuecount.smw_sortkey";
341
				}
342 59
				if ( $labelField == $fieldname ) {
343 59
					$labelField = "o$valuecount.smw_sortkey";
344
				}
345
346 59
				$valuecount += 4;
347
			} else {
348 96
				$select .= ( ( $select !== '' ) ? ',' : '' ) .
349 96
					"$fieldname AS v$valuecount";
350
			}
351
352 102
			$valuecount += 1;
353
		}
354
355 102
		if ( !$isSubject ) { // Apply sorting/string matching; only with given property
356 1
			$where .= $this->store->getSQLConditions( $requestOptions, $valueField, $labelField, $where !== '' );
357
		} else {
358 101
			$valueField = '';
359
		}
360
361
		// ***  Now execute the query and read the results  ***//
362 102
		$res = $db->select( $from, $select, $where, __METHOD__,
363 102
				( $usedistinct ?
364 1
					$this->store->getSQLOptions( $requestOptions, $valueField ) + array( 'DISTINCT' ) :
365 102
					$this->store->getSQLOptions( $requestOptions, $valueField )
366
				) );
367
368 102
		foreach ( $res as $row ) {
369
370 52
			$valueHash = '';
371
372 52
			if ( $isSubject ) { // use joined or predefined property name
373 51
				$propertykey = $propTable->isFixedPropertyTable() ? $propTable->getFixedProperty() : $row->prop;
374 51
				$valueHash = $propertykey;
375
			}
376
377
			// Use enclosing array only for results with many values:
378 52
			if ( $valuecount > 1 ) {
379 47
				$valuekeys = array();
380 47
				for ( $i = 0; $i < $valuecount; $i += 1 ) { // read the value fields from the current row
381 47
					$fieldname = "v$i";
382 47
					$valuekeys[] = $row->$fieldname;
383
				}
384
			} else {
385 51
				$valuekeys = $row->v0;
386
			}
387
388
			// #Issue 615
389
			// If the iw field contains a redirect marker then remove it
390 52
			if ( isset( $valuekeys[2] ) && ( $valuekeys[2] === SMW_SQL3_SMWREDIIW || $valuekeys[2] === SMW_SQL3_SMWDELETEIW ) ) {
391 5
				$valuekeys[2] = '';
392
			}
393
394
			// The valueHash prevents from inserting duplicate entries of the same content
395 52
			$valueHash = $valuecount > 1 ? md5( $valueHash . implode( '#', $valuekeys ) ) : md5( $valueHash . $valuekeys );
396
397
			// Filter out any accidentally retrieved internal things (interwiki starts with ":"):
398 52
			if ( $valuecount < 3 || implode( '', $fields ) != 'p' ||
399 52
			     $valuekeys[2] === '' || $valuekeys[2]{0} != ':' ) {
400
401 52
				if ( isset( $result[$valueHash] ) ) {
402
					wfDebugLog( 'smw', __METHOD__ . " Duplicate entry for {$propertykey} with " . ( is_array( $valuekeys ) ? implode( ',', $valuekeys ) : $valuekeys ) . "\n" );
403
				}
404
405 52
				$result[$valueHash] = $isSubject ? array( $propertykey, $valuekeys ) : $valuekeys;
406
			}
407
		}
408
409 102
		$db->freeResult( $res );
410
411 102
		return $result;
412
	}
413
414
	/**
415
	 * @see SMWStore::getPropertySubjects
416
	 *
417
	 * @todo This method cannot retrieve subjects for sortkeys, i.e., for
418
	 * property _SKEY. Only empty arrays will be returned there.
419
	 *
420
	 * @param SMWDIProperty $property
421
	 * @param SMWDataItem|null $value
422
	 * @param SMWRequestOptions|null $requestOptions
423
	 *
424
	 * @return array of DIWikiPage
425
	 */
426 129
	public function getPropertySubjects( SMWDIProperty $property, SMWDataItem $value = null, SMWRequestOptions $requestOptions = null ) {
427
		/// TODO: should we share code with #ask query computation here? Just use queries?
428
429 129
		if ( $property->isInverse() ) { // inverses are working differently
430
			$noninverse = new SMW\DIProperty( $property->getKey(), false );
431
			$result = $this->getPropertyValues( $value, $noninverse, $requestOptions );
432
			return $result;
433
		}
434
435
		// #1222, Filter those where types don't match (e.g property = _txt
436
		// and value = _wpg)
437 129
		if ( $value !== null && DataTypeRegistry::getInstance()->getDataItemId( $property->findPropertyTypeID() ) !== $value->getDIType() ) {
438 1
			return array();
439
		}
440
441
		// First build $select, $from, and $where for the DB query
442 129
		$where = $from = '';
0 ignored issues
show
$from is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
443 129
		$pid = $this->store->smwIds->getSMWPropertyID( $property );
444 129
		$tableid =  $this->store->findPropertyTableID( $property );
445
446 129
		if ( ( $pid == 0 ) || ( $tableid === '' ) ) {
447 118
			return array();
448
		}
449
450 129
		$proptables =  $this->store->getPropertyTables();
451 129
		$proptable = $proptables[$tableid];
452 129
		$db = $this->store->getConnection();
453
454 129
		if ( $proptable->usesIdSubject() ) { // join with ID table to get title data
455 129
			$from = $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " INNER JOIN " . $db->tableName( $proptable->getName() ) . " AS t1 ON t1.s_id=smw_id";
456 129
			$select = 'smw_title, smw_namespace, smw_iw, smw_sortkey, smw_subobject';
457
		} else { // no join needed, title+namespace as given in proptable
458 3
			$from = $db->tableName( $proptable->getName() ) . " AS t1";
459 3
			$select = 's_title AS smw_title, s_namespace AS smw_namespace, \'\' AS smw_iw, s_title AS smw_sortkey, \'\' AS smw_subobject';
460
		}
461
462 129
		if ( !$proptable->isFixedPropertyTable() ) {
463 125
			$where .= ( $where ? ' AND ' : '' ) . "t1.p_id=" . $db->addQuotes( $pid );
464
		}
465
466 129
		$this->prepareValueQuery( $from, $where, $proptable, $value, 1 );
467
468
		// ***  Now execute the query and read the results  ***//
469 129
		$result = array();
470
471 129
		if ( !$proptable->isFixedPropertyTable() ) {
472 125
			if ( $where !== '' && strpos( SMW_SQL3_SMWIW_OUTDATED, $where ) === false ) {
473 125
				$where .= " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW );
474
			} else {
475
				$where .= " smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW );
476
			}
477
		}
478
479 129
		$res = $db->select( $from, 'DISTINCT ' . $select,
480 129
		                    $where . $this->store->getSQLConditions( $requestOptions, 'smw_sortkey', 'smw_sortkey', $where !== '' ),
481 129
		                    __METHOD__, $this->store->getSQLOptions( $requestOptions, 'smw_sortkey' ) );
482
483 129
		$diHandler = $this->store->getDataItemHandlerForDIType( SMWDataItem::TYPE_WIKIPAGE );
484
485 129
		foreach ( $res as $row ) {
486
			try {
487 12
				if ( $row->smw_iw === '' || $row->smw_iw{0} != ':' ) { // filter special objects
488 12
					$result[] = $diHandler->dataItemFromDBKeys( array_values( (array)$row ) );
489
				}
490 12
			} catch ( SMWDataItemException $e ) {
491
				// silently drop data, should be extremely rare and will usually fix itself at next edit
492
			}
493
		}
494
495 129
		$db->freeResult( $res );
496
497 129
		return $result;
498
	}
499
500
501
	/**
502
	 * Helper function to compute from and where strings for a DB query so that
503
	 * only rows of the given value object match. The parameter $tableindex
504
	 * counts that tables used in the query to avoid duplicate table names. The
505
	 * parameter $proptable provides the SMWSQLStore3Table object that is
506
	 * queried.
507
	 *
508
	 * @todo Maybe do something about redirects. The old code was
509
	 * $oid = $this->store->smwIds->getSMWPageID($value->getDBkey(),$value->getNamespace(),$value->getInterwiki(),false);
510
	 *
511
	 * @note This method cannot handle DIContainer objects with sortkey
512
	 * properties correctly. This should never occur, but it would be good
513
	 * to fail in a more controlled way if it ever does.
514
	 *
515
	 * @param string $from
516
	 * @param string $where
517
	 * @param TableDefinition $propTable
518
	 * @param SMWDataItem $value
519
	 * @param integer $tableIndex
520
	 */
521 132
	private function prepareValueQuery( &$from, &$where, TableDefinition $propTable, $value, $tableIndex = 1 ) {
522 132
		$db = $this->store->getConnection();
523
524 132
		if ( $value instanceof SMWDIContainer ) { // recursive handling of containers
525
			$keys = array_keys( $propTable->getFields( $this->store ) );
526
			$joinfield = "t$tableIndex." . reset( $keys ); // this must be a type 'p' object
527
			$proptables =  $this->store->getPropertyTables();
528
			$semanticData = $value->getSemanticData();
529
530
			foreach ( $semanticData->getProperties() as $subproperty ) {
531
				$tableid =  $this->store->findPropertyTableID( $subproperty );
532
				$subproptable = $proptables[$tableid];
533
534
				foreach ( $semanticData->getPropertyValues( $subproperty ) as $subvalue ) {
535
					$tableIndex++;
536
537
					if ( $subproptable->usesIdSubject() ) { // simply add property table to check values
538
						$from .= " INNER JOIN " . $db->tableName( $subproptable->getName() ) . " AS t$tableIndex ON t$tableIndex.s_id=$joinfield";
539
					} else { // exotic case with table that uses subject title+namespace in container object (should never happen in SMW core)
540
						$from .= " INNER JOIN " . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " AS ids$tableIndex ON ids$tableIndex.smw_id=$joinfield" .
541
						         " INNER JOIN " . $db->tableName( $subproptable->getName() ) . " AS t$tableIndex ON " .
542
						         "t$tableIndex.s_title=ids$tableIndex.smw_title AND t$tableIndex.s_namespace=ids$tableIndex.smw_namespace";
543
					}
544
545
					if ( !$subproptable->isFixedPropertyTable() ) { // the ID we get should be !=0, so no point in filtering the converse
546
						$where .= ( $where ? ' AND ' : '' ) . "t$tableIndex.p_id=" . $db->addQuotes( $this->store->smwIds->getSMWPropertyID( $subproperty ) );
547
					}
548
549
					$this->prepareValueQuery( $from, $where, $subproptable, $subvalue, $tableIndex );
550
				}
551
			}
552 132
		} elseif ( !is_null( $value ) ) { // add conditions for given value
553 131
			$diHandler = $this->store->getDataItemHandlerForDIType( $value->getDIType() );
554 131
			foreach ( $diHandler->getWhereConds( $value ) as $fieldname => $value ) {
555 131
				$where .= ( $where ? ' AND ' : '' ) . "t$tableIndex.$fieldname=" . $db->addQuotes( $value );
556
			}
557
		}
558 132
	}
559
560
	/**
561
	 * @see SMWStore::getAllPropertySubjects
562
	 *
563
	 * @param SMWDIProperty $property
564
	 * @param SMWRequestOptions $requestOptions
565
	 *
566
	 * @return array of DIWikiPage
567
	 */
568 125
	public function getAllPropertySubjects( SMWDIProperty $property, SMWRequestOptions $requestOptions = null ) {
569 125
		$result = $this->getPropertySubjects( $property, null, $requestOptions );
570
571 125
		return $result;
572
	}
573
574
	/**
575
	 * @see Store::getProperties
576
	 *
577
	 * @param DIWikiPage $subject
578
	 * @param SMWRequestOptions|null $requestOptions
579
	 *
580
	 * @return SMWDataItem[]
581
	 */
582 1
	public function getProperties( DIWikiPage $subject, SMWRequestOptions $requestOptions = null ) {
583 1
		$sid = $this->store->smwIds->getSMWPageID(
584 1
			$subject->getDBkey(),
585 1
			$subject->getNamespace(),
586 1
			$subject->getInterwiki(),
587 1
			$subject->getSubobjectName()
588
		);
589
590 1
		if ( $sid == 0 ) { // no id, no page, no properties
591 1
			return array();
592
		}
593
594
		$db = $this->store->getConnection();
595
		$result = array();
596
597
		// potentially need to get more results, since options apply to union
598
		if ( $requestOptions !== null ) {
599
			$suboptions = clone $requestOptions;
600
			$suboptions->limit = $requestOptions->limit + $requestOptions->offset;
601
			$suboptions->offset = 0;
602
		} else {
603
			$suboptions = null;
604
		}
605
606
		foreach ( $this->store->getPropertyTables() as $propertyTable ) {
607
			if ( $propertyTable->usesIdSubject() ) {
608
				$where = 's_id=' . $db->addQuotes( $sid );
609
			} elseif ( $subject->getInterwiki() === '' ) {
610
				$where = 's_title=' . $db->addQuotes( $subject->getDBkey() ) . ' AND s_namespace=' . $db->addQuotes( $subject->getNamespace() );
611
			} else { // subjects with non-emtpy interwiki cannot have properties
612
				continue;
613
			}
614
615
			if ( $propertyTable->isFixedPropertyTable() ) {
616
				// just check if subject occurs in table
617
				$res = $db->select(
618
					$propertyTable->getName(),
619
					'*',
620
					$where,
621
					__METHOD__,
622
					array( 'LIMIT' => 1 )
623
				);
624
625
				if ( $db->numRows( $res ) > 0 ) {
626
					$result[] = new SMW\DIProperty( $propertyTable->getFixedProperty() );
627
				}
628
629
630
			} else {
631
				// select all properties
632
				$from = $db->tableName( $propertyTable->getName() );
633
634
				$from .= " INNER JOIN " . $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " ON smw_id=p_id";
635
				$res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey',
636
					// (select sortkey since it might be used in ordering (needed by Postgres))
637
					$where . $this->store->getSQLConditions( $suboptions, 'smw_sortkey', 'smw_sortkey' ),
638
					__METHOD__, $this->store->getSQLOptions( $suboptions, 'smw_sortkey' ) );
639
				foreach ( $res as $row ) {
640
					$result[] = new SMW\DIProperty( $row->smw_title );
641
				}
642
			}
643
644
			$db->freeResult( $res );
645
		}
646
647
		// apply options to overall result
648
		$result = $this->store->applyRequestOptions( $result, $requestOptions );
649
650
651
		return $result;
652
	}
653
654
	/**
655
	 * Implementation of SMWStore::getInProperties(). This function is meant to
656
	 * be used for finding properties that link to wiki pages.
657
	 *
658
	 * @since 1.8
659
	 * @see SMWStore::getInProperties
660
	 *
661
	 * @param SMWDataItem $value
662
	 * @param SMWRequestOptions|null $requestOptions
663
	 *
664
	 * @return array of SMWWikiPageValue
665
	 */
666 15
	public function getInProperties( SMWDataItem $value, SMWRequestOptions $requestOptions = null ) {
667
668 15
		$db = $this->store->getConnection();
669 15
		$result = array();
670
671
		// Potentially need to get more results, since options apply to union.
672 15
		if ( $requestOptions !== null ) {
673 4
			$subOptions = clone $requestOptions;
674 4
			$subOptions->limit = $requestOptions->limit + $requestOptions->offset;
675 4
			$subOptions->offset = 0;
676
		} else {
677 11
			$subOptions = null;
678
		}
679
680 15
		$diType = $value->getDIType();
681
682 15
		foreach ( $this->store->getPropertyTables() as $proptable ) {
683 15
			if ( $diType != $proptable->getDiType() ) {
684 15
				continue;
685
			}
686
687 15
			$where = $from = '';
0 ignored issues
show
$from is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
688 15
			if ( !$proptable->isFixedPropertyTable() ) { // join ID table to get property titles
689 15
				$from = $db->tableName( SMWSql3SmwIds::TABLE_NAME ) . " INNER JOIN " . $db->tableName( $proptable->getName() ) . " AS t1 ON t1.p_id=smw_id";
690 15
				$this->prepareValueQuery( $from, $where, $proptable, $value, 1 );
691
692 15
				$where .= " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWIW_OUTDATED ) . " AND smw_iw!=" . $db->addQuotes( SMW_SQL3_SMWDELETEIW );
693
694 15
				$res = $db->select( $from, 'DISTINCT smw_title,smw_sortkey,smw_iw',
695
						// select sortkey since it might be used in ordering (needed by Postgres)
696 15
						$where . $this->store->getSQLConditions( $subOptions, 'smw_sortkey', 'smw_sortkey', $where !== '' ),
697 15
						__METHOD__, $this->store->getSQLOptions( $subOptions, 'smw_sortkey' ) );
698
699 15
				foreach ( $res as $row ) {
700
					try {
701 3
						$result[] = new SMW\DIProperty( $row->smw_title );
702 15
					} catch (SMWDataItemException $e) {
703
						// has been observed to happen (empty property title); cause unclear; ignore this data
704
					}
705
				}
706
			} else {
707 15
				$from = $db->tableName( $proptable->getName() ) . " AS t1";
708 15
				$this->prepareValueQuery( $from, $where, $proptable, $value, 1 );
709 15
				$res = $db->select( $from, '*', $where, __METHOD__, array( 'LIMIT' => 1 ) );
710
711 15
				if ( $db->numRows( $res ) > 0 ) {
712 8
					$result[] = new SMW\DIProperty( $proptable->getFixedProperty() );
713
				}
714
			}
715 15
			$db->freeResult( $res );
716
		}
717
718 15
		$result = $this->store->applyRequestOptions( $result, $requestOptions ); // apply options to overall result
719
720 15
		return $result;
721
	}
722
723
}
724