Completed
Push — master ( 264630...c90943 )
by mw
230:08 queued 195:34
created

includes/storage/SQLStore/SMW_SQLStore3.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\DIConcept;
5
use SMW\DIProperty;
6
use SMW\DIWikiPage;
7
use SMW\SemanticData;
8
use SMW\SQLStore\PropertyTableInfoFetcher;
9
use SMW\SQLStore\SQLStoreFactory;
10
use SMW\SQLStore\TableDefinition;
11
12
/**
13
 * SQL-based implementation of SMW's storage abstraction layer.
14
 *
15
 * @author Markus Krötzsch
16
 * @author Jeroen De Dauw
17
 * @author Nischay Nahata
18
 *
19
 * @since 1.8
20
 *
21
 * @ingroup SMWStore
22
 */
23
24
// The use of the following constants is explained in SMWSQLStore3::setup():
25
define( 'SMW_SQL3_SMWIW_OUTDATED', ':smw' ); // virtual "interwiki prefix" for old-style special SMW objects (no longer used)
26
define( 'SMW_SQL3_SMWREDIIW', ':smw-redi' ); // virtual "interwiki prefix" for SMW objects that are redirected
27
define( 'SMW_SQL3_SMWBORDERIW', ':smw-border' ); // virtual "interwiki prefix" separating very important pre-defined properties from the rest
28
define( 'SMW_SQL3_SMWINTDEFIW', ':smw-intprop' ); // virtual "interwiki prefix" marking internal (invisible) predefined properties
29
define( 'SMW_SQL3_SMWDELETEIW', ':smw-delete' ); // virtual "interwiki prefix" marking a deleted subject, see #1100
30
31
/**
32
 * Storage access class for using the standard MediaWiki SQL database for
33
 * keeping semantic data.
34
 *
35
 * @note Regarding the use of interwiki links in the store, there is currently
36
 * no support for storing semantic data about interwiki objects, and hence
37
 * queries that involve interwiki objects really make sense only for them
38
 * occurring in object positions. Most methods still use the given input
39
 * interwiki text as a simple way to filter out results that may be found if an
40
 * interwiki object is given but a local object of the same name exists. It is
41
 * currently not planned to support things like interwiki reuse of properties.
42
 *
43
 * @since 1.8
44
 * @ingroup SMWStore
45
 */
