SMWSql3SmwIds   F
last analyzed

Complexity

Total Complexity 123

Size/Duplication

Total Lines 1233
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 78.97%

Importance

Changes 0
Metric Value
dl 0
loc 1233
ccs 308
cts 390
cp 0.7897
rs 3.9999
c 0
b 0
f 0
wmc 123
lcom 1
cbo 11

34 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A checkIsRedirect() 0 9 1
A findRedirectIdFor() 0 3 1
A addRedirectForId() 0 3 1
A deleteRedirectEntry() 0 3 1
A getSMWPageIDandSort() 0 8 2
D getDatabaseIdAndSort() 0 110 20
B getListOfIdMatchesFor() 0 26 3
A exists() 0 3 1
B getIDFor() 0 54 7
A getSMWPageID() 0 4 1
A makeSMWPageID() 0 8 2
B makeDatabaseId() 0 66 7
A getPropertyInterwiki() 0 3 2
A updateInterwikiField() 0 18 2
A getSMWPropertyID() 0 8 2
A makeSMWPropertyID() 0 15 2
D getPredefinedData() 0 26 10
A moveSMWPageID() 0 73 3
B setCache() 0 25 6
A getDataItemById() 0 3 1
A getDataItemPoolHashListFor() 0 3 1
B getCachedId() 0 20 6
B getCachedSortKey() 0 16 6
B deleteCache() 0 17 6
B moveSubobjects() 0 12 5
A clearCaches() 0 7 1
A checkPropertySizeLimit() 0 9 3
A checkRegularSizeLimit() 0 9 3
C getPropertyTableHashes() 0 26 7
A setPropertyTableHashes() 0 15 2
A setPropertyTableHashesCache() 0 8 2
B debugDumpCacheStats() 0 22 4
A getIdTable() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like SMWSql3SmwIds often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SMWSql3SmwIds, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\DIProperty;
5
use SMW\DIWikiPage;
6
use SMW\HashBuilder;
7
use SMW\RequestOptions;
8
use SMW\SQLStore\IdToDataItemMatchFinder;
9
use SMW\SQLStore\PropertyStatisticsTable;
10
use SMW\SQLStore\RedirectInfoStore;
11
12
/**
13
 * @ingroup SMWStore
14
 * @since 1.8
15
 * @author Markus Krötzsch
16
 */
17
18
/**
19
 * Class to access the SMW IDs table in SQLStore3.
20
 * Provides transparent in-memory caching facilities.
21
 *
22
 * Documentation for the SMW IDs table: This table is a dictionary that
23
 * assigns integer IDs to pages, properties, and other objects used by SMW.
24
 * All tables that refer to such objects store these IDs instead. If the ID
25
 * information is lost (e.g., table gets deleted), then the data stored in SMW
26
 * is no longer meaningful: all tables need to be dropped, recreated, and
27
 * refreshed to get back to a working database.
28
 *
29
 * The table has a column for storing interwiki prefixes, used to refer to
30
 * pages on external sites (like in MediaWiki). This column is also used to
31
 * mark some special objects in the table, using "interwiki prefixes" that
32
 * cannot occur in MediaWiki:
33
 *
34
 * - Rows with iw SMW_SQL3_SMWREDIIW are similar to normal entries for
35
 * (internal) wiki pages, but the iw indicates that the page is a redirect, the
36
 * (target of which should be sought using the smw_fpt_redi table.
37
 *
38
 * - The (unique) row with iw SMW_SQL3_SMWBORDERIW just marks the border
39
 * between predefined ids (rows that are reserved for hardcoded ids built into
40
 * SMW) and normal entries. It is no object, but makes sure that SQL's auto
41
 * increment counter is high enough to not add any objects before that marked
42
 * "border".
43
 *
44
 * @note Do not call the constructor of SMWDIWikiPage using data from the SMW
45
 * IDs table; use SMWDIHandlerWikiPage::dataItemFromDBKeys() instead. The table
46
 * does not always contain data as required wiki pages. Especially predefined
47
 * properties are represented by language-independent keys rather than proper
48
 * titles. SMWDIHandlerWikiPage takes care of this.
49
 *
50
 * @since 1.8
51
 *
52
 * @ingroup SMWStore
53
 */
54
class SMWSql3SmwIds {
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...
55
56
	/**
57
	 * Specifies the border limit for pre-defined properties declared
58
	 * in SMWSql3SmwIds::special_ids
59
	 */
60
	const FXD_PROP_BORDER_ID = SMWSQLStore3::FIXED_PROPERTY_ID_UPPERBOUND;
61
62
	/**
63
	 * Name of the table to store IDs in.
64
	 *
65
	 * @note This should never change. Existing wikis will have to drop and
66
	 * rebuild their SMW tables completely to recover from any change here.
67
	 */
68
	const TABLE_NAME = SMWSQLStore3::ID_TABLE;
69
70
	const POOLCACHE_ID = 'sql.store.id.cache';
71
72
	/**
73
	 * Id for which property table hashes are cached, if any.
74
	 *
75
	 * @since 1.8
76
	 * @var integer
77
	 */
78
	protected $hashCacheId = 0;
79
80
	/**
81
	 * Cached property table hashes for $hashCacheId.
82
	 *
83
	 * @since 1.8
84
	 * @var string
85
	 */
86
	protected $hashCacheContents = '';
87
88
	/**
89
	 * Maximal number of cached property IDs.
90
	 *
91
	 * @since 1.8
92
	 * @var integer
93
	 */
94
	public static $PROP_CACHE_MAX_SIZE = 250;
95
96
	/**
97
	 * Maximal number of cached non-property IDs.
98
	 *
99
	 * @since 1.8
100
	 * @var integer
101
	 */
102
	public static $PAGE_CACHE_MAX_SIZE = 500;
103
104
	protected $selectrow_sort_debug = 0;
105
	protected $selectrow_redi_debug = 0;
106
	protected $prophit_debug = 0;
107
	protected $propmiss_debug = 0;
108
	protected $reghit_debug = 0;
109
	protected $regmiss_debug = 0;
110
111
	static protected $singleton_debug = null;
112
113
	/**
114
	 * Parent SMWSQLStore3.
115
	 *
116
	 * @since 1.8
117
	 * @var SMWSQLStore3
118
	 */
119
	public $store;
120
121
	/**
122
	 * Cache for property IDs.
123
	 *
124
	 * @note Tests indicate that it is more memory efficient to have two
125
	 * arrays (IDs and sortkeys) than to have one array that stores both
126
	 * values in some data structure (other than a single string).
127
	 *
128
	 * @since 1.8
129
	 * @var array
130
	 */
131
	protected $prop_ids = array();
132
133
	/**
134
	 * @var IdToDataItemMatchFinder
135
	 */
136
	private $idToDataItemMatchFinder;
137
138
	/**
139
	 * @var RedirectInfoStore
140
	 */
141
	private $redirectInfoStore;
142
143
	/**
144
	 * Cache for property sortkeys.
145
	 *
146
	 * @since 1.8
147
	 * @var array
148
	 */
149
	protected $prop_sortkeys = array();
150
151
	/**
152
	 * Cache for non-property IDs.
153
	 *
154
	 * @since 1.8
155
	 * @var array
156
	 */
157
	protected $regular_ids = array();
158
159
	/**
160
	 * Cache for non-property sortkeys.
161
	 *
162
	 * @since 1.8
163
	 * @var array
164
	 */
165
	protected $regular_sortkeys = array();
166
167
	/**
168
	 * Use pre-defined ids for Very Important Properties, avoiding frequent
169
	 * ID lookups for those.
170
	 *
171
	 * @note These constants also occur in the store. Changing them will
172
	 * require to run setup.php again. They can also not be larger than 50.
173
	 *
174
	 * @since 1.8
175
	 * @var array
176
	 */
177
	public static $special_ids = array(
178
		'_TYPE' => 1,
179
		'_URI'  => 2,
180
		'_INST' => 4,
181
		'_UNIT' => 7,
182
		'_IMPO' => 8,
183
		'_PPLB' => 9,
184
		'_PDESC' => 10,
185
		'_PREC' => 11,
186
		'_CONV' => 12,
187
		'_SERV' => 13,
188
		'_PVAL' => 14,
189
		'_REDI' => 15,
190
		'_DTITLE' => 16,
191
		'_SUBP' => 17,
192
		'_SUBC' => 18,
193
		'_CONC' => 19,
194
//		'_SF_DF' => 20, // Semantic Form's default form property
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
195
//		'_SF_AF' => 21,  // Semantic Form's alternate form property
196
		'_ERRP' => 22,
197
// 		'_1' => 23, // properties for encoding (short) lists
0 ignored issues
show
Unused Code Comprehensibility introduced by
49% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
198
// 		'_2' => 24,
199
// 		'_3' => 25,
200
// 		'_4' => 26,
201
// 		'_5' => 27,
202
// 		'_SOBJ' => 27
203
		'_LIST' => 28,
204
		'_MDAT' => 29,
205
		'_CDAT' => 30,
206
		'_NEWP' => 31,
207
		'_LEDT' => 32,
208
		// properties related to query management
209
		'_ASK'   =>  33,
210
		'_ASKST' =>  34,
211
		'_ASKFO' =>  35,
212
		'_ASKSI' =>  36,
213
		'_ASKDE' =>  37,
214
		'_ASKPA' =>  38,
215
		'_ASKSC' =>  39,
216
		'_LCODE' =>  40,
217
		'_TEXT'  =>  41,
218
	);
219
220
	/**
221
	 * Constructor.
222
	 *
223
	 * @since 1.8
224
	 * @param SMWSQLStore3 $store
225 30
	 */
226 30
	public function __construct( SMWSQLStore3 $store, IdToDataItemMatchFinder $idToDataItemMatchFinder ) {
227
		$this->store = $store;
228 30
		// Yes, this is a hack, but we only use it for convenient debugging:
229
		self::$singleton_debug = $this;
230 30
231
		$this->idToDataItemMatchFinder = $idToDataItemMatchFinder;
232 30
233 30
		$this->redirectInfoStore = new RedirectInfoStore(
234
			$this->store->getConnection( 'mw.db' )
235
		);
236 30
237 30
		$this->intermediaryIdCache = ApplicationFactory::getInstance()->getInMemoryPoolCache()->getPoolCacheById( self::POOLCACHE_ID );
0 ignored issues
show
Bug introduced by
The property intermediaryIdCache does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
238
	}
239
240
	/**
241
	 * @since  2.1
242
	 *
243
	 * @param DIWikiPage $subject
244
	 *
245
	 * @return boolean
246 145
	 */
247
	public function checkIsRedirect( DIWikiPage $subject ) {
248 145
249 145
		$redirectId = $this->findRedirectIdFor(
250 145
			$subject->getDBKey(),
251
			$subject->getNamespace()
252
		);
253 145
254
		return $redirectId != 0;
255
	}
256
257
	/**
258
	 * @see RedirectInfoStore::findRedirectIdFor
259
	 *
260
	 * @since 2.1
261
	 *
262
	 * @param string $title DB key
263
	 * @param integer $namespace
264
	 *
265
	 * @return integer
266 289
	 */
267 289
	public function findRedirectIdFor( $title, $namespace ) {
268
		return $this->redirectInfoStore->findRedirectIdFor( $title, $namespace );
269
	}
270
271
	/**
272
	 * @see RedirectInfoStore::addRedirectForId
273
	 *
274
	 * @since 2.1
275
	 *
276
	 * @param integer $id
277
	 * @param string $title
278
	 * @param integer $namespace
279 26
	 */
280 26
	public function addRedirectForId( $id, $title, $namespace ) {
281 26
		$this->redirectInfoStore->addRedirectForId( $id, $title, $namespace );
282
	}
283
284
	/**
285
	 * @see RedirectInfoStore::deleteRedirectEntry
286
	 *
287
	 * @since 2.1
288
	 *
289
	 * @param string $title
290
	 * @param integer $namespace
291 25
	 */
292 25
	public function deleteRedirectEntry( $title, $namespace ) {
293 25
		$this->redirectInfoStore->deleteRedirectEntry( $title, $namespace );
294
	}
295
296
	/**
297
	 * Find the numeric ID used for the page of the given title,
298
	 * namespace, interwiki, and subobject. If $canonical is set to true,
299
	 * redirects are taken into account to find the canonical alias ID for
300
	 * the given page. If no such ID exists, 0 is returned. The Call-By-Ref
301
	 * parameter $sortkey is set to the current sortkey, or to '' if no ID
302
	 * exists.
303
	 *
304
	 * If $fetchhashes is true, the property table hash blob will be
305
	 * retrieved in passing if the opportunity arises, and cached
306
	 * internally. This will speed up a subsequent call to
307
	 * getPropertyTableHashes() for this id. This should only be done
308
	 * if such a call is intended, both to safe the previous cache and
309
	 * to avoid extra work (even if only a little) to fill it.
310
	 *
311
	 * @since 1.8
312
	 * @param string $title DB key
313
	 * @param integer $namespace namespace
314
	 * @param string $iw interwiki prefix
315
	 * @param string $subobjectName name of subobject
316
	 * @param string $sortkey call-by-ref will be set to sortkey
317
	 * @param boolean $canonical should redirects be resolved?
318
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
319
	 * @return integer SMW id or 0 if there is none
320 298
	 */
321 298
	public function getSMWPageIDandSort( $title, $namespace, $iw, $subobjectName, &$sortkey, $canonical, $fetchHashes = false ) {
322 298
		$id = $this->getPredefinedData( $title, $namespace, $iw, $subobjectName, $sortkey );
323 47
		if ( $id != 0 ) {
324
			return (int)$id;
325 296
		} else {
326
			return (int)$this->getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, $sortkey, $canonical, $fetchHashes );
327
		}
328
	}
329
330
	/**
331
	 * Find the numeric ID used for the page of the given normalized title,
332
	 * namespace, interwiki, and subobjectName. Predefined IDs are not
333
	 * taken into account (however, they would still be found correctly by
334
	 * an avoidable database read if they are stored correctly in the
335
	 * database; this should always be the case). In all other aspects, the
336
	 * method works just like getSMWPageIDandSort().
337
	 *
338
	 * @since 1.8
339
	 * @param string $title DB key
340
	 * @param integer $namespace namespace
341
	 * @param string $iw interwiki prefix
342
	 * @param string $subobjectName name of subobject
343
	 * @param string $sortkey call-by-ref will be set to sortkey
344
	 * @param boolean $canonical should redirects be resolved?
345
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
346
	 * @return integer SMW id or 0 if there is none
347 299
	 */
348 299
	protected function getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, &$sortkey, $canonical, $fetchHashes ) {
349
		global $smwgQEqualitySupport;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
350 299
351
		$db = $this->store->getConnection();
352
353
		// Integration test "query-04-02-subproperty-dc-import-marc21.json"
354
		// showed a deterministic failure (due to a wrong cache id during querying
355
		// for redirects) hence we force to read directly from the RedirectInfoStore
356 299
		// for objects marked as redirect
357 299
		if ( $iw === SMW_SQL3_SMWREDIIW && $canonical &&
358 288
			$smwgQEqualitySupport !== SMW_EQ_NONE && $subobjectName === '' ) {
359
			$id = $this->findRedirectIdFor( $title, $namespace );
360 299
		} else {
361
			$id = $this->getCachedId(
362
				$title,
363
				$namespace,
364
				$iw,
365
				$subobjectName
366
			);
367
		}
368 299
369 288
		if ( $id !== false ) { // cache hit
370 299
			$sortkey = $this->getCachedSortKey( $title, $namespace, $iw, $subobjectName );
371 299
		} elseif ( $iw == SMW_SQL3_SMWREDIIW && $canonical &&
372
			$smwgQEqualitySupport != SMW_EQ_NONE && $subobjectName === '' ) {
373
			$id = $this->findRedirectIdFor( $title, $namespace );
374
			if ( $id != 0 ) {
375
376
				if ( $fetchHashes ) {
377
					$select = array( 'smw_sortkey', 'smw_proptable_hash' );
378
				} else {
379
					$select = array( 'smw_sortkey' );
380
				}
381
382
				$row = $db->selectRow(
383
					self::TABLE_NAME,
384
					$select,
385
					array( 'smw_id' => $id ),
386
					__METHOD__
387
				);
388
389
				if ( $row !== false ) {
390
					$sortkey = $row->smw_sortkey;
391
					if ( $fetchHashes ) {
392
						$this->setPropertyTableHashesCache( $id, $row->smw_proptable_hash );
393
					}
394
				} else { // inconsistent DB; just recover somehow
395
					$sortkey = str_replace( '_', ' ', $title );
396
				}
397
			} else {
398
				$sortkey = '';
399
			}
400
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
401
		} else {
402 299
403 264
			if ( $fetchHashes ) {
404
				$select = array( 'smw_id', 'smw_sortkey', 'smw_proptable_hash' );
405 292
			} else {
406
				$select = array( 'smw_id', 'smw_sortkey' );
407
			}
408 299
409 299
			$row = $db->selectRow(
410
				self::TABLE_NAME,
411
				$select,
412 299
				array(
413 299
					'smw_title' => $title,
414 299
					'smw_namespace' => $namespace,
415 299
					'smw_iw' => $iw,
416
					'smw_subobject' => $subobjectName
417 299
				),
418
				__METHOD__
419
			);
420 299
421
			$this->selectrow_sort_debug++;
422 299
423 250
			if ( $row !== false ) {
424 250
				$id = $row->smw_id;
425 250
				$sortkey = $row->smw_sortkey;
426 250
				if ( $fetchHashes ) {
427
					$this->setPropertyTableHashesCache( $id, $row->smw_proptable_hash);
428
				}
429 282
			} else {
430 282
				$id = 0;
431
				$sortkey = '';
432
			}
433 299
434
			$this->setCache(
435
				$title,
436
				$namespace,
437
				$iw,
438
				$subobjectName,
439
				$id,
440
				$sortkey
441
			);
442
		}
443 299
444 288
		if ( $id == 0 && $subobjectName === '' && $iw === '' ) { // could be a redirect; check
445
			$id = $this->getSMWPageIDandSort(
446
				$title,
447 288
				$namespace,
448
				SMW_SQL3_SMWREDIIW,
449
				$subobjectName,
450
				$sortkey,
451
				$canonical,
452
				$fetchHashes
453
			);
454
		}
455 299
456
		return $id;
457
	}
458
459
	/**
460
	 * @since 2.3
461
	 *
462
	 * @param string $title DB key
463
	 * @param integer $namespace namespace
464
	 * @param string $iw interwiki prefix
465
	 * @param string $subobjectName name of subobject
466
	 *
467
	 * @param array
468 249
	 */
469
	public function getListOfIdMatchesFor( $title, $namespace, $iw, $subobjectName = '' ) {
470 249
471
		$matches = array();
472 249
473 249
		$rows = $this->store->getConnection( 'mw.db' )->select(
474 249
			self::TABLE_NAME,
475
			$select = array( 'smw_id' ),
476 249
			array(
0 ignored issues
show
Documentation introduced by
array('smw_title' => $ti...ect' => $subobjectName) is of type array<string,string|inte...w_subobject":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
477 249
				'smw_title' => $title,
478 249
				'smw_namespace' => $namespace,
479 249
				'smw_iw' => $iw,
480
				'smw_subobject' => $subobjectName
481 249
			),
482
			__METHOD__
483
		);
484 249
485
		if ( $rows === false ) {
486
			return $matches;
487
		}
488 249
489 242
		foreach ( $rows as $row ) {
490
			$matches[] = $row->smw_id;
491
		}
492 249
493
		return $matches;
494
	}
495
496
	/**
497
	 * @since 2.4
498
	 *
499
	 * @param DIWikiPage $subject
500
	 *
501
	 * @param boolean
502 39
	 */
503 39
	public function exists( DIWikiPage $subject ) {
504
		return $this->getIDFor( $subject ) > 0;
505
	}
506
507
	/**
508
	 * @note SMWSql3SmwIds::getSMWPageID has some issues with the cache as it returned
509
	 * 0 even though an object was matchable, using this method is safer then trying
510
	 * to encipher getSMWPageID related methods.
511
	 *
512
	 * It uses the PoolCache which means Lru is in place to avoid memory leakage.
513
	 *
514
	 * @since 2.4
515
	 *
516
	 * @param DIWikiPage $subject
517
	 *
518
	 * @param integer
519 102
	 */
520
	public function getIDFor( DIWikiPage $subject ) {
521
522 102
		// Try to match a predefined property
523 77
		if ( $subject->getNamespace() === SMW_NS_PROPERTY && $subject->getInterWiki() === '' ) {
524 77
			$property = DIProperty::newFromUserLabel( $subject->getDBKey() );
525
			$key = $property->getKey();
526
527 77
			// Has a fixed ID?
528 8
			if ( isset( self::$special_ids[$key] ) ) {
529
				return self::$special_ids[$key];
530
			}
531
532 77
			// Switch title for fixed properties without a fixed ID (e.g. _MIME is the smw_title)
533 3
			if ( !$property->isUserDefined() ) {
534
				$subject = new DIWikiPage( $key, SMW_NS_PROPERTY );
535
			}
536
		}
537 102
538
		$hash = HashBuilder::getHashIdForDiWikiPage( $subject );
539 102
540 88
		if ( ( $id = $this->intermediaryIdCache->fetch( $hash ) ) !== false ) {
541
			return $id;
542
		}
543 94
544
		$id = 0;
545 94
546 94
		$row = $this->store->getConnection( 'mw.db' )->selectRow(
547 94
			self::TABLE_NAME,
548
			array( 'smw_id' ),
549 94
			array(
550 94
				'smw_title' => $subject->getDBKey(),
551 94
				'smw_namespace' => $subject->getNamespace(),
552 94
				'smw_iw' => $subject->getInterWiki(),
553
				'smw_subobject' => $subject->getSubobjectName()
554 94
			),
555
			__METHOD__
556
		);
557 94
558 2
		if ( $row !== false ) {
559
			$id = $row->smw_id;
560
		}
561
562 94
		// Legacy
563 94
		$this->setCache(
564 94
			$subject->getDBKey(),
565 94
			$subject->getNamespace(),
566 94
			$subject->getInterWiki(),
567
			$subject->getSubobjectName(),
568 94
			$id,
569
			$subject->getSortKey()
570
		);
571 94
572
		return $id;
573
	}
574
575
	/**
576
	 * Convenience method for calling getSMWPageIDandSort without
577
	 * specifying a sortkey (if not asked for).
578
	 *
579
	 * @since 1.8
580
	 * @param string $title DB key
581
	 * @param integer $namespace namespace
582
	 * @param string $iw interwiki prefix
583
	 * @param string $subobjectName name of subobject
584
	 * @param boolean $canonical should redirects be resolved?
585
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
586
	 * @return integer SMW id or 0 if there is none
587 242
	 */
588 242
	public function getSMWPageID( $title, $namespace, $iw, $subobjectName, $canonical = true, $fetchHashes = false ) {
589 242
		$sort = '';
590
		return $this->getSMWPageIDandSort( $title, $namespace, $iw, $subobjectName, $sort, $canonical, $fetchHashes );
591
	}
592
593
	/**
594
	 * Find the numeric ID used for the page of the given title, namespace,
595
	 * interwiki, and subobjectName. If $canonical is set to true,
596
	 * redirects are taken into account to find the canonical alias ID for
597
	 * the given page. If no such ID exists, a new ID is created and
598
	 * returned. In any case, the current sortkey is set to the given one
599
	 * unless $sortkey is empty.
600
	 *
601
	 * @note Using this with $canonical==false can make sense, especially when
602
	 * the title is a redirect target (we do not want chains of redirects).
603
	 * But it is of no relevance if the title does not have an id yet.
604
	 *
605
	 * @since 1.8
606
	 * @param string $title DB key
607
	 * @param integer $namespace namespace
608
	 * @param string $iw interwiki prefix
609
	 * @param string $subobjectName name of subobject
610
	 * @param boolean $canonical should redirects be resolved?
611
	 * @param string $sortkey call-by-ref will be set to sortkey
612
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
613
	 * @return integer SMW id or 0 if there is none
614 277
	 */
615 277
	public function makeSMWPageID( $title, $namespace, $iw, $subobjectName, $canonical = true, $sortkey = '', $fetchHashes = false ) {
616 277
		$id = $this->getPredefinedData( $title, $namespace, $iw, $subobjectName, $sortkey );
617 13
		if ( $id != 0 ) {
618
			return (int)$id;
619 277
		} else {
620
			return (int)$this->makeDatabaseId( $title, $namespace, $iw, $subobjectName, $canonical, $sortkey, $fetchHashes );
621
		}
622
	}
623
624
	/**
625
	 * Find the numeric ID used for the page of the given normalized title,
626
	 * namespace, interwiki, and subobjectName. Predefined IDs are not
627
	 * taken into account (however, they would still be found correctly by
628
	 * an avoidable database read if they are stored correctly in the
629
	 * database; this should always be the case). In all other aspects, the
630
	 * method works just like makeSMWPageID(). Especially, if no ID exists,
631
	 * a new ID is created and returned.
632
	 *
633
	 * @since 1.8
634
	 * @param string $title DB key
635
	 * @param integer $namespace namespace
636
	 * @param string $iw interwiki prefix
637
	 * @param string $subobjectName name of subobject
638
	 * @param boolean $canonical should redirects be resolved?
639
	 * @param string $sortkey call-by-ref will be set to sortkey
640
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
641
	 * @return integer SMW id or 0 if there is none
642 277
	 */
643
	protected function makeDatabaseId( $title, $namespace, $iw, $subobjectName, $canonical, $sortkey, $fetchHashes ) {
644 277
645 277
		$oldsort = '';
646 277
		$id = $this->getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, $oldsort, $canonical, $fetchHashes );
647
		$db = $this->store->getConnection( 'mw.db' );
648 277
649
		$db->beginAtomicTransaction( __METHOD__ );
650 277
651 273
		if ( $id == 0 ) {
652 273
			$sortkey = $sortkey ? $sortkey : ( str_replace( '_', ' ', $title ) );
653
			$sequenceValue = $db->nextSequenceValue( $this->getIdTable() . '_smw_id_seq' ); // Bug 42659
654
655 273
			// #2089 (MySQL 5.7 complained with "Data too long for column")
656
			$sortkey = substr( $sortkey, 0, 254 );
657 273
658 273
			$db->insert(
659
				self::TABLE_NAME,
660 273
				array(
661 273
					'smw_id' => $sequenceValue,
662 273
					'smw_title' => $title,
663 273
					'smw_namespace' => $namespace,
664 273
					'smw_iw' => $iw,
665 273
					'smw_subobject' => $subobjectName,
666
					'smw_sortkey' => $sortkey
667 273
				),
668
				__METHOD__
669
			);
670 273
671
			$id = (int)$db->insertId();
672
673 273
			// Properties also need to be in the property statistics table
674
			if( $namespace === SMW_NS_PROPERTY ) {
675 218
676
				$statsStore = new PropertyStatisticsTable(
677 218
					$db,
678
					SMWSQLStore3::PROPERTY_STATISTICS_TABLE
679
				);
680 218
681
				$statsStore->insertUsageCount( $id, 0 );
682
			}
683 273
684
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
685 273
686 273
			if ( $fetchHashes ) {
687
				$this->setPropertyTableHashesCache( $id, null );
688
			}
689 254
690
		} elseif ( $sortkey !== '' && $sortkey != $oldsort ) {
691
692 54
			// #2089 (MySQL 5.7 complained with "Data too long for column")
693
			$sortkey = substr( $sortkey, 0, 254 );
694 54
695 54
			$db->update(
696 54
				self::TABLE_NAME,
697 54
				array( 'smw_sortkey' => $sortkey ),
698 54
				array( 'smw_id' => $id ),
699
				__METHOD__
700
			);
701 54
702
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
703
		}
704 277
705
		$db->endAtomicTransaction( __METHOD__ );
706 277
707
		return $id;
708
	}
709
710
	/**
711
	 * Properties have a mechanisms for being predefined (i.e. in PHP instead
712
	 * of in wiki). Special "interwiki" prefixes separate the ids of such
713
	 * predefined properties from the ids for the current pages (which may,
714
	 * e.g., be moved, while the predefined object is not movable).
715
	 *
716
	 * @todo This documentation is out of date. Right now, the special
717
	 * interwiki is used only for special properties without a label, i.e.,
718
	 * which cannot be shown to a user. This allows us to filter such cases
719
	 * from all queries that retrieve lists of properties. It should be
720
	 * checked that this is really the only use that this has throughout
721
	 * the code.
722
	 *
723
	 * @since 1.8
724
	 * @param SMWDIProperty $property
725
	 * @return string
726 270
	 */
727 270
	public function getPropertyInterwiki( SMWDIProperty $property ) {
728
		return ( $property->getLabel() !== '' ) ? '' : SMW_SQL3_SMWINTDEFIW;
729
	}
730
731
	/**
732
	 * @since  2.1
733
	 *
734
	 * @param integer $sid
735
	 * @param DIWikiPage $subject
736
	 * @param integer|string|null $interWiki
737 244
	 */
738
	public function updateInterwikiField( $sid, DIWikiPage $subject, $interWiki = null ) {
739 244
740 244
		$this->store->getConnection()->update(
741 244
			self::TABLE_NAME,
742 244
			array( 'smw_iw' => $interWiki !== null ? $interWiki : $subject->getInterWiki() ),
743 244
			array( 'smw_id' => $sid ),
744
			__METHOD__
745
		);
746 244
747 244
		$this->setCache(
748 244
			$subject->getDBKey(),
749 244
			$subject->getNamespace(),
750 244
			$subject->getInterWiki(),
751
			$subject->getSubobjectName(),
752 244
			$sid,
753
			$subject->getSortKey()
754 244
		);
755
	}
756
757
	/**
758
	 * Fetch the ID for an SMWDIProperty object. This method achieves the
759
	 * same as getSMWPageID(), but avoids additional normalization steps
760
	 * that have already been performed when creating an SMWDIProperty
761
	 * object.
762
	 *
763
	 * @note There is no distinction between properties and inverse
764
	 * properties here. A property and its inverse have the same ID in SMW.
765
	 *
766
	 * @param SMWDIProperty $property
767
	 * @return integer
768 272
	 */
769 272
	public function getSMWPropertyID( SMWDIProperty $property ) {
770 271
		if ( array_key_exists( $property->getKey(), self::$special_ids ) ) {
771
			return self::$special_ids[$property->getKey()];
772 270
		} else {
773 270
			$sortkey = '';
774
			return $this->getDatabaseIdAndSort( $property->getKey(), SMW_NS_PROPERTY, $this->getPropertyInterwiki( $property ), '', $sortkey, true, false );
775
		}
776
	}
777
778
	/**
779
	 * Fetch and possibly create the ID for an SMWDIProperty object. The
780
	 * method achieves the same as getSMWPageID() but avoids additional
781
	 * normalization steps that have already been performed when creating
782
	 * an SMWDIProperty object.
783
	 *
784
	 * @see getSMWPropertyID
785
	 * @param SMWDIProperty $property
786
	 * @return integer
787 254
	 */
788 254
	public function makeSMWPropertyID( SMWDIProperty $property ) {
789 224
		if ( array_key_exists( $property->getKey(), self::$special_ids ) ) {
790
			return (int)self::$special_ids[$property->getKey()];
791 225
		} else {
792 225
			return (int)$this->makeDatabaseId(
793 225
				$property->getKey(),
794 225
				SMW_NS_PROPERTY,
795 225
				$this->getPropertyInterwiki( $property ),
796 225
				'',
797 225
				true,
798 225
				$property->getLabel(),
799
				false
800
			);
801
		}
802
	}
803
804
	/**
805
	 * Normalize the information for an SMW object (page etc.) and return
806
	 * the predefined ID if any. All parameters are call-by-reference and
807
	 * will be changed to perform any kind of built-in normalization that
808
	 * SMW requires. This mainly applies to predefined properties that
809
	 * should always use their property key as a title, have fixed
810
	 * sortkeys, etc. Some very special properties also have fixed IDs that
811
	 * do not require any DB lookups. In such cases, the method returns
812
	 * this ID; otherwise it returns 0.
813
	 *
814
	 * @note This function could be extended to account for further kinds
815
	 * of normalization and predefined ID. However, both getSMWPropertyID
816
	 * and makeSMWPropertyID must then also be adjusted to do the same.
817
	 *
818
	 * @since 1.8
819
	 * @param string $title DB key
820
	 * @param integer $namespace namespace
821
	 * @param string $iw interwiki prefix
822
	 * @param string $subobjectName
823
	 * @param string $sortkey
824
	 * @return integer predefined id or 0 if none
825 300
	 */
826 300
	protected function getPredefinedData( &$title, &$namespace, &$iw, &$subobjectName, &$sortkey ) {
827 300
		if ( $namespace == SMW_NS_PROPERTY &&
828
			( $iw === '' || $iw == SMW_SQL3_SMWINTDEFIW ) && $title != '' ) {
829
830 234
			// Check if this is a predefined property:
831
			if ( $title{0} != '_' ) {
832
				// This normalization also applies to
833 234
				// subobjects of predefined properties.
834 234
				$newTitle = SMW\DIProperty::findPropertyID( str_replace( '_', ' ', $title ) );
0 ignored issues
show
Deprecated Code introduced by
The method SMW\DIProperty::findPropertyID() has been deprecated with message: since 2.1, use PropertyRegistry::findPropertyIdByLabel

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
835 60
				if ( $newTitle ) {
836 60
					$title = $newTitle;
837 60
					$sortkey = SMW\DIProperty::findPropertyLabel( $title );
0 ignored issues
show
Deprecated Code introduced by
The method SMW\DIProperty::findPropertyLabel() has been deprecated with message: since 2.1, use PropertyRegistry::findPropertyLabelById

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
838
					if ( $sortkey === '' ) {
839
						$iw = SMW_SQL3_SMWINTDEFIW;
840
					}
841
				}
842
			}
843
844 234
			// Check if this is a property with a fixed SMW ID:
845 52
			if ( $subobjectName === '' && array_key_exists( $title, self::$special_ids ) ) {
846
				return self::$special_ids[$title];
847
			}
848
		}
849 298
850
		return 0;
851
	}
852
853
	/**
854
	 * Change an internal id to another value. If no target value is given, the
855
	 * value is changed to become the last id entry (based on the automatic id
856
	 * increment of the database). Whatever currently occupies this id will be
857
	 * moved consistently in all relevant tables. Whatever currently occupies
858
	 * the target id will be ignored (it should be ensured that nothing is
859
	 * moved to an id that is still in use somewhere).
860
	 *
861
	 * @since 1.8
862
	 * @param integer $curid
863
	 * @param integer $targetid
864 1
	 */
865 1
	public function moveSMWPageID( $curid, $targetid = 0 ) {
866
		$db = $this->store->getConnection();
867 1
868 1
		$row = $db->selectRow(
869 1
			self::TABLE_NAME,
870 1
			'*',
871 1
			array( 'smw_id' => $curid ),
872
			__METHOD__
873
		);
874 1
875 1
		if ( $row === false ) {
876
			return; // no id at current position, ignore
877
		}
878
879
		$db->beginAtomicTransaction( __METHOD__ );
880
881
		if ( $targetid == 0 ) { // append new id
882
			$sequenceValue = $db->nextSequenceValue( $this->getIdTable() . '_smw_id_seq' ); // Bug 42659
883
884
			$db->insert(
885
				self::TABLE_NAME,
886
				array(
887
					'smw_id' => $sequenceValue,
888
					'smw_title' => $row->smw_title,
889
					'smw_namespace' => $row->smw_namespace,
890
					'smw_iw' => $row->smw_iw,
891
					'smw_subobject' => $row->smw_subobject,
892
					'smw_sortkey' => $row->smw_sortkey
893
				),
894
				__METHOD__
895
			);
896
897
			$targetid = $db->insertId();
898
		} else { // change to given id
899
			$db->insert(
900
				self::TABLE_NAME,
901
				array( 'smw_id' => $targetid,
902
					'smw_title' => $row->smw_title,
903
					'smw_namespace' => $row->smw_namespace,
904
					'smw_iw' => $row->smw_iw,
905
					'smw_subobject' => $row->smw_subobject,
906
					'smw_sortkey' => $row->smw_sortkey
907
				),
908
				__METHOD__
909
			);
910
		}
911
912
		$db->delete(
913
			self::TABLE_NAME,
914
			array(
915
				'smw_id' => $curid
916
			),
917
			__METHOD__
918
		);
919
920
		$this->setCache(
921
			$row->smw_title,
922
			$row->smw_namespace,
923
			$row->smw_iw,
924
			$row->smw_subobject,
925
			$targetid,
926
			$row->smw_sortkey
927
		);
928
929
		$this->store->changeSMWPageID(
930
			$curid,
931
			$targetid,
932
			$row->smw_namespace,
933
			$row->smw_namespace
934
		);
935
936
		$db->endAtomicTransaction( __METHOD__ );
937
	}
938
939
	/**
940
	 * Add or modify a cache entry. The key consists of the
941
	 * parameters $title, $namespace, $interwiki, and $subobject. The
942
	 * cached data is $id and $sortkey.
943
	 *
944
	 * @since 1.8
945
	 * @param string $title
946
	 * @param integer $namespace
947
	 * @param string $interwiki
948
	 * @param string $subobject
949
	 * @param integer $id
950
	 * @param string $sortkey
951 300
	 */
952
	public function setCache( $title, $namespace, $interwiki, $subobject, $id, $sortkey ) {
953 300
954
		if ( strpos( $title, ' ' ) !== false ) {
955
			throw new RuntimeException( "Somebody tried to use spaces in a cache title! ($title)");
956
		}
957 300
958
		$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
959 300
960 278
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
961 278
			$this->checkPropertySizeLimit();
962 278
			$this->prop_ids[$title] = $id;
963
			$this->prop_sortkeys[$title] = $sortkey;
964 287
		} else {
965 287
			$this->checkRegularSizeLimit();
966 287
			$this->regular_ids[$hashKey] = $id;
967
			$this->regular_sortkeys[$hashKey] = $sortkey;
968
		}
969 300
970 300
		$this->idToDataItemMatchFinder->saveToCache( $id, $hashKey );
971
		$this->intermediaryIdCache->save( $hashKey, $id );
972 300
973 265
		if ( $interwiki == SMW_SQL3_SMWREDIIW ) { // speed up detection of redirects when fetching IDs
974
			$this->setCache(  $title, $namespace, '', $subobject, 0, '' );
975 300
		}
976
	}
977
978
	/**
979
	 * @since 2.1
980
	 *
981
	 * @param integer $id
982
	 *
983
	 * @return DIWikiPage|null
984 270
	 */
985 270
	public function getDataItemById( $id ) {
986
		return $this->idToDataItemMatchFinder->getDataItemById( $id );
987
	}
988
989
	/**
990
	 * @since 2.3
991
	 *
992
	 * @param integer $id
0 ignored issues
show
Bug introduced by
There is no parameter named $id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
993
	 * @param RequestOptions|null $requestOptions
994
	 *
995 79
	 * @return string[]
996 79
	 */
997
	public function getDataItemPoolHashListFor( array $idlist, RequestOptions $requestOptions = null ) {
998
		return $this->idToDataItemMatchFinder->getDataItemsFromList( $idlist, $requestOptions );
999
	}
1000
1001
	/**
1002
	 * Get a cached SMW ID, or false if no cache entry is found.
1003
	 *
1004
	 * @since 1.8
1005
	 * @param string $title
1006
	 * @param integer $namespace
1007
	 * @param string $interwiki
1008
	 * @param string $subobject
1009 299
	 * @return integer|boolean
1010 299
	 */
1011 282
	protected function getCachedId( $title, $namespace, $interwiki, $subobject ) {
1012 261
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1013 261
			if ( array_key_exists( $title, $this->prop_ids ) ) {
1014
				$this->prophit_debug++;
1015 278
				return (int)$this->prop_ids[$title];
1016 278
			} else {
1017
				$this->propmiss_debug++;
1018
				return false;
1019 286
			}
1020 286
		} else {
1021 267
			$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1022 267
			if ( array_key_exists( $hashKey, $this->regular_ids ) ) {
1023
				$this->reghit_debug++;
1024 286
				return (int)$this->regular_ids[$hashKey];
1025 286
			} else {
1026
				$this->regmiss_debug++;
1027
				return false;
1028
			}
1029
		}
1030
	}
1031
1032
	/**
1033
	 * Get a cached SMW sortkey, or false if no cache entry is found.
1034
	 *
1035
	 * @since 1.8
1036
	 * @param string $title
1037
	 * @param integer $namespace
1038
	 * @param string $interwiki
1039
	 * @param string $subobject
1040 288
	 * @return string|boolean
1041 288
	 */
1042 261
	protected function getCachedSortKey( $title, $namespace, $interwiki, $subobject ) {
1043 261
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1044
			if ( array_key_exists( $title, $this->prop_sortkeys ) ) {
1045
				return $this->prop_sortkeys[$title];
1046
			} else {
1047
				return false;
1048 288
			}
1049 288
		} else {
1050 269
			$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1051
			if ( array_key_exists( $hashKey, $this->regular_sortkeys ) ) {
1052 288
				return $this->regular_sortkeys[$hashKey];
1053
			} else {
1054
				return false;
1055
			}
1056
		}
1057
	}
1058
1059
	/**
1060
	 * Remove any cache entry for the given data. The key consists of the
1061
	 * parameters $title, $namespace, $interwiki, and $subobject. The
1062
	 * cached data is $id and $sortkey.
1063
	 *
1064
	 * @since 1.8
1065
	 * @param string $title
1066
	 * @param integer $namespace
1067
	 * @param string $interwiki
1068 9
	 * @param string $subobject
1069
	 */
1070 9
	public function deleteCache( $title, $namespace, $interwiki, $subobject ) {
1071
1072 9
		$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1073 1
1074 1
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1075 1
			$id =  isset( $this->prop_ids[$title] ) ?  $this->prop_ids[$title] : 0;
1076
			unset( $this->prop_ids[$title] );
1077 9
			unset( $this->prop_sortkeys[$title] );
1078 9
		} else {
1079 9
			$id = isset( $this->regular_ids[$hashKey] ) ? $this->regular_ids[$hashKey] : 0;
1080
			unset( $this->regular_ids[$hashKey] );
1081
			unset( $this->regular_sortkeys[$hashKey] );
1082 9
		}
1083 9
1084 9
		$this->intermediaryIdCache->delete( $hashKey );
1085
		$this->idToDataItemMatchFinder->deleteFromCache( $id );
1086
	}
1087
1088
	/**
1089
	 * Move all cached information about subobjects.
1090
	 *
1091
	 * @todo This method is neither efficient nor very convincing
1092
	 * architecturally; it should be redesigned.
1093
	 *
1094
	 * @since 1.8
1095
	 * @param string $oldtitle
1096
	 * @param integer $oldnamespace
1097
	 * @param string $newtitle
1098 22
	 * @param integer $newnamespace
1099
	 */
1100
	public function moveSubobjects( $oldtitle, $oldnamespace, $newtitle, $newnamespace ) {
0 ignored issues
show
Unused Code introduced by
The parameter $oldtitle is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $newtitle is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1101 22
		// Currently we have no way to change title and namespace across all entries.
1102 7
		// Best we can do is clear the cache to avoid wrong hits:
1103 7
		if ( $oldnamespace == SMW_NS_PROPERTY || $newnamespace == SMW_NS_PROPERTY ) {
1104
			$this->prop_ids = array();
1105 22
			$this->prop_sortkeys = array();
1106 16
		}
1107 16
		if ( $oldnamespace != SMW_NS_PROPERTY || $newnamespace != SMW_NS_PROPERTY ) {
1108
			$this->regular_ids = array();
1109 22
			$this->regular_sortkeys = array();
1110
		}
1111
	}
1112
1113
	/**
1114
	 * Delete all cached information.
1115
	 *
1116 26
	 * @since 1.8
1117 26
	 */
1118 26
	public function clearCaches() {
1119 26
		$this->prop_ids = array();
1120 26
		$this->prop_sortkeys = array();
1121 26
		$this->regular_ids = array();
1122 26
		$this->regular_sortkeys = array();
1123
		$this->idToDataItemMatchFinder->clear();
1124
	}
1125
1126
	/**
1127
	 * Ensure that the property ID and sortkey caches have space to insert
1128
	 * at least one more element. If not, some other entries will be unset.
1129
	 *
1130 278
	 * @since 1.8
1131 278
	 */
1132
	protected function checkPropertySizeLimit() {
1133
		if ( count( $this->prop_ids ) >= self::$PROP_CACHE_MAX_SIZE ) {
1134
			$keys = array_rand( $this->prop_ids, 10 );
1135
			foreach ( $keys as $key ) {
1136
				unset( $this->prop_ids[$key] );
1137
				unset( $this->prop_sortkeys[$key] );
1138 278
			}
1139
		}
1140
	}
1141
1142
	/**
1143
	 * Ensure that the non-property ID and sortkey caches have space to
1144
	 * insert at least one more element. If not, some other entries will be
1145
	 * unset.
1146
	 *
1147 287
	 * @since 1.8
1148 287
	 */
1149
	protected function checkRegularSizeLimit() {
1150
		if ( count( $this->regular_ids ) >= self::$PAGE_CACHE_MAX_SIZE ) {
1151
			$keys = array_rand( $this->regular_ids, 10 );
1152
			foreach ( $keys as $key ) {
1153
				unset( $this->regular_ids[$key] );
1154
				unset( $this->regular_sortkeys[$key] );
1155 287
			}
1156
		}
1157
	}
1158
1159
	/**
1160
	 * Return an array of hashes with table names as keys. These
1161
	 * hashes are used to compare new data with old data for each
1162
	 * property-value table when updating data
1163
	 *
1164
	 * @since 1.8
1165
	 *
1166
	 * @param integer $subjectId ID of the page as stored in the SMW IDs table
1167
	 *
1168 269
	 * @return array
1169 269
	 */
1170 269
	public function getPropertyTableHashes( $subjectId ) {
0 ignored issues
show
Coding Style introduced by
getPropertyTableHashes uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1171
		$hash = null;
1172 269
		$db = $this->store->getConnection();
1173 269
1174 229
		if ( $this->hashCacheId == $subjectId ) {
1175
			$hash = $this->hashCacheContents;
1176 229
		} elseif ( $subjectId !== 0 ) {
1177 229
1178 229
			$row = $db->selectRow(
1179 229
				self::TABLE_NAME,
1180 229
				array( 'smw_proptable_hash' ),
1181
				'smw_id=' . $subjectId,
1182
				__METHOD__
1183 229
			);
1184 229
1185
			if ( $row !== false ) {
1186
				$hash = $row->smw_proptable_hash;
1187
			}
1188 269
		}
1189
1190
		if ( $hash !== null && $GLOBALS['wgDBtype'] == 'postgres' ) {
1191
			$hash = pg_unescape_bytea( $hash );
1192 269
		}
1193
1194
		return is_null( $hash ) ? array() : unserialize( $hash );
1195
	}
1196
1197
	/**
1198
	 * Update the proptable_hash for a given page.
1199
	 *
1200
	 * @since 1.8
1201
	 * @param integer $sid ID of the page as stored in SMW IDs table
1202 254
	 * @param string[] of hash values with table names as keys
1203 254
	 */
1204 254
	public function setPropertyTableHashes( $sid, array $newTableHashes ) {
1205
		$db = $this->store->getConnection();
1206 254
		$propertyTableHash = serialize( $newTableHashes );
1207 254
1208 254
		$db->update(
1209 254
			self::TABLE_NAME,
1210 254
			array( 'smw_proptable_hash' => $propertyTableHash ),
1211
			array( 'smw_id' => $sid ),
1212
			__METHOD__
1213 254
		);
1214 254
1215
		if ( $sid == $this->hashCacheId ) {
1216 254
			$this->setPropertyTableHashesCache( $sid, $propertyTableHash );
1217
		}
1218
	}
1219
1220
	/**
1221
	 * Temporarily cache a property tablehash that has been retrieved for
1222
	 * the given SMW ID.
1223
	 *
1224
	 * @since 1.8
1225
	 * @param $id integer
1226 273
	 * @param $propertyTableHash string
1227 273
	 */
1228 2
	protected function setPropertyTableHashesCache( $id, $propertyTableHash ) {
1229
		if ( $id == 0 ) {
1230
			return; // never cache 0
1231 273
		}
1232 273
		//print "Cache set for $id.\n";
1233 273
		$this->hashCacheId = $id;
1234
		$this->hashCacheContents = $propertyTableHash;
1235
	}
1236
1237
	/**
1238
	 * Simple helper method for debugging cache performance. Prints
1239
	 * statistics about the SMWSql3SmwIds object created last.
1240
	 * The following code can be used in LocalSettings.php to enable
1241
	 * this in a wiki:
1242
	 *
1243
	 * $wgHooks['SkinAfterContent'][] = 'showCacheStats';
1244
	 * function showCacheStats() {
1245
	 *   self::debugDumpCacheStats();
1246
	 *   return true;
1247
	 * }
1248
	 *
1249
	 * @note This is a debugging/profiling method that no published code
1250
	 * should rely on.
1251
	 *
1252
	 * @since 1.8
1253
	 */
1254
	public static function debugDumpCacheStats() {
1255
		$that = self::$singleton_debug;
1256
		if ( is_null( $that ) ) {
1257
			return;
1258
		}
1259
1260
		$debugString =
1261
			"Statistics for SMWSql3SmwIds:\n" .
1262
			"- Executed {$that->selectrow_sort_debug} selects for sortkeys.\n" .
1263
			"- Executed {$that->selectrow_redi_debug} selects for redirects.\n" .
1264
			"- Regular cache hits: {$that->reghit_debug} misses: {$that->regmiss_debug}";
1265
		if ( $that->regmiss_debug + $that->reghit_debug > 0 ) {
1266
			$debugString .= " rate: " . round( $that->reghit_debug/( $that->regmiss_debug + $that->reghit_debug ), 3 );
1267
		}
1268
		$debugString .= " cache size: " . count( $that->regular_ids ) . "\n";
1269
		$debugString .= "- Property cache hits: {$that->prophit_debug} misses: {$that->propmiss_debug}";
1270
		if ( $that->propmiss_debug + $that->prophit_debug > 0 ) {
1271
			$debugString .= " rate: " . round( $that->prophit_debug/( $that->propmiss_debug + $that->prophit_debug ), 3 );
1272
		}
1273
		$debugString .= " cache size: " . count( $that->prop_ids ) . "\n";
1274
		wfDebug( $debugString );
1275
	}
1276
1277
	/**
1278
	 * Returns store Id table name
1279
	 *
1280 274
	 * @return string
1281 274
	 */
1282
	public function getIdTable() {
1283
		return self::TABLE_NAME;
1284
	}
1285
1286
}
1287