Completed
Push — master ( b931d6...c92449 )
by mw
259:40 queued 224:38
created

SMWSql3SmwIds::exists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\DIProperty;
5
use SMW\DIWikiPage;
6
use SMW\HashBuilder;
7
use SMW\SQLStore\IdToDataItemMatchFinder;
8
use SMW\SQLStore\PropertyStatisticsTable;
9
use SMW\SQLStore\RedirectInfoStore;
10
11
/**
12
 * @ingroup SMWStore
13
 * @since 1.8
14
 * @author Markus Krötzsch
15
 */
16
17
/**
18
 * Class to access the SMW IDs table in SQLStore3.
19
 * Provides transparent in-memory caching facilities.
20
 *
21
 * Documentation for the SMW IDs table: This table is a dictionary that
22
 * assigns integer IDs to pages, properties, and other objects used by SMW.
23
 * All tables that refer to such objects store these IDs instead. If the ID
24
 * information is lost (e.g., table gets deleted), then the data stored in SMW
25
 * is no longer meaningful: all tables need to be dropped, recreated, and
26
 * refreshed to get back to a working database.
27
 *
28
 * The table has a column for storing interwiki prefixes, used to refer to
29
 * pages on external sites (like in MediaWiki). This column is also used to
30
 * mark some special objects in the table, using "interwiki prefixes" that
31
 * cannot occur in MediaWiki:
32
 *
33
 * - Rows with iw SMW_SQL3_SMWREDIIW are similar to normal entries for
34
 * (internal) wiki pages, but the iw indicates that the page is a redirect, the
35
 * (target of which should be sought using the smw_fpt_redi table.
36
 *
37
 * - The (unique) row with iw SMW_SQL3_SMWBORDERIW just marks the border
38
 * between predefined ids (rows that are reserved for hardcoded ids built into
39
 * SMW) and normal entries. It is no object, but makes sure that SQL's auto
40
 * increment counter is high enough to not add any objects before that marked
41
 * "border".
42
 *
43
 * @note Do not call the constructor of SMWDIWikiPage using data from the SMW
44
 * IDs table; use SMWDIHandlerWikiPage::dataItemFromDBKeys() instead. The table
45
 * does not always contain data as required wiki pages. Especially predefined
46
 * properties are represented by language-independent keys rather than proper
47
 * titles. SMWDIHandlerWikiPage takes care of this.
48
 *
49
 * @since 1.8
50
 *
51
 * @ingroup SMWStore
52
 */
53
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...
54
55
	/**
56
	 * Specifies the border limit for pre-defined properties declared
57
	 * in SMWSql3SmwIds::special_ids
58
	 */
59
	const FXD_PROP_BORDER_ID = SMWSQLStore3::FIXED_PROPERTY_ID_UPPERBOUND;
60
61
	/**
62
	 * Name of the table to store IDs in.
63
	 *
64
	 * @note This should never change. Existing wikis will have to drop and
65
	 * rebuild their SMW tables completely to recover from any change here.
66
	 */
67
	const TABLE_NAME = SMWSQLStore3::ID_TABLE;
68
69
	const POOLCACHE_ID = 'sql.store.id.cache';
70
71
	/**
72
	 * Id for which property table hashes are cached, if any.
73
	 *
74
	 * @since 1.8
75
	 * @var integer
76
	 */
77
	protected $hashCacheId = 0;
78
79
	/**
80
	 * Cached property table hashes for $hashCacheId.
81
	 *
82
	 * @since 1.8
83
	 * @var string
84
	 */
85
	protected $hashCacheContents = '';
86
87
	/**
88
	 * Maximal number of cached property IDs.
89
	 *
90
	 * @since 1.8
91
	 * @var integer
92
	 */
93
	public static $PROP_CACHE_MAX_SIZE = 250;
94
95
	/**
96
	 * Maximal number of cached non-property IDs.
97
	 *
98
	 * @since 1.8
99
	 * @var integer
100
	 */
101
	public static $PAGE_CACHE_MAX_SIZE = 500;
102
103
	protected $selectrow_sort_debug = 0;
104
	protected $selectrow_redi_debug = 0;
105
	protected $prophit_debug = 0;
106
	protected $propmiss_debug = 0;
107
	protected $reghit_debug = 0;
108
	protected $regmiss_debug = 0;
109
110
	static protected $singleton_debug = null;
111
112
	/**
113
	 * Parent SMWSQLStore3.
114
	 *
115
	 * @since 1.8
116
	 * @var SMWSQLStore3
117
	 */
118
	public $store;
119
120
	/**
121
	 * Cache for property IDs.
122
	 *
123
	 * @note Tests indicate that it is more memory efficient to have two
124
	 * arrays (IDs and sortkeys) than to have one array that stores both
125
	 * values in some data structure (other than a single string).
126
	 *
127
	 * @since 1.8
128
	 * @var array
129
	 */
130
	protected $prop_ids = array();
131
132
	/**
133
	 * @var IdToDataItemMatchFinder
134
	 */
135
	private $idToDataItemMatchFinder;
136
137
	/**
138
	 * @var RedirectInfoStore
139
	 */
140
	private $redirectInfoStore;
141
142
	/**
143
	 * Cache for property sortkeys.
144
	 *
145
	 * @since 1.8
146
	 * @var array
147
	 */
148
	protected $prop_sortkeys = array();
149
150
	/**
151
	 * Cache for non-property IDs.
152
	 *
153
	 * @since 1.8
154
	 * @var array
155
	 */
156
	protected $regular_ids = array();
157
158
	/**
159
	 * Cache for non-property sortkeys.
160
	 *
161
	 * @since 1.8
162
	 * @var array
163
	 */
164
	protected $regular_sortkeys = array();
165
166
	/**
167
	 * Use pre-defined ids for Very Important Properties, avoiding frequent
168
	 * ID lookups for those.
169
	 *
170
	 * @note These constants also occur in the store. Changing them will
171
	 * require to run setup.php again. They can also not be larger than 50.
172
	 *
173
	 * @since 1.8
174
	 * @var array
175
	 */