46
class SMWSQLStore3 extends SMWStore {
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...
47
48
	/**
49
	 * Specifies the border limit (upper bound) for pre-defined properties used
50
	 * in the ID_TABLE
51
	 *
52
	 * When changing the upper bound, please make sure to copy the current upper
53
	 * bound as legcy to the SMWSQLStore3SetupHandlers::checkPredefinedPropertyBorder
54
	 */
55
	const FIXED_PROPERTY_ID_UPPERBOUND = 50;
56
57
	/**
58
	 * Name of the table to store the concept cache in.
59
	 *
60
	 * @note This should never change. If it is changed, the concept caches
61
	 * will appear empty until they are recomputed.
62
	 */
63
	const CONCEPT_CACHE_TABLE = 'smw_concept_cache';
64
	const CONCEPT_TABLE = 'smw_fpt_conc';
65
66
	/**
67
	 * Name of the table to store the concept cache in.
68
	 *
69
	 * @note This should never change, but if it does then its contents can
70
	 * simply be rebuilt by running the setup.
71
	 */
72
	const PROPERTY_STATISTICS_TABLE = 'smw_prop_stats';
73
74
	/**
75
	 * Name of the table that manages the query dependency links
76
	 */
77
	const QUERY_LINKS_TABLE = 'smw_query_links';
78
79
	/**
80
	 * Name of the table that manages the fulltext index
81
	 */
82
	const FT_SEARCH_TABLE = 'smw_ft_search';
83
84
	/**
85
	 * Name of the table that manages the Store IDs
86
	 */
87
	const ID_TABLE = 'smw_object_ids';
88
89
	/**
90
	 * @var SQLStoreFactory
91
	 */
92
	private $factory;
93
94
	/**
95
	 * @var PropertyTableInfoFetcher|null
96
	 */
97
	private $propertyTableInfoFetcher = null;
98
99
	/**
100
	 * @var PropertyTableIdReferenceFinder
101
	 */
102
	private $propertyTableIdReferenceFinder;
103
104
	/**
105
	 * @var RequestOptionsProcessor|null
106
	 */
107
	private $requestOptionsProcessor = null;
108
109
	/**
110
	 * @var DataItemHandlerDispatcher
111
	 */
112
	private $dataItemHandlerDispatcher;
113
114
	/**
115
	 * @var EntityLookup
116
	 */
117
	private $entityLookup;
118
119
	/**
120
	 * Object to access the SMW IDs table.
121
	 *
122
	 * @since 1.8
123
	 * @var SMWSql3SmwIds
124
	 */
125
	public $smwIds;
126
127
	/**
128
	 * The reader object used by this store. Initialized by getReader()
129
	 * Always access using getReader()
130
	 *
131
	 * @since 1.8
132
	 * @var SMWSQLStore3Readers
133
	 */
134
	protected $reader = false;
135
136
	/**
137
	 * The writer object used by this store. Initialized by getWriter(),
138
	 * which is the only way in which it should be accessed.
139
	 *
140
	 * @since 1.8
141
	 * @var SMWSQLStore3Writers
142
	 */
143
	protected $writer = false;
144
145
	/**
146
	 * Cache for SemanticData objects, indexed by SMW ID.
147
	 *
148
	 * @todo In the future, the cache should be managed by a helper class.
149
	 *
150
	 * @since 1.8
151
	 * @var array
152
	 */
153
	public $m_semdata = array();
154
155
	/**
156
	 * Like SMWSQLStore3::m_semdata, but containing flags indicating
157
	 * completeness of the SemanticData objs.
158
	 *
159
	 * @since 1.8
160
	 * @var array
161
	 */
162
	public $m_sdstate = array();
163
164
	/**
165
	 * @since 1.8
166
	 */
167
	public function __construct() {
168
		$this->factory = new SQLStoreFactory( $this );
169
		$this->smwIds = $this->factory->newIdTableManager();
170
	}
171
172
	/**
173
	 * Get an object of the dataitem handler from the dataitem provided.
174
	 *
175
	 * @since 1.8
176 16
	 * @param integer $diType
177 16
	 *
178 16
	 * @return SMWDIHandler
179 16
	 * @throws RuntimeException if no handler exists for the given type
180
	 */
181
	public function getDataItemHandlerForDIType( $diType ) {
182
183
		if ( $this->dataItemHandlerDispatcher === null ) {
184
			$this->dataItemHandlerDispatcher = $this->factory->newDataItemHandlerDispatcher( $this );
185
		}
186
187
		return $this->dataItemHandlerDispatcher->getHandlerByType( $diType );
188
	}
189
190 252
///// Reading methods /////
191
192 252
	public function getReader() {
193 5
		if( $this->reader == false ) {
194
			$this->reader = new SMWSQLStore3Readers( $this );//Initialize if not done already
195
		}
196 252
197
		return $this->reader;
198
	}
199
200
	public function getSemanticData( DIWikiPage $subject, $filter = false ) {
201 260
		return $this->getEntityLookup()->getSemanticData( $subject, $filter );
202 260
	}
203 5
204
	/**
205
	 * @param mixed $subject
206 260
	 * @param DIProperty $property
207
	 * @param null $requestOptions
208
	 *
209 221
	 * @return SMWDataItem[]
210 221
	 */
211
	public function getPropertyValues( $subject, DIProperty $property, $requestOptions = null ) {
212
		return $this->getEntityLookup()->getPropertyValues(	$subject, $property, $requestOptions );
213
	}
214
215
	public function getProperties( DIWikiPage $subject, $requestOptions = null ) {
216
		return $this->getEntityLookup()->getProperties( $subject, $requestOptions );
217
	}
218
219
	public function getPropertySubjects( DIProperty $property, $dataItem, $requestOptions = null ) {
220 219
		return $this->getEntityLookup()->getPropertySubjects( $property, $dataItem, $requestOptions );
221 219
	}
222
223
	public function getAllPropertySubjects( DIProperty $property, $requestoptions = null ) {
224 2
		return $this->getEntityLookup()->getAllPropertySubjects( $property, $requestoptions );
225 2
	}
226
227
	public function getInProperties( SMWDataItem $value, $requestoptions = null ) {
228 155
		return $this->getEntityLookup()->getInProperties( $value, $requestoptions );
229 155
	}
230
231
232 149
///// Writing methods /////
233 149
234
235
	public function getWriter() {
236 17
		if( $this->writer == false ) {
237 17
			$this->writer = new SMWSQLStore3Writers( $this );//Initialize if not done already
238
		}
239
240
		return $this->writer;
241
	}
242
243
	public function deleteSubject( Title $title ) {
244 250
245 250
		$subject = DIWikiPage::newFromTitle( $title );
246 4
247
		$this->getEntityLookup()->resetCacheBy(
248
			$subject
249 250
		);
250
251
		$this->getWriter()->deleteSubject( $title );
252 230
253
		$this->doDeferredCachedListLookupUpdate(
254 230
			$subject
255
		);
256 230
	}
257
258
	protected function doDataUpdate( SemanticData $semanticData ) {
259
260 230
		$this->getEntityLookup()->resetCacheBy(
261
			$semanticData->getSubject()
262 230
		);
263
264
		$this->getWriter()->doDataUpdate( $semanticData );
265 230
266
		$this->doDeferredCachedListLookupUpdate(
267 242
			$semanticData->getSubject()
268
		);
269 242
	}
270 242
271
	public function changeTitle( Title $oldtitle, Title $newtitle, $pageid, $redirid = 0 ) {
272
273 242
		$this->getEntityLookup()->resetCacheBy(
274
			DIWikiPage::newFromTitle( $oldtitle )
275 242
		);
276 242
277
		$this->getEntityLookup()->resetCacheBy(
278 242
			DIWikiPage::newFromTitle( $newtitle )
279
		);
280 25
281
		$this->getWriter()->changeTitle( $oldtitle, $newtitle, $pageid, $redirid );
282 25
283 25
		$this->doDeferredCachedListLookupUpdate(
284
			DIWikiPage::newFromTitle( $oldtitle )
285
		);
286 25
	}
287 25
288
	private function doDeferredCachedListLookupUpdate( DIWikiPage $subject ) {
289
290 25
		if ( $subject->getNamespace() !== SMW_NS_PROPERTY ) {
291
			return null;
292 25
		}
293 25
294
		$deferredCallableUpdate = $this->factory->newDeferredCallableCachedListLookupUpdate();
295 25
		$deferredCallableUpdate->setOrigin( __METHOD__ );
296
		$deferredCallableUpdate->pushToUpdateQueue();
297 250
	}
298
299 250
///// Query answering /////
300 246
301
	/**
302
	 * @note Move hooks to the base class in 3.*
303 164
	 *
304 164
	 * @see SMWStore::fetchQueryResult
305 164
	 *
306 164
	 * @since 1.8
307
	 * @param SMWQuery $query
308
	 * @return SMWQueryResult|string|integer depends on $query->querymode
309
	 */
310
	public function getQueryResult( SMWQuery $query ) {
311
312
		$result = null;
313
		$start = microtime( true );
314
315
		if ( \Hooks::run( 'SMW::Store::BeforeQueryResultLookupComplete', array( $this, $query, &$result ) ) ) {
316
			$result = $this->fetchQueryResult( $query );
317
		}
318
319 162
		\Hooks::run( 'SMW::SQLStore::AfterQueryResultLookupComplete', array( $this, &$result ) );
320
		\Hooks::run( 'SMW::Store::AfterQueryResultLookupComplete', array( $this, &$result ) );
321 162
322 162
		$query->setOption( SMWQuery::PROC_QUERY_TIME, microtime( true ) - $start );
323
324 162
		return $result;
325 161
	}
326
327
	protected function fetchQueryResult( SMWQuery $query ) {
328 162
		return $this->factory->newSlaveQueryEngine()->getQueryResult( $query );
329 162
	}
330
331 162
///// Special page functions /////
332
333 162
	/**
334
	 * @param RequestOptions|null $requestOptions
335
	 *
336 158
	 * @return CachedListLookup
337 158
	 */
338
	public function getPropertiesSpecial( $requestOptions = null ) {
339
		return $this->factory->newPropertyUsageCachedListLookup( $requestOptions );
340
	}
341
342
	/**
343
	 * @param RequestOptions|null $requestOptions
344
	 *
345
	 * @return CachedListLookup
346
	 */
347 1
	public function getUnusedPropertiesSpecial( $requestOptions = null ) {
348 1
		return $this->factory->newUnusedPropertyCachedListLookup( $requestOptions );
349
	}
350
351
	/**
352
	 * @param RequestOptions|null $requestOptions
353
	 *
354
	 * @return CachedListLookup
355
	 */
356 2
	public function getWantedPropertiesSpecial( $requestOptions = null ) {
357 2
		return $this->factory->newUndeclaredPropertyCachedListLookup( $requestOptions );
358
	}
359
360
	public function getStatistics() {
361
		return $this->factory->newUsageStatisticsCachedListLookup()->fetchList();
362
	}
363
364
365 2
///// Setup store /////
366 2
367
368
	/**
369 1
	 * @since 1.8
370 1
	 *
371
	 * {@inheritDoc}
372
	 */
373
	public function setup( $verbose = true ) {
374
		return $this->factory->newInstaller()->install( $verbose );
375
	}
376 3
377 3
	/**
378
	 * @since 1.8
379
	 *
380
	 * {@inheritDoc}
381 3
	 */
382
	public function drop( $verbose = true ) {
383
		return $this->factory->newInstaller()->uninstall( $verbose );
384 3
	}
385 3
386
	public function refreshData( &$id, $count, $namespaces = false, $usejobs = true ) {
387
388 1
		$entityRebuildDispatcher = $this->factory->newEntityRebuildDispatcher();
389 1
390
		$entityRebuildDispatcher->setDispatchRangeLimit( $count );
391
		$entityRebuildDispatcher->setRestrictionToNamespaces( $namespaces );
392 7
		$entityRebuildDispatcher->useJobQueueScheduler( $usejobs );
393
394 7
		return $entityRebuildDispatcher;
395
	}
396 7
397 7
398 7
///// Concept caching /////
399
400 7
	/**
401
	 * Refresh the concept cache for the given concept.
402
	 *
403
	 * @since 1.8
404
	 * @param Title $concept
405
	 * @return array of error strings (empty if no errors occurred)
406
	 */
407
	public function refreshConceptCache( Title $concept ) {
408
		return $this->factory->newMasterConceptCache()->refreshConceptCache( $concept );
409
	}
410
411
	/**
412
	 * Delete the concept cache for the given concept.
413 5
	 *
414 5
	 * @since 1.8
415
	 * @param Title $concept
416
	 */
417
	public function deleteConceptCache( $concept ) {
418
		$this->factory->newMasterConceptCache()->deleteConceptCache( $concept );
419
	}
420
421
	/**
422
	 * Return status of the concept cache for the given concept as an array
423 6
	 * with key 'status' ('empty': not cached, 'full': cached, 'no': not
424 6
	 * cachable). If status is not 'no', the array also contains keys 'size'
425 6
	 * (query size), 'depth' (query depth), 'features' (query features). If
426
	 * status is 'full', the array also contains keys 'date' (timestamp of
427
	 * cache), 'count' (number of results in cache).
428
	 *
429
	 * @since 1.8
430
	 * @param Title|SMWWikiPageValue $concept
431
	 *
432
	 * @return DIConcept|null
433
	 */
434
	public function getConceptCacheStatus( $concept ) {
435
		return $this->factory->newSlaveConceptCache()->getStatus( $concept );
436
	}
437
438
439
///// Helper methods, mostly protected /////
440 5
441 5
	/**
442
	 * @see RequestOptionsProcessor::getSQLOptionsFrom
443
	 *
444
	 * @since 1.8
445
	 *
446
	 * @param SMWRequestOptions|null $requestOptions
447
	 * @param string $valuecol
448
	 *
449
	 * @return array
450
	 */
451
	public function getSQLOptions( SMWRequestOptions $requestOptions = null, $valueCol = '' ) {
452
		return $this->getRequestOptionsProcessor()->getSQLOptionsFrom( $requestOptions, $valueCol );
453
	}
454
455
	/**
456
	 * @see RequestOptionsProcessor::getSQLConditionsFrom
457 190
	 *
458 190
	 * @since 1.8
459
	 *
460
	 * @param SMWRequestOptions|null $requestOptions
461
	 * @param string $valueCol name of SQL column to which conditions apply
462
	 * @param string $labelCol name of SQL column to which string conditions apply, if any
463
	 * @param boolean $addAnd indicate whether the string should begin with " AND " if non-empty
464
	 *
465
	 * @return string
466
	 */
467
	public function getSQLConditions( SMWRequestOptions $requestOptions = null, $valueCol = '', $labelCol = '', $addAnd = true ) {
468
		return $this->getRequestOptionsProcessor()->getSQLConditionsFrom( $requestOptions, $valueCol, $labelCol, $addAnd );
469
	}
470
471
	/**
472
	 * @see RequestOptionsProcessor::applyRequestOptionsTo
473 158
	 *
474 158
	 * @since 1.8
475
	 *
476
	 * @param array $data array of SMWDataItem objects
477
	 * @param SMWRequestOptions|null $requestOptions
478
	 *
479
	 * @return SMWDataItem[]
480
	 */
481
	public function applyRequestOptions( array $data, SMWRequestOptions $requestOptions = null ) {
482
		return $this->getRequestOptionsProcessor()->applyRequestOptionsTo( $data, $requestOptions );
483
	}
484
485
	/**
486
	 * PropertyTableInfoFetcher::findTableIdForDataTypeTypeId
487 180
	 *
488 180
	 * @param string $typeid
489
	 *
490
	 * @return string
491
	 */
492
	public function findTypeTableId( $typeid ) {
493
		return $this->getPropertyTableInfoFetcher()->findTableIdForDataTypeTypeId( $typeid );
494
	}
495
496
	/**
497
	 * PropertyTableInfoFetcher::findTableIdForDataItemTypeId
498 2
	 *
499 2
	 * @param integer $dataItemId
500
	 *
501
	 * @return string
502
	 */
503
	public function findDiTypeTableId( $dataItemId ) {
504
		return $this->getPropertyTableInfoFetcher()->findTableIdForDataItemTypeId( $dataItemId );
505
	}
506
507
	/**
508
	 * PropertyTableInfoFetcher::findTableIdForProperty
509
	 *
510
	 * @param DIProperty $property
511
	 *
512
	 * @return string
513
	 */
514
	public function findPropertyTableID( DIProperty $property ) {
515
		return $this->getPropertyTableInfoFetcher()->findTableIdForProperty( $property );
516
	}
517
518
	/**
519
	 * Change an SMW page id across all relevant tables. The redirect table
520 238
	 * is also updated (without much effect if the change happended due to
521 238
	 * some redirect, since the table should not contain the id of the
522
	 * redirected page). If namespaces are given, then they are used to
523
	 * delete any entries that are limited to one particular namespace (e.g.
524
	 * only properties can be used as properties) instead of moving them.
525
	 *
526
	 * The id in the SMW IDs table is not touched.
527
	 *
528
	 * @note This method only changes internal page IDs in SMW. It does not
529
	 * assume any change in (title-related) data, as e.g. in a page move.
530
	 * Internal objects (subobject) do not need to be updated since they
531
	 * refer to the title of their parent page, not to its ID.
532
	 *
533
	 * @since 1.8
534
	 * @param integer $oldid numeric ID that is to be changed
535
	 * @param integer $newid numeric ID to which the records are to be changed
536
	 * @param integer $oldnamespace namespace of old id's page (-1 to ignore it)
537
	 * @param integer $newnamespace namespace of new id's page (-1 to ignore it)
538
	 * @param boolean $sdata stating whether to update subject references
539
	 * @param boolean $podata stating if to update property/object references
540
	 */
541
	public function changeSMWPageID( $oldid, $newid, $oldnamespace = -1,
542
				$newnamespace = -1, $sdata = true, $podata = true ) {
543
544
		$db = $this->getConnection( 'mw.db' );
545
546
		// Change all id entries in property tables:
547 10
		foreach ( $this->getPropertyTables() as $proptable ) {
548
			if ( $sdata && $proptable->usesIdSubject() ) {
549
				$db->update( $proptable->getName(), array( 's_id' => $newid ), array( 's_id' => $oldid ), __METHOD__ );
550 10
			}
551
552
			if ( $podata ) {
553 10
				if ( ( ( $oldnamespace == -1 ) || ( $oldnamespace == SMW_NS_PROPERTY ) ) && ( !$proptable->isFixedPropertyTable() ) ) {
554 10
					if ( ( $newnamespace == -1 ) || ( $newnamespace == SMW_NS_PROPERTY ) ) {
555 10
						$db->update( $proptable->getName(), array( 'p_id' => $newid ), array( 'p_id' => $oldid ), __METHOD__ );
556
					} else {
557
						$db->delete( $proptable->getName(), array( 'p_id' => $oldid ), __METHOD__ );
558 10
					}
559 10
				}
560 1
561 1
				foreach ( $proptable->getFields( $this ) as $fieldname => $type ) {
562
					if ( $type == 'p' ) {
563
						$db->update( $proptable->getName(), array( $fieldname => $newid ), array( $fieldname => $oldid ), __METHOD__ );
564
					}
565
				}
566
			}
567 10
		}
568 10
569 10
		// Change id entries in concept-related tables:
570
		if ( $sdata && ( ( $oldnamespace == -1 ) || ( $oldnamespace == SMW_NS_CONCEPT ) ) ) {
571
			if ( ( $newnamespace == -1 ) || ( $newnamespace == SMW_NS_CONCEPT ) ) {
572
				$db->update( 'smw_fpt_conc', array( 's_id' => $newid ), array( 's_id' => $oldid ), __METHOD__ );
573
				$db->update( self::CONCEPT_CACHE_TABLE, array( 's_id' => $newid ), array( 's_id' => $oldid ), __METHOD__ );
574
			} else {
575
				$db->delete( 'smw_fpt_conc', array( 's_id' => $oldid ), __METHOD__ );
576 10
				$db->delete( self::CONCEPT_CACHE_TABLE, array( 's_id' => $oldid ), __METHOD__ );
577
			}
578
		}
579
580
		if ( $podata ) {
581
			$db->update( self::CONCEPT_CACHE_TABLE, array( 'o_id' => $newid ), array( 'o_id' => $oldid ), __METHOD__ );
582
		}
583
	}
584
585
	/**
586 10
	 * PropertyTableInfoFetcher::getPropertyTableDefinitions
587 10
	 *
588
	 * @return TableDefinition[]
589 10
	 */
590
	public function getPropertyTables() {
591
		return $this->getPropertyTableInfoFetcher()->getPropertyTableDefinitions();
592
	}
593
594
	/**
595
	 * Returns SMW Id object
596 255
	 *
597 255
	 * @since 1.9
598
	 *
599
	 * @return SMWSql3SmwIds
600
	 */
601
	public function getObjectIds() {
602
		return $this->smwIds;
603
	}
604
605
	/**
606
	 * Returns the statics table
607 258
	 *
608 258
	 * @since 1.9
609
	 *
610
	 * @return string
611
	 */
612
	public function getStatisticsTable() {
613
		return self::PROPERTY_STATISTICS_TABLE;
614
	}
615
616
	/**
617
	 * Resets internal objects
618 2
	 *
619 2
	 * @since 1.9.1.1
620
	 */
621
	public function clear() {
622
		parent::clear();
623
		$this->m_semdata = array();
624
		$this->m_sdstate = array();
625
		$this->propertyTableInfoFetcher = null;
626
		$this->getObjectIds()->clearCaches();
627 30
	}
628 30
629 30
	/**
630 30
	 * @since 2.1
631 30
	 *
632 30
	 * @param string $connectionTypeId
633 30
	 *
634
	 * @return \SMW\MediaWiki\Database
635
	 */
636
	public function getConnection( $connectionTypeId = 'mw.db' ) {
637
		return parent::getConnection( $connectionTypeId );
638
	}
639
640
	/**
641
	 * @since 2.2
642 288
	 *
643 288
	 * @return PropertyTableInfoFetcher
644
	 */
645
	public function getPropertyTableInfoFetcher() {
646
647
		if ( $this->propertyTableInfoFetcher === null ) {
648
			$this->propertyTableInfoFetcher = $this->factory->newPropertyTableInfoFetcher();
649
		}
650
651 258
		return $this->propertyTableInfoFetcher;
652
	}
653 258
654 237
	/**
655
	 * @since 2.4
656
	 *
657 258
	 * @return PropertyTableIdReferenceFinder
658
	 */
659
	public function getPropertyTableIdReferenceFinder() {
660
661
		if ( $this->propertyTableIdReferenceFinder === null ) {
662
			$this->propertyTableIdReferenceFinder = $this->factory->newPropertyTableIdReferenceFinder();
663
		}
664
665 2
		return $this->propertyTableIdReferenceFinder;
666
	}
667 2
668 1
	/**
669
	 * @return RequestOptionsProcessor
670
	 */
671 2
	private function getRequestOptionsProcessor() {
672
673
		if ( $this->requestOptionsProcessor === null ) {
674
			$this->requestOptionsProcessor = $this->factory->newRequestOptionsProcessor();
675
		}
676
677 193
		return $this->requestOptionsProcessor;
678
	}
679 193
680 1
	/**
681
	 * @return EntityLookup
682
	 */
683 193
	private function getEntityLookup() {
684
685
		if ( $this->entityLookup === null ) {
686
			$this->entityLookup = $this->factory->newEntityLookup();
687
		}
688
689 263
		return $this->entityLookup;
690
	}
691 263
692
}
693