176
	public static $special_ids = array(
177
		'_TYPE' => 1,
178
		'_URI'  => 2,
179
		'_INST' => 4,
180
		'_UNIT' => 7,
181
		'_IMPO' => 8,
182
		'_PPLB' => 9,
183
		'_PDESC' => 10,
184
		'_PREC' => 11,
185
		'_CONV' => 12,
186
		'_SERV' => 13,
187
		'_PVAL' => 14,
188
		'_REDI' => 15,
189
		'_DTITLE' => 16,
190
		'_SUBP' => 17,
191
		'_SUBC' => 18,
192
		'_CONC' => 19,
193
//		'_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...
194
//		'_SF_AF' => 21,  // Semantic Form's alternate form property
195
		'_ERRP' => 22,
196
// 		'_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...
197
// 		'_2' => 24,
198
// 		'_3' => 25,
199
// 		'_4' => 26,
200
// 		'_5' => 27,
201
// 		'_SOBJ' => 27
202
		'_LIST' => 28,
203
		'_MDAT' => 29,
204
		'_CDAT' => 30,
205
		'_NEWP' => 31,
206
		'_LEDT' => 32,
207
		// properties related to query management
208
		'_ASK'   =>  33,
209
		'_ASKST' =>  34,
210
		'_ASKFO' =>  35,
211
		'_ASKSI' =>  36,
212
		'_ASKDE' =>  37,
213
//		'_ASKDU' =>  38,
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
214
		'_ASKSC' =>  39,
215
		'_LCODE' =>  40,
216
		'_TEXT'  =>  41,
217
	);
218
219
	/**
220
	 * Constructor.
221
	 *
222
	 * @since 1.8
223
	 * @param SMWSQLStore3 $store
224
	 */
225 30
	public function __construct( SMWSQLStore3 $store, IdToDataItemMatchFinder $idToDataItemMatchFinder ) {
226 30
		$this->store = $store;
227
		// Yes, this is a hack, but we only use it for convenient debugging:
228 30
		self::$singleton_debug = $this;
229
230 30
		$this->idToDataItemMatchFinder = $idToDataItemMatchFinder;
231
232 30
		$this->redirectInfoStore = new RedirectInfoStore(
233 30
			$this->store->getConnection( 'mw.db' )
234
		);
235
236 30
		$this->intermediaryIdCache = ApplicationFactory::getInstance()->getInMemoryPoolCache()->getPoolCacheFor( 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...
237 30
	}
238
239
	/**
240
	 * @since  2.1
241
	 *
242
	 * @param DIWikiPage $subject
243
	 *
244
	 * @return boolean
245
	 */
246 145
	public function checkIsRedirect( DIWikiPage $subject ) {
247
248 145
		$redirectId = $this->findRedirectIdFor(
249 145
			$subject->getDBKey(),
250 145
			$subject->getNamespace()
251
		);
252
253 145
		return $redirectId != 0;
254
	}
255
256
	/**
257
	 * @see RedirectInfoStore::findRedirectIdFor
258
	 *
259
	 * @since 2.1
260
	 *
261
	 * @param string $title DB key
262
	 * @param integer $namespace
263
	 *
264
	 * @return integer
265
	 */
266 289
	public function findRedirectIdFor( $title, $namespace ) {
267 289
		return $this->redirectInfoStore->findRedirectIdFor( $title, $namespace );
268
	}
269
270
	/**
271
	 * @see RedirectInfoStore::addRedirectForId
272
	 *
273
	 * @since 2.1
274
	 *
275
	 * @param integer $id
276
	 * @param string $title
277
	 * @param integer $namespace
278
	 */
279 26
	public function addRedirectForId( $id, $title, $namespace ) {
280 26
		$this->redirectInfoStore->addRedirectForId( $id, $title, $namespace );
281 26
	}
282
283
	/**
284
	 * @see RedirectInfoStore::deleteRedirectEntry
285
	 *
286
	 * @since 2.1
287
	 *
288
	 * @param string $title
289
	 * @param integer $namespace
290
	 */
291 25
	public function deleteRedirectEntry( $title, $namespace ) {
292 25
		$this->redirectInfoStore->deleteRedirectEntry( $title, $namespace );
293 25
	}
294
295
	/**
296
	 * Find the numeric ID used for the page of the given title,
297
	 * namespace, interwiki, and subobject. If $canonical is set to true,
298
	 * redirects are taken into account to find the canonical alias ID for
299
	 * the given page. If no such ID exists, 0 is returned. The Call-By-Ref
300
	 * parameter $sortkey is set to the current sortkey, or to '' if no ID
301
	 * exists.
302
	 *
303
	 * If $fetchhashes is true, the property table hash blob will be
304
	 * retrieved in passing if the opportunity arises, and cached
305
	 * internally. This will speed up a subsequent call to
306
	 * getPropertyTableHashes() for this id. This should only be done
307
	 * if such a call is intended, both to safe the previous cache and
308
	 * to avoid extra work (even if only a little) to fill it.
309
	 *
310
	 * @since 1.8
311
	 * @param string $title DB key
312
	 * @param integer $namespace namespace
313
	 * @param string $iw interwiki prefix
314
	 * @param string $subobjectName name of subobject
315
	 * @param string $sortkey call-by-ref will be set to sortkey
316
	 * @param boolean $canonical should redirects be resolved?
317
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
318
	 * @return integer SMW id or 0 if there is none
319
	 */
320 298
	public function getSMWPageIDandSort( $title, $namespace, $iw, $subobjectName, &$sortkey, $canonical, $fetchHashes = false ) {
321 298
		$id = $this->getPredefinedData( $title, $namespace, $iw, $subobjectName, $sortkey );
322 298
		if ( $id != 0 ) {
323 47
			return (int)$id;
324
		} else {
325 296
			return (int)$this->getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, $sortkey, $canonical, $fetchHashes );
326
		}
327
	}
328
329
	/**
330
	 * Find the numeric ID used for the page of the given normalized title,
331
	 * namespace, interwiki, and subobjectName. Predefined IDs are not
332
	 * taken into account (however, they would still be found correctly by
333
	 * an avoidable database read if they are stored correctly in the
334
	 * database; this should always be the case). In all other aspects, the
335
	 * method works just like getSMWPageIDandSort().
336
	 *
337
	 * @since 1.8
338
	 * @param string $title DB key
339
	 * @param integer $namespace namespace
340
	 * @param string $iw interwiki prefix
341
	 * @param string $subobjectName name of subobject
342
	 * @param string $sortkey call-by-ref will be set to sortkey
343
	 * @param boolean $canonical should redirects be resolved?
344
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
345
	 * @return integer SMW id or 0 if there is none
346
	 */
347 299
	protected function getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, &$sortkey, $canonical, $fetchHashes ) {
348 299
		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...
349
350 299
		$db = $this->store->getConnection();
351
352
		// Integration test "query-04-02-subproperty-dc-import-marc21.json"
353
		// showed a deterministic failure (due to a wrong cache id during querying
354
		// for redirects) hence we force to read directly from the RedirectInfoStore
355
		// for objects marked as redirect
356 299
		if ( $iw === SMW_SQL3_SMWREDIIW && $canonical &&
357 299
			$smwgQEqualitySupport !== SMW_EQ_NONE && $subobjectName === '' ) {
358 288
			$id = $this->findRedirectIdFor( $title, $namespace );
359
		} else {
360 299
			$id = $this->getCachedId(
361
				$title,
362
				$namespace,
363
				$iw,
364
				$subobjectName
365
			);
366
		}
367
368 299
		if ( $id !== false ) { // cache hit
369 288
			$sortkey = $this->getCachedSortKey( $title, $namespace, $iw, $subobjectName );
370 299
		} elseif ( $iw == SMW_SQL3_SMWREDIIW && $canonical &&
371 299
			$smwgQEqualitySupport != SMW_EQ_NONE && $subobjectName === '' ) {
372
			$id = $this->findRedirectIdFor( $title, $namespace );
373
			if ( $id != 0 ) {
374
375
				if ( $fetchHashes ) {
376
					$select = array( 'smw_sortkey', 'smw_proptable_hash' );
377
				} else {
378
					$select = array( 'smw_sortkey' );
379
				}
380
381
				$row = $db->selectRow(
382
					self::TABLE_NAME,
383
					$select,
384
					array( 'smw_id' => $id ),
385
					__METHOD__
386
				);
387
388
				if ( $row !== false ) {
389
					$sortkey = $row->smw_sortkey;
390
					if ( $fetchHashes ) {
391
						$this->setPropertyTableHashesCache( $id, $row->smw_proptable_hash );
392
					}
393
				} else { // inconsistent DB; just recover somehow
394
					$sortkey = str_replace( '_', ' ', $title );
395
				}
396
			} else {
397
				$sortkey = '';
398
			}
399
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
400
		} else {
401
402 299
			if ( $fetchHashes ) {
403 264
				$select = array( 'smw_id', 'smw_sortkey', 'smw_proptable_hash' );
404
			} else {
405 292
				$select = array( 'smw_id', 'smw_sortkey' );
406
			}
407
408 299
			$row = $db->selectRow(
409 299
				self::TABLE_NAME,
410
				$select,
411
				array(
412 299
					'smw_title' => $title,
413 299
					'smw_namespace' => $namespace,
414 299
					'smw_iw' => $iw,
415 299
					'smw_subobject' => $subobjectName
416
				),
417 299
				__METHOD__
418
			);
419
420 299
			$this->selectrow_sort_debug++;
421
422 299
			if ( $row !== false ) {
423 250
				$id = $row->smw_id;
424 250
				$sortkey = $row->smw_sortkey;
425 250
				if ( $fetchHashes ) {
426 250
					$this->setPropertyTableHashesCache( $id, $row->smw_proptable_hash);
427
				}
428
			} else {
429 282
				$id = 0;
430 282
				$sortkey = '';
431
			}
432
433 299
			$this->setCache(
434
				$title,
435
				$namespace,
436
				$iw,
437
				$subobjectName,
438
				$id,
439
				$sortkey
440
			);
441
		}
442
443 299
		if ( $id == 0 && $subobjectName === '' && $iw === '' ) { // could be a redirect; check
444 288
			$id = $this->getSMWPageIDandSort(
445
				$title,
446
				$namespace,
447 288
				SMW_SQL3_SMWREDIIW,
448
				$subobjectName,
449
				$sortkey,
450
				$canonical,
451
				$fetchHashes
452
			);
453
		}
454
455 299
		return $id;
456
	}
457
458
	/**
459
	 * @since 2.3
460
	 *
461
	 * @param string $title DB key
462
	 * @param integer $namespace namespace
463
	 * @param string $iw interwiki prefix
464
	 * @param string $subobjectName name of subobject
465
	 *
466
	 * @param array
467
	 */
468 249
	public function getListOfIdMatchesFor( $title, $namespace, $iw, $subobjectName = '' ) {
469
470 249
		$matches = array();
471
472 249
		$rows = $this->store->getConnection( 'mw.db' )->select(
473 249
			self::TABLE_NAME,
474 249
			$select = array( 'smw_id' ),
475
			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...
476 249
				'smw_title' => $title,
477 249
				'smw_namespace' => $namespace,
478 249
				'smw_iw' => $iw,
479 249
				'smw_subobject' => $subobjectName
480
			),
481 249
			__METHOD__
482
		);
483
484 249
		if ( $rows === false ) {
485
			return $matches;
486
		}
487
488 249
		foreach ( $rows as $row ) {
489 242
			$matches[] = $row->smw_id;
490
		}
491
492 249
		return $matches;
493
	}
494
495
	/**
496
	 * @since 2.4
497
	 *
498
	 * @param DIWikiPage $subject
499
	 *
500
	 * @param boolean
501
	 */
502 39
	public function exists( DIWikiPage $subject ) {
503 39
		return $this->getIDFor( $subject ) > 0;
504
	}
505
506
	/**
507
	 * @note SMWSql3SmwIds::getSMWPageID has some issues with the cache as it returned
508
	 * 0 even though an object was matchable, using this method is safer then trying
509
	 * to encipher getSMWPageID related methods.
510
	 *
511
	 * It uses the PoolCache which means Lru is in place to avoid memory leakage.
512
	 *
513
	 * @since 2.4
514
	 *
515
	 * @param DIWikiPage $subject
516
	 *
517
	 * @param integer
518
	 */
519 102
	public function getIDFor( DIWikiPage $subject ) {
520
521
		// Try to match a predefined property
522 102
		if ( $subject->getNamespace() === SMW_NS_PROPERTY && $subject->getInterWiki() === '' ) {
523 77
			$property = DIProperty::newFromUserLabel( $subject->getDBKey() );
524 77
			$key = $property->getKey();
525
526
			// Has a fixed ID?
527 77
			if ( isset( self::$special_ids[$key] ) ) {
528 8
				return self::$special_ids[$key];
529
			}
530
531
			// Switch title for fixed properties without a fixed ID (e.g. _MIME is the smw_title)
532 77
			if ( !$property->isUserDefined() ) {
533 3
				$subject = new DIWikiPage( $key, SMW_NS_PROPERTY );
534
			}
535
		}
536
537 102
		$hash = HashBuilder::getHashIdForDiWikiPage( $subject );
538
539 102
		if ( ( $id = $this->intermediaryIdCache->fetch( $hash ) ) !== false ) {
540 88
			return $id;
541
		}
542
543 94
		$id = 0;
544
545 94
		$row = $this->store->getConnection( 'mw.db' )->selectRow(
546 94
			self::TABLE_NAME,
547 94
			array( 'smw_id' ),
548
			array(
549 94
				'smw_title' => $subject->getDBKey(),
550 94
				'smw_namespace' => $subject->getNamespace(),
551 94
				'smw_iw' => $subject->getInterWiki(),
552 94
				'smw_subobject' => $subject->getSubobjectName()
553
			),
554 94
			__METHOD__
555
		);
556
557 94
		if ( $row !== false ) {
558 2
			$id = $row->smw_id;
559
		}
560
561
		// Legacy
562 94
		$this->setCache(
563 94
			$subject->getDBKey(),
564 94
			$subject->getNamespace(),
565 94
			$subject->getInterWiki(),
566 94
			$subject->getSubobjectName(),
567
			$id,
568 94
			$subject->getSortKey()
569
		);
570
571 94
		return $id;
572
	}
573
574
	/**
575
	 * Convenience method for calling getSMWPageIDandSort without
576
	 * specifying a sortkey (if not asked for).
577
	 *
578
	 * @since 1.8
579
	 * @param string $title DB key
580
	 * @param integer $namespace namespace
581
	 * @param string $iw interwiki prefix
582
	 * @param string $subobjectName name of subobject
583
	 * @param boolean $canonical should redirects be resolved?
584
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
585
	 * @return integer SMW id or 0 if there is none
586
	 */
587 242
	public function getSMWPageID( $title, $namespace, $iw, $subobjectName, $canonical = true, $fetchHashes = false ) {
588 242
		$sort = '';
589 242
		return $this->getSMWPageIDandSort( $title, $namespace, $iw, $subobjectName, $sort, $canonical, $fetchHashes );
590
	}
591
592
	/**
593
	 * Find the numeric ID used for the page of the given title, namespace,
594
	 * interwiki, and subobjectName. If $canonical is set to true,
595
	 * redirects are taken into account to find the canonical alias ID for
596
	 * the given page. If no such ID exists, a new ID is created and
597
	 * returned. In any case, the current sortkey is set to the given one
598
	 * unless $sortkey is empty.
599
	 *
600
	 * @note Using this with $canonical==false can make sense, especially when
601
	 * the title is a redirect target (we do not want chains of redirects).
602
	 * But it is of no relevance if the title does not have an id yet.
603
	 *
604
	 * @since 1.8
605
	 * @param string $title DB key
606
	 * @param integer $namespace namespace
607
	 * @param string $iw interwiki prefix
608
	 * @param string $subobjectName name of subobject
609
	 * @param boolean $canonical should redirects be resolved?
610
	 * @param string $sortkey call-by-ref will be set to sortkey
611
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
612
	 * @return integer SMW id or 0 if there is none
613
	 */
614 277
	public function makeSMWPageID( $title, $namespace, $iw, $subobjectName, $canonical = true, $sortkey = '', $fetchHashes = false ) {
615 277
		$id = $this->getPredefinedData( $title, $namespace, $iw, $subobjectName, $sortkey );
616 277
		if ( $id != 0 ) {
617 13
			return (int)$id;
618
		} else {
619 277
			return (int)$this->makeDatabaseId( $title, $namespace, $iw, $subobjectName, $canonical, $sortkey, $fetchHashes );
620
		}
621
	}
622
623
	/**
624
	 * Find the numeric ID used for the page of the given normalized title,
625
	 * namespace, interwiki, and subobjectName. Predefined IDs are not
626
	 * taken into account (however, they would still be found correctly by
627
	 * an avoidable database read if they are stored correctly in the
628
	 * database; this should always be the case). In all other aspects, the
629
	 * method works just like makeSMWPageID(). Especially, if no ID exists,
630
	 * a new ID is created and returned.
631
	 *
632
	 * @since 1.8
633
	 * @param string $title DB key
634
	 * @param integer $namespace namespace
635
	 * @param string $iw interwiki prefix
636
	 * @param string $subobjectName name of subobject
637
	 * @param boolean $canonical should redirects be resolved?
638
	 * @param string $sortkey call-by-ref will be set to sortkey
639
	 * @param boolean $fetchHashes should the property hashes be obtained and cached?
640
	 * @return integer SMW id or 0 if there is none
641
	 */
642 277
	protected function makeDatabaseId( $title, $namespace, $iw, $subobjectName, $canonical, $sortkey, $fetchHashes ) {
643
644 277
		$oldsort = '';
645 277
		$id = $this->getDatabaseIdAndSort( $title, $namespace, $iw, $subobjectName, $oldsort, $canonical, $fetchHashes );
646 277
		$db = $this->store->getConnection( 'mw.db' );
647
648 277
		$db->beginAtomicTransaction( __METHOD__ );
649
650 277
		if ( $id == 0 ) {
651 273
			$sortkey = $sortkey ? $sortkey : ( str_replace( '_', ' ', $title ) );
652 273
			$sequenceValue = $db->nextSequenceValue( $this->getIdTable() . '_smw_id_seq' ); // Bug 42659
653
654
			// #2089 (MySQL 5.7 complained with "Data too long for column")
655 273
			$sortkey = substr( $sortkey, 0, 254 );
656
657 273
			$db->insert(
658 273
				self::TABLE_NAME,
659
				array(
660 273
					'smw_id' => $sequenceValue,
661 273
					'smw_title' => $title,
662 273
					'smw_namespace' => $namespace,
663 273
					'smw_iw' => $iw,
664 273
					'smw_subobject' => $subobjectName,
665 273
					'smw_sortkey' => $sortkey
666
				),
667 273
				__METHOD__
668
			);
669
670 273
			$id = (int)$db->insertId();
671
672
			// Properties also need to be in the property statistics table
673 273
			if( $namespace === SMW_NS_PROPERTY ) {
674
675 218
				$statsStore = new PropertyStatisticsTable(
676
					$db,
677 218
					SMWSQLStore3::PROPERTY_STATISTICS_TABLE
678
				);
679
680 218
				$statsStore->insertUsageCount( $id, 0 );
681
			}
682
683 273
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
684
685 273
			if ( $fetchHashes ) {
686 273
				$this->setPropertyTableHashesCache( $id, null );
687
			}
688
689 254
		} elseif ( $sortkey !== '' && $sortkey != $oldsort ) {
690
691
			// #2089 (MySQL 5.7 complained with "Data too long for column")
692 54
			$sortkey = substr( $sortkey, 0, 254 );
693
694 54
			$db->update(
695 54
				self::TABLE_NAME,
696 54
				array( 'smw_sortkey' => $sortkey ),
697 54
				array( 'smw_id' => $id ),
698 54
				__METHOD__
699
			);
700
701 54
			$this->setCache( $title, $namespace, $iw, $subobjectName, $id, $sortkey );
702
		}
703
704 277
		$db->endAtomicTransaction( __METHOD__ );
705
706 277
		return $id;
707
	}
708
709
	/**
710
	 * Properties have a mechanisms for being predefined (i.e. in PHP instead
711
	 * of in wiki). Special "interwiki" prefixes separate the ids of such
712
	 * predefined properties from the ids for the current pages (which may,
713
	 * e.g., be moved, while the predefined object is not movable).
714
	 *
715
	 * @todo This documentation is out of date. Right now, the special
716
	 * interwiki is used only for special properties without a label, i.e.,
717
	 * which cannot be shown to a user. This allows us to filter such cases
718
	 * from all queries that retrieve lists of properties. It should be
719
	 * checked that this is really the only use that this has throughout
720
	 * the code.
721
	 *
722
	 * @since 1.8
723
	 * @param SMWDIProperty $property
724
	 * @return string
725
	 */
726 270
	public function getPropertyInterwiki( SMWDIProperty $property ) {
727 270
		return ( $property->getLabel() !== '' ) ? '' : SMW_SQL3_SMWINTDEFIW;
728
	}
729
730
	/**
731
	 * @since  2.1
732
	 *
733
	 * @param integer $sid
734
	 * @param DIWikiPage $subject
735
	 * @param integer|string|null $interWiki
736
	 */
737 244
	public function updateInterwikiField( $sid, DIWikiPage $subject, $interWiki = null ) {
738
739 244
		$this->store->getConnection()->update(
740 244
			self::TABLE_NAME,
741 244
			array( 'smw_iw' => $interWiki !== null ? $interWiki : $subject->getInterWiki() ),
742 244
			array( 'smw_id' => $sid ),
743 244
			__METHOD__
744
		);
745
746 244
		$this->setCache(
747 244
			$subject->getDBKey(),
748 244
			$subject->getNamespace(),
749 244
			$subject->getInterWiki(),
750 244
			$subject->getSubobjectName(),
751
			$sid,
752 244
			$subject->getSortKey()
753
		);
754 244
	}
755
756
	/**
757
	 * Fetch the ID for an SMWDIProperty object. This method achieves the
758
	 * same as getSMWPageID(), but avoids additional normalization steps
759
	 * that have already been performed when creating an SMWDIProperty
760
	 * object.
761
	 *
762
	 * @note There is no distinction between properties and inverse
763
	 * properties here. A property and its inverse have the same ID in SMW.
764
	 *
765
	 * @param SMWDIProperty $property
766
	 * @return integer
767
	 */
768 272
	public function getSMWPropertyID( SMWDIProperty $property ) {
769 272
		if ( array_key_exists( $property->getKey(), self::$special_ids ) ) {
770 271
			return self::$special_ids[$property->getKey()];
771
		} else {
772 270
			$sortkey = '';
773 270
			return $this->getDatabaseIdAndSort( $property->getKey(), SMW_NS_PROPERTY, $this->getPropertyInterwiki( $property ), '', $sortkey, true, false );
774
		}
775
	}
776
777
	/**
778
	 * Fetch and possibly create the ID for an SMWDIProperty object. The
779
	 * method achieves the same as getSMWPageID() but avoids additional
780
	 * normalization steps that have already been performed when creating
781
	 * an SMWDIProperty object.
782
	 *
783
	 * @see getSMWPropertyID
784
	 * @param SMWDIProperty $property
785
	 * @return integer
786
	 */
787 254
	public function makeSMWPropertyID( SMWDIProperty $property ) {
788 254
		if ( array_key_exists( $property->getKey(), self::$special_ids ) ) {
789 224
			return (int)self::$special_ids[$property->getKey()];
790
		} else {
791 225
			return (int)$this->makeDatabaseId(
792 225
				$property->getKey(),
793 225
				SMW_NS_PROPERTY,
794 225
				$this->getPropertyInterwiki( $property ),
795 225
				'',
796 225
				true,
797 225
				$property->getLabel(),
798 225
				false
799
			);
800
		}
801
	}
802
803
	/**
804
	 * Normalize the information for an SMW object (page etc.) and return
805
	 * the predefined ID if any. All parameters are call-by-reference and
806
	 * will be changed to perform any kind of built-in normalization that
807
	 * SMW requires. This mainly applies to predefined properties that
808
	 * should always use their property key as a title, have fixed
809
	 * sortkeys, etc. Some very special properties also have fixed IDs that
810
	 * do not require any DB lookups. In such cases, the method returns
811
	 * this ID; otherwise it returns 0.
812
	 *
813
	 * @note This function could be extended to account for further kinds
814
	 * of normalization and predefined ID. However, both getSMWPropertyID
815
	 * and makeSMWPropertyID must then also be adjusted to do the same.
816
	 *
817
	 * @since 1.8
818
	 * @param string $title DB key
819
	 * @param integer $namespace namespace
820
	 * @param string $iw interwiki prefix
821
	 * @param string $subobjectName
822
	 * @param string $sortkey
823
	 * @return integer predefined id or 0 if none
824
	 */
825 300
	protected function getPredefinedData( &$title, &$namespace, &$iw, &$subobjectName, &$sortkey ) {
826 300
		if ( $namespace == SMW_NS_PROPERTY &&
827 300
			( $iw === '' || $iw == SMW_SQL3_SMWINTDEFIW ) && $title != '' ) {
828
829
			// Check if this is a predefined property:
830 234
			if ( $title{0} != '_' ) {
831
				// This normalization also applies to
832
				// subobjects of predefined properties.
833 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...
834 234
				if ( $newTitle ) {
835 60
					$title = $newTitle;
836 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...
837 60
					if ( $sortkey === '' ) {
838
						$iw = SMW_SQL3_SMWINTDEFIW;
839
					}
840
				}
841
			}
842
843
			// Check if this is a property with a fixed SMW ID:
844 234
			if ( $subobjectName === '' && array_key_exists( $title, self::$special_ids ) ) {
845 52
				return self::$special_ids[$title];
846
			}
847
		}
848
849 298
		return 0;
850
	}
851
852
	/**
853
	 * Change an internal id to another value. If no target value is given, the
854
	 * value is changed to become the last id entry (based on the automatic id
855
	 * increment of the database). Whatever currently occupies this id will be
856
	 * moved consistently in all relevant tables. Whatever currently occupies
857
	 * the target id will be ignored (it should be ensured that nothing is
858
	 * moved to an id that is still in use somewhere).
859
	 *
860
	 * @since 1.8
861
	 * @param integer $curid
862
	 * @param integer $targetid
863
	 */
864 1
	public function moveSMWPageID( $curid, $targetid = 0 ) {
865 1
		$db = $this->store->getConnection();
866
867 1
		$row = $db->selectRow(
868 1
			self::TABLE_NAME,
869 1
			'*',
870 1
			array( 'smw_id' => $curid ),
871 1
			__METHOD__
872
		);
873
874 1
		if ( $row === false ) {
875 1
			return; // no id at current position, ignore
876
		}
877
878
		$db->beginAtomicTransaction( __METHOD__ );
879
880
		if ( $targetid == 0 ) { // append new id
881
			$sequenceValue = $db->nextSequenceValue( $this->getIdTable() . '_smw_id_seq' ); // Bug 42659
882
883
			$db->insert(
884
				self::TABLE_NAME,
885
				array(
886
					'smw_id' => $sequenceValue,
887
					'smw_title' => $row->smw_title,
888
					'smw_namespace' => $row->smw_namespace,
889
					'smw_iw' => $row->smw_iw,
890
					'smw_subobject' => $row->smw_subobject,
891
					'smw_sortkey' => $row->smw_sortkey
892
				),
893
				__METHOD__
894
			);
895
896
			$targetid = $db->insertId();
897
		} else { // change to given id
898
			$db->insert(
899
				self::TABLE_NAME,
900
				array( 'smw_id' => $targetid,
901
					'smw_title' => $row->smw_title,
902
					'smw_namespace' => $row->smw_namespace,
903
					'smw_iw' => $row->smw_iw,
904
					'smw_subobject' => $row->smw_subobject,
905
					'smw_sortkey' => $row->smw_sortkey
906
				),
907
				__METHOD__
908
			);
909
		}
910
911
		$db->delete(
912
			self::TABLE_NAME,
913
			array(
914
				'smw_id' => $curid
915
			),
916
			__METHOD__
917
		);
918
919
		$this->setCache(
920
			$row->smw_title,
921
			$row->smw_namespace,
922
			$row->smw_iw,
923
			$row->smw_subobject,
924
			$targetid,
925
			$row->smw_sortkey
926
		);
927
928
		$this->store->changeSMWPageID(
929
			$curid,
930
			$targetid,
931
			$row->smw_namespace,
932
			$row->smw_namespace
933
		);
934
935
		$db->endAtomicTransaction( __METHOD__ );
936
	}
937
938
	/**
939
	 * Add or modify a cache entry. The key consists of the
940
	 * parameters $title, $namespace, $interwiki, and $subobject. The
941
	 * cached data is $id and $sortkey.
942
	 *
943
	 * @since 1.8
944
	 * @param string $title
945
	 * @param integer $namespace
946
	 * @param string $interwiki
947
	 * @param string $subobject
948
	 * @param integer $id
949
	 * @param string $sortkey
950
	 */
951 300
	public function setCache( $title, $namespace, $interwiki, $subobject, $id, $sortkey ) {
952
953 300
		if ( strpos( $title, ' ' ) !== false ) {
954
			throw new RuntimeException( "Somebody tried to use spaces in a cache title! ($title)");
955
		}
956
957 300
		$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
958
959 300
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
960 278
			$this->checkPropertySizeLimit();
961 278
			$this->prop_ids[$title] = $id;
962 278
			$this->prop_sortkeys[$title] = $sortkey;
963
		} else {
964 287
			$this->checkRegularSizeLimit();
965 287
			$this->regular_ids[$hashKey] = $id;
966 287
			$this->regular_sortkeys[$hashKey] = $sortkey;
967
		}
968
969 300
		$this->idToDataItemMatchFinder->saveToCache( $id, $hashKey );
970 300
		$this->intermediaryIdCache->save( $hashKey, $id );
971
972 300
		if ( $interwiki == SMW_SQL3_SMWREDIIW ) { // speed up detection of redirects when fetching IDs
973 265
			$this->setCache(  $title, $namespace, '', $subobject, 0, '' );
974
		}
975 300
	}
976
977
	/**
978
	 * @since 2.1
979
	 *
980
	 * @param integer $id
981
	 *
982
	 * @return DIWikiPage|null
983
	 */
984 270
	public function getDataItemById( $id ) {
985 270
		return $this->idToDataItemMatchFinder->getDataItemById( $id );
986
	}
987
988
	/**
989
	 * @since 2.3
990
	 *
991
	 * @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...
992
	 *
993
	 * @return string[]
994
	 */
995 79
	public function getDataItemPoolHashListFor( array $idlist ) {
996 79
		return $this->idToDataItemMatchFinder->getDataItemPoolHashListFor( $idlist );
997
	}
998
999
	/**
1000
	 * Get a cached SMW ID, or false if no cache entry is found.
1001
	 *
1002
	 * @since 1.8
1003
	 * @param string $title
1004
	 * @param integer $namespace
1005
	 * @param string $interwiki
1006
	 * @param string $subobject
1007
	 * @return integer|boolean
1008
	 */
1009 299
	protected function getCachedId( $title, $namespace, $interwiki, $subobject ) {
1010 299
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1011 282
			if ( array_key_exists( $title, $this->prop_ids ) ) {
1012 261
				$this->prophit_debug++;
1013 261
				return (int)$this->prop_ids[$title];
1014
			} else {
1015 278
				$this->propmiss_debug++;
1016 278
				return false;
1017
			}
1018
		} else {
1019 286
			$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1020 286
			if ( array_key_exists( $hashKey, $this->regular_ids ) ) {
1021 267
				$this->reghit_debug++;
1022 267
				return (int)$this->regular_ids[$hashKey];
1023
			} else {
1024 286
				$this->regmiss_debug++;
1025 286
				return false;
1026
			}
1027
		}
1028
	}
1029
1030
	/**
1031
	 * Get a cached SMW sortkey, or false if no cache entry is found.
1032
	 *
1033
	 * @since 1.8
1034
	 * @param string $title
1035
	 * @param integer $namespace
1036
	 * @param string $interwiki
1037
	 * @param string $subobject
1038
	 * @return string|boolean
1039
	 */
1040 288
	protected function getCachedSortKey( $title, $namespace, $interwiki, $subobject ) {
1041 288
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1042 261
			if ( array_key_exists( $title, $this->prop_sortkeys ) ) {
1043 261
				return $this->prop_sortkeys[$title];
1044
			} else {
1045
				return false;
1046
			}
1047
		} else {
1048 288
			$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1049 288
			if ( array_key_exists( $hashKey, $this->regular_sortkeys ) ) {
1050 269
				return $this->regular_sortkeys[$hashKey];
1051
			} else {
1052 288
				return false;
1053
			}
1054
		}
1055
	}
1056
1057
	/**
1058
	 * Remove any cache entry for the given data. The key consists of the
1059
	 * parameters $title, $namespace, $interwiki, and $subobject. The
1060
	 * cached data is $id and $sortkey.
1061
	 *
1062
	 * @since 1.8
1063
	 * @param string $title
1064
	 * @param integer $namespace
1065
	 * @param string $interwiki
1066
	 * @param string $subobject
1067
	 */
1068 9
	public function deleteCache( $title, $namespace, $interwiki, $subobject ) {
1069
1070 9
		$hashKey = HashBuilder::createFromSegments( $title, $namespace, $interwiki, $subobject );
1071
1072 9
		if ( $namespace == SMW_NS_PROPERTY && $interwiki === '' && $subobject === '' ) {
1073 1
			$id =  isset( $this->prop_ids[$title] ) ?  $this->prop_ids[$title] : 0;
1074 1
			unset( $this->prop_ids[$title] );
1075 1
			unset( $this->prop_sortkeys[$title] );
1076
		} else {
1077 9
			$id = isset( $this->regular_ids[$hashKey] ) ? $this->regular_ids[$hashKey] : 0;
1078 9
			unset( $this->regular_ids[$hashKey] );
1079 9
			unset( $this->regular_sortkeys[$hashKey] );
1080
		}
1081
1082 9
		$this->intermediaryIdCache->delete( $hashKey );
1083 9
		$this->idToDataItemMatchFinder->deleteFromCache( $id );
1084 9
	}
1085
1086
	/**
1087
	 * Move all cached information about subobjects.
1088
	 *
1089
	 * @todo This method is neither efficient nor very convincing
1090
	 * architecturally; it should be redesigned.
1091
	 *
1092
	 * @since 1.8
1093
	 * @param string $oldtitle
1094
	 * @param integer $oldnamespace
1095
	 * @param string $newtitle
1096
	 * @param integer $newnamespace
1097
	 */
1098 22
	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...
1099
		// Currently we have no way to change title and namespace across all entries.
1100
		// Best we can do is clear the cache to avoid wrong hits:
1101 22
		if ( $oldnamespace == SMW_NS_PROPERTY || $newnamespace == SMW_NS_PROPERTY ) {
1102 7
			$this->prop_ids = array();
1103 7
			$this->prop_sortkeys = array();
1104
		}
1105 22
		if ( $oldnamespace != SMW_NS_PROPERTY || $newnamespace != SMW_NS_PROPERTY ) {
1106 16
			$this->regular_ids = array();
1107 16
			$this->regular_sortkeys = array();
1108
		}
1109 22
	}
1110
1111
	/**
1112
	 * Delete all cached information.
1113
	 *
1114
	 * @since 1.8
1115
	 */
1116 26
	public function clearCaches() {
1117 26
		$this->prop_ids = array();
1118 26
		$this->prop_sortkeys = array();
1119 26
		$this->regular_ids = array();
1120 26
		$this->regular_sortkeys = array();
1121 26
		$this->idToDataItemMatchFinder->clear();
1122 26
	}
1123
1124
	/**
1125
	 * Ensure that the property ID and sortkey caches have space to insert
1126
	 * at least one more element. If not, some other entries will be unset.
1127
	 *
1128
	 * @since 1.8
1129
	 */
1130 278
	protected function checkPropertySizeLimit() {
1131 278
		if ( count( $this->prop_ids ) >= self::$PROP_CACHE_MAX_SIZE ) {
1132
			$keys = array_rand( $this->prop_ids, 10 );
1133
			foreach ( $keys as $key ) {
1134
				unset( $this->prop_ids[$key] );
1135
				unset( $this->prop_sortkeys[$key] );
1136
			}
1137
		}
1138 278
	}
1139
1140
	/**
1141
	 * Ensure that the non-property ID and sortkey caches have space to
1142
	 * insert at least one more element. If not, some other entries will be
1143
	 * unset.
1144
	 *
1145
	 * @since 1.8
1146
	 */
1147 287
	protected function checkRegularSizeLimit() {
1148 287
		if ( count( $this->regular_ids ) >= self::$PAGE_CACHE_MAX_SIZE ) {
1149
			$keys = array_rand( $this->regular_ids, 10 );
1150
			foreach ( $keys as $key ) {
1151
				unset( $this->regular_ids[$key] );
1152
				unset( $this->regular_sortkeys[$key] );
1153
			}
1154
		}
1155 287
	}
1156
1157
	/**
1158
	 * Return an array of hashes with table names as keys. These
1159
	 * hashes are used to compare new data with old data for each
1160
	 * property-value table when updating data
1161
	 *
1162
	 * @since 1.8
1163
	 *
1164
	 * @param integer $subjectId ID of the page as stored in the SMW IDs table
1165
	 *
1166
	 * @return array
1167
	 */
1168 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...
1169 269
		$hash = null;
1170 269
		$db = $this->store->getConnection();
1171
1172 269
		if ( $this->hashCacheId == $subjectId ) {
1173 269
			$hash = $this->hashCacheContents;
1174 229
		} elseif ( $subjectId !== 0 ) {
1175
1176 229
			$row = $db->selectRow(
1177 229
				self::TABLE_NAME,
1178 229
				array( 'smw_proptable_hash' ),
1179 229
				'smw_id=' . $subjectId,
1180 229
				__METHOD__
1181
			);
1182
1183 229
			if ( $row !== false ) {
1184 229
				$hash = $row->smw_proptable_hash;
1185
			}
1186
		}
1187
1188 269
		if ( $hash !== null && $GLOBALS['wgDBtype'] == 'postgres' ) {
1189
			$hash = pg_unescape_bytea( $hash );
1190
		}
1191
1192 269
		return is_null( $hash ) ? array() : unserialize( $hash );
1193
	}
1194
1195
	/**
1196
	 * Update the proptable_hash for a given page.
1197
	 *
1198
	 * @since 1.8
1199
	 * @param integer $sid ID of the page as stored in SMW IDs table
1200
	 * @param string[] of hash values with table names as keys
1201
	 */
1202 254
	public function setPropertyTableHashes( $sid, array $newTableHashes ) {
1203 254
		$db = $this->store->getConnection();
1204 254
		$propertyTableHash = serialize( $newTableHashes );
1205
1206 254
		$db->update(
1207 254
			self::TABLE_NAME,
1208 254
			array( 'smw_proptable_hash' => $propertyTableHash ),
1209 254
			array( 'smw_id' => $sid ),
1210 254
			__METHOD__
1211
		);
1212
1213 254
		if ( $sid == $this->hashCacheId ) {
1214 254
			$this->setPropertyTableHashesCache( $sid, $propertyTableHash );
1215
		}
1216 254
	}
1217
1218
	/**
1219
	 * Temporarily cache a property tablehash that has been retrieved for
1220
	 * the given SMW ID.
1221
	 *
1222
	 * @since 1.8
1223
	 * @param $id integer
1224
	 * @param $propertyTableHash string
1225
	 */
1226 273
	protected function setPropertyTableHashesCache( $id, $propertyTableHash ) {
1227 273
		if ( $id == 0 ) {
1228 2
			return; // never cache 0
1229
		}
1230
		//print "Cache set for $id.\n";
1231 273
		$this->hashCacheId = $id;
1232 273
		$this->hashCacheContents = $propertyTableHash;
1233 273
	}
1234
1235
	/**
1236
	 * Simple helper method for debugging cache performance. Prints
1237
	 * statistics about the SMWSql3SmwIds object created last.
1238
	 * The following code can be used in LocalSettings.php to enable
1239
	 * this in a wiki:
1240
	 *
1241
	 * $wgHooks['SkinAfterContent'][] = 'showCacheStats';
1242
	 * function showCacheStats() {
1243
	 *   self::debugDumpCacheStats();
1244
	 *   return true;
1245
	 * }
1246
	 *
1247
	 * @note This is a debugging/profiling method that no published code
1248
	 * should rely on.
1249
	 *
1250
	 * @since 1.8
1251
	 */
1252
	public static function debugDumpCacheStats() {
1253
		$that = self::$singleton_debug;
1254
		if ( is_null( $that ) ) {
1255
			return;
1256
		}
1257
1258
		$debugString =
1259
			"Statistics for SMWSql3SmwIds:\n" .
1260
			"- Executed {$that->selectrow_sort_debug} selects for sortkeys.\n" .
1261
			"- Executed {$that->selectrow_redi_debug} selects for redirects.\n" .
1262
			"- Regular cache hits: {$that->reghit_debug} misses: {$that->regmiss_debug}";
1263
		if ( $that->regmiss_debug + $that->reghit_debug > 0 ) {
1264
			$debugString .= " rate: " . round( $that->reghit_debug/( $that->regmiss_debug + $that->reghit_debug ), 3 );
1265
		}
1266
		$debugString .= " cache size: " . count( $that->regular_ids ) . "\n";
1267
		$debugString .= "- Property cache hits: {$that->prophit_debug} misses: {$that->propmiss_debug}";
1268
		if ( $that->propmiss_debug + $that->prophit_debug > 0 ) {
1269
			$debugString .= " rate: " . round( $that->prophit_debug/( $that->propmiss_debug + $that->prophit_debug ), 3 );
1270
		}
1271
		$debugString .= " cache size: " . count( $that->prop_ids ) . "\n";
1272
		wfDebug( $debugString );
1273
	}
1274
1275
	/**
1276
	 * Returns store Id table name
1277
	 *
1278
	 * @return string
1279
	 */
1280 274
	public function getIdTable() {
1281 274
		return self::TABLE_NAME;
1282
	}
1283
1284
}
1285