Completed
Push — master ( 089e57...c667b0 )
by mw
111:13 queued 76:21
created

addQueryResultToCache()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 15
nc 2
nop 4
dl 0
loc 27
ccs 15
cts 15
cp 1
crap 3
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\Query\Result;
4
5
use Onoi\BlobStore\BlobStore;
6
use SMWQuery as Query;
7
use SMWQueryResult as QueryResult;
8
use SMW\Store;
9
use SMW\DIWikiPage;
10
use SMW\QueryEngine;
11
use SMW\QueryFactory;
12
use Psr\Log\LoggerInterface;
13
use Psr\Log\LoggerAwareInterface;
14
use SMW\Utils\BufferedStatsdCollector;
15
use SMW\Utils\Timer;
16
use SMW\ApplicationFactory;
17
use RuntimeException;
18
19
/**
20
 * The prefetcher only caches the subject list from a computed a query
21
 * condition. The result is processed before an individual query printer has
22
 * access to the query result hence it does not interfere with the final string
23
 * output manipulation.
24
 *
25
 * The main objective is to avoid unnecessary computing of results for queries
26
 * that have the same query signature. PrintRequests as part of a QueryResult
27
 * object are not cached and are not part of a query signature.
28
 *
29
 * Cache eviction is carried out either manually (action=purge) or executed
30
 * through the QueryDepedencyLinksStore.
31
 *
32
 * @license GNU GPL v2+
33
 * @since 2.5
34
 *
35
 * @author mwjames
36
 */
37
class CachedQueryResultPrefetcher implements QueryEngine, LoggerAwareInterface {
38
39
	/**
40
	 * Update this version number when the serialization format
41
	 * changes.
42
	 */
43
	const VERSION = '1';
44
45
	/**
46
	 * Namespace occupied by the BlobStore
47
	 */
48
	const CACHE_NAMESPACE = 'smw:query:store';
49
50
	/**
51
	 * ID used by the bufferedStatsdCollector, requires to be changed in case
52
	 * the data schema is modified
53
	 *
54
	 * PHP 5.6 can do self::CACHE_NAMESPACE . ':' . self::VERSION
55
	 */
56
	const STATSD_ID = 'smw:query:store:1:d:';
57
58
	/**
59
	 * ID for the tempCache
60
	 */
61
	const POOLCACHE_ID = 'queryresult.prefetcher';
62
63
	/**
64
	 * @var Store
65
	 */
66
	private $store;
67
68
	/**
69
	 * @var QueryFactory
70
	 */
71
	private $queryFactory;
72
73
	/**
74
	 * @var BlobStore
75
	 */
76
	private $blobStore;
77
78
	/**
79
	 * @var QueryEngine
80
	 */
81
	private $queryEngine;
82
83
	/**
84
	 * @var BufferedStatsdCollector
85
	 */
86
	private $bufferedStatsdCollector;
87
88
	/**
89
	 * @var integer|boolean
90
	 */
91
	private $nonEmbeddedCacheLifetime = false;
92
93
	/**
94
	 * @var boolean
95
	 */
96
	private $enabledCache = true;
97
98
	/**
99
	 * @var loggerInterface
100
	 */
101
	private $logger;
102
103
	/**
104
	 * Keep a temp cache to hold on query results that aren't stored yet.
105
	 *
106
	 * If for example the retrieval is executed in deferred mode then a request
107
	 * may occur in the same transaction cycle without being stored to the actual
108
	 * back-end, yet queries with the same signature may have been retrieved
109
	 * already therefore allow to recall the result from tempCache.
110
	 *
111
	 * @var InMemoryCache
112
	 */
113
	private $tempCache;
114
115
	/**
116
	 * An internal change to the query execution may occur without being detected
117
	 * by the Description hash (which is the desired behaviour) and to avoid a
118
	 * stalled cache on an altered execution plan, use this modifier to generate
119
	 * a new hash.
120
	 *
121
	 * @var string/integer
122
	 */
123
	private $hashModifier = '';
124
125
	/**
126
	 * @since 2.5
127
	 *
128
	 * @param Store $store
129
	 * @param QueryFactory $queryFactory
130
	 * @param BlobStore $blobStore
131
	 * @param BufferedStatsdCollector $bufferedStatsdCollector
132
	 */
133 235
	public function __construct( Store $store, QueryFactory $queryFactory, BlobStore $blobStore, BufferedStatsdCollector $bufferedStatsdCollector ) {
134 235
		$this->store = $store;
135 235
		$this->queryFactory = $queryFactory;
136 235
		$this->blobStore = $blobStore;
137 235
		$this->bufferedStatsdCollector = $bufferedStatsdCollector;
138 235
		$this->tempCache = ApplicationFactory::getInstance()->getInMemoryPoolCache()->getPoolCacheById( self::POOLCACHE_ID );
0 ignored issues
show
Documentation Bug introduced by
It seems like \SMW\ApplicationFactory:...yId(self::POOLCACHE_ID) of type object<SMW\Cache> is incompatible with the declared type object<SMW\Query\Result\InMemoryCache> of property $tempCache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
139
140 235
		$this->initStats( date( 'Y-m-d H:i:s' ) );
141 235
	}
142
143
	/**
144
	 * @since 2.5
145
	 *
146
	 * @return array
147
	 */
148 1
	public function getStats() {
149
150
		$stats = array_filter( $this->bufferedStatsdCollector->getStats(), function( $key ) {
151 1
			return $key !== false;
152 1
		} );
153
154 1
		if ( !isset( $stats['misses'] ) || ! isset( $stats['hits'] ) ) {
155
			return $stats;
156
		}
157
158
		$misses = $this->sum( 0, $stats['misses'] );
159 1
		$hits = $this->sum( 0, $stats['hits'] );
160 1
161
		$stats['ratio'] = array();
162 1
		$stats['ratio']['hit'] = $hits > 0 ? round( $hits / ( $hits + $misses ), 4 ) : 0;
163 1
		$stats['ratio']['miss'] = $hits > 0 ? round( 1 - $stats['ratio']['hit'], 4 ) : 1;
164
165
		// Move to last
166 1
		$meta = $stats['meta'];
167 1
		unset( $stats['meta'] );
168 1
		$stats['meta'] = $meta;
169
170 1
		return $stats;
171
	}
172
173
	/**
174
	 * @since 2.5
175
	 *
176
	 * @param string|integer $hashModifier
177
	 */
178 227
	public function setHashModifier( $hashModifier ) {
179 227
		$this->hashModifier = $hashModifier;
0 ignored issues
show
Documentation Bug introduced by
It seems like $hashModifier can also be of type integer. However, the property $hashModifier is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
180 227
	}
181
182
	/**
183
	 * @see LoggerAwareInterface::setLogger
184
	 *
185
	 * @since 2.5
186
	 *
187
	 * @param LoggerInterface $logger
188
	 */
189 227
	public function setLogger( LoggerInterface $logger ) {
190 227
		$this->logger = $logger;
0 ignored issues
show
Documentation Bug introduced by
It seems like $logger of type object<Psr\Log\LoggerInterface> is incompatible with the declared type object<SMW\Query\Result\loggerInterface> of property $logger.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
191 227
	}
192
193
	/**
194
	 * @since 2.5
195
	 *
196
	 * @param QueryEngine $queryEngine
197
	 */
198 138
	public function setQueryEngine( QueryEngine $queryEngine ) {
199 138
		$this->queryEngine = $queryEngine;
200 138
	}
201
202
	/**
203
	 * @since 2.5
204
	 *
205
	 * @param boolean
206
	 */
207 235
	public function isEnabled() {
208 235
		return $this->blobStore->canUse();
209
	}
210
211
	/**
212
	 * @since 2.5
213
	 *
214
	 * @param QueryEngine $queryEngine
0 ignored issues
show
Bug introduced by
There is no parameter named $queryEngine. 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...
215
	 */
216
	public function disableCache() {
217
		$this->enabledCache = false;
218
	}
219
220
	/**
221
	 * @since 2.5
222
	 */
223 135
	public function recordStats() {
224 135
		$this->bufferedStatsdCollector->recordStats();
225 135
	}
226
227
	/**
228
	 * @since 2.5
229
	 *
230
	 * @param integer|boolean $nonEmbeddedCacheLifetime
231
	 */
232 227
	public function setNonEmbeddedCacheLifetime( $nonEmbeddedCacheLifetime ) {
233 227
		$this->nonEmbeddedCacheLifetime = $nonEmbeddedCacheLifetime;
234 227
	}
235
236
	/**
237
	 * @see QueryEngine::getQueryResult
238
	 * @since 2.5
239
	 *
240
	 * {@inheritDoc}
241
	 */
242 7
	public function getQueryResult( Query $query ) {
243
244 7
		if ( !$this->queryEngine instanceof QueryEngine ) {
245 1
			throw new RuntimeException( "Missing a QueryEngine instance." );
246
		}
247
248 6
		if ( !$this->canUse( $query ) || $query->getLimit() < 1 || $query->getOption( Query::NO_CACHE ) === true ) {
249 2
			$this->bufferedStatsdCollector->incr( $this->getNoCacheId( $query ) );
250 2
			return $this->queryEngine->getQueryResult( $query );
251
		}
252
253 4
		Timer::start( __CLASS__ );
254
255 4
		$queryId = $this->getHashFrom( $query->getQueryId() );
256
257 4
		$container = $this->blobStore->read(
258
			$queryId
259
		);
260
261 4
		if ( $this->tempCache->contains( $queryId ) || $container->has( 'results' ) ) {
262 4
			return $this->newQueryResultFromCache( $queryId, $query, $container );
263
		}
264
265 4
		$queryResult = $this->queryEngine->getQueryResult( $query );
266
267 4
		$this->tempCache->save(
268
			$queryId,
269
			$queryResult
270
		);
271
272 4
		$this->log(
273 4
			__METHOD__ . ' from backend in (sec): ' . Timer::getElapsedTime( __CLASS__, 5 ) . " ($queryId)"
274
		);
275
276 4
		if ( $this->canUse( $query ) && $queryResult instanceof QueryResult ) {
277 3
			$this->addQueryResultToCache( $queryResult, $queryId, $container, $query );
278
		}
279
280 4
		return $queryResult;
281
	}
282
283
	/**
284
	 * @since 2.5
285
	 *
286
	 * @param DIWikiPage|array $list
0 ignored issues
show
Bug introduced by
There is no parameter named $list. 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...
287
	 * @param string $context
288
	 */
289 235
	public function resetCacheBy( $item, $context = '' ) {
290
291 235
		if ( !is_array( $item ) ) {
292 234
			$item = array( $item );
293
		}
294
295 235
		$recordStats = false;
296 235
		$context = $context === '' ? 'Undefined' : $context;
297
298 235
		foreach ( $item as $id ) {
299 235
			$id = $this->getHashFrom( $id );
300 235
			$this->tempCache->delete( $id );
301
302 235
			if ( $this->blobStore->exists( $id ) ) {
303 211
				$recordStats = true;
304 211
				$this->bufferedStatsdCollector->incr( 'deletes.on' . $context );
305 235
				$this->blobStore->delete( $id );
306
			}
307
		}
308
309 235
		if ( $recordStats ) {
310 211
			$this->bufferedStatsdCollector->recordStats();
311
		}
312 235
	}
313
314 6
	private function canUse( $query ) {
315 6
		return $this->enabledCache && $this->blobStore->canUse() && ( $query->getContextPage() !== null || ( $query->getContextPage() === null && $this->nonEmbeddedCacheLifetime > 0 ) );
316
	}
317
318 4
	private function newQueryResultFromCache( $queryId, $query, $container ) {
319
320 4
		$results = array();
321 4
		$incrStats = 'hits.Undefined';
0 ignored issues
show
Unused Code introduced by
$incrStats is not used, you could remove the assignment.

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

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

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

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

Loading history...
322
323 4
		if ( ( $context = $query->getOption( Query::PROC_CONTEXT ) ) === false ) {
324 3
			$context = 'Undefined';
325
		}
326
327
		// Check if the tempCache is available for result that have not yet been
328
		// stored to the cache back-end
329 4
		if ( ( $queryResult = $this->tempCache->fetch( $queryId ) ) !== false ) {
330 1
			$this->log( __METHOD__ . ' using tempCache ' . "($queryId)" );
331
332 1
			if ( !$queryResult instanceof QueryResult ) {
333 1
				return $queryResult;
334
			}
335
336
			$incrStats = 'hits.tempCache.' . ( $query->getContextPage() !== null ? 'embedded' : 'nonEmbedded' );
337
338
			$queryResult->reset();
339
			$results = $queryResult->getResults();
340
341
			$hasFurtherResults = $queryResult->hasFurtherResults();
342
			$countValue = $queryResult->getCountValue();
343
		} else {
344
345
			$incrStats = ( $query->getContextPage() !== null ? 'hits.embedded.' : 'hits.nonEmbedded.' ) . $context;
346
347
			foreach ( $container->get( 'results' ) as $hash ) {
348 3
				$results[] = DIWikiPage::doUnserialize( $hash );
349
			}
350 3
351 3
			$hasFurtherResults = $container->get( 'continue' );
352
			$countValue = $container->get( 'count' );
353
		}
354 3
355 3
		$queryResult = $this->queryFactory->newQueryResult(
356
			$this->store,
357
			$query,
358 3
			$results,
359 3
			$hasFurtherResults
360
		);
361
362
		$queryResult->setCountValue( $countValue );
363
		$queryResult->setFromCache( true );
364
365 3
		$time = Timer::getElapsedTime( __CLASS__, 5 );
366 3
367
		$this->bufferedStatsdCollector->incr( $incrStats );
368 3
369
		$this->bufferedStatsdCollector->calcMedian(
370 3
			'medianRetrievalResponseTime.cached',
371
			$time
372 3
		);
373 3
374
		$this->log( __METHOD__ . ' (sec): ' . $time . " ($queryId)" );
375
376
		return $queryResult;
377 3
	}
378
379 3
	private function addQueryResultToCache( $queryResult, $queryId, $container, $query ) {
380
381
		if ( ( $context = $query->getOption( Query::PROC_CONTEXT ) ) === false ) {
382 3
			$context = 'Undefined';
383
		}
384 3
385
		$this->bufferedStatsdCollector->incr(
386 3
			( $query->getContextPage() !== null ? 'misses.embedded.' : 'misses.nonEmbedded.' ) . $context
387 3
		);
388 3
389
		$this->bufferedStatsdCollector->calcMedian(
390
			'medianRetrievalResponseTime.uncached',
391 3
			Timer::getElapsedTime( __CLASS__, 5 )
392 3
		);
393 3
394
		$callback = function() use( $queryResult, $queryId, $container, $query ) {
395 3
			$this->doCacheQueryResult( $queryResult, $queryId, $container, $query );
396
		};
397
398
		$deferredCallableUpdate = ApplicationFactory::getInstance()->newDeferredCallableUpdate(
399 3
			$callback
400 3
		);
401 3
402 3
		$deferredCallableUpdate->setOrigin( __METHOD__ );
403
		$deferredCallableUpdate->setFingerprint( __METHOD__ . $queryId );
404 3
		$deferredCallableUpdate->pushUpdate();
405
	}
406 3
407
	private function doCacheQueryResult( $queryResult, $queryId, $container, $query ) {
408
409
		$results = array();
410 3
411 3
		// Keep the simple string representation to avoid unnecessary data cruft
412
		// during using PHP serialize( ... )
413
		foreach ( $queryResult->getResults() as $dataItem ) {
414 3
			$results[] = $dataItem->getSerialization();
415 3
		}
416 3
417
		$container->set( 'results', $results );
418 3
		$container->set( 'continue', $queryResult->hasFurtherResults() );
419 3
		$container->set( 'count', $queryResult->getCountValue() );
420
421 3
		$queryResult->reset();
422
		$contextPage = $query->getContextPage();
423
424
		if ( $contextPage === null ) {
425 3
			$container->setExpiryInSeconds( $this->nonEmbeddedCacheLifetime );
426 3
			$hash = 'nonEmbedded';
0 ignored issues
show
Unused Code introduced by
$hash is not used, you could remove the assignment.

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

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

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

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

Loading history...
427
		} else {
428
			$this->addToLinkedList( $contextPage, $queryId );
429 3
			$hash = $contextPage->getHash();
0 ignored issues
show
Unused Code introduced by
$hash is not used, you could remove the assignment.

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

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

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

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

Loading history...
430
		}
431
432
		$this->blobStore->save(
433 3
			$container
434
		);
435 3
436 3
		$this->tempCache->delete( $queryId );
437
438
		$this->log(
439 3
			__METHOD__ . ' cache storage (sec): ' . Timer::getElapsedTime( __CLASS__, 5 ) . " ($queryId)"
440
		);
441
442 3
		return $queryResult;
443
	}
444
445
	private function addToLinkedList( $contextPage, $queryId ) {
446 3
447 3
		// Ensure that without QueryDependencyLinksStore being enabled recorded
448
		// subjects related to a query can be discoverable and purged separately
449
		$container = $this->blobStore->read(
450
			$this->getHashFrom( $contextPage )
451
		);
452 3
453
		// If a subject gets purged then the linked list of queries associated
454 3
		// with that subject allows for an immediate associated removal
455
		$container->addToLinkedList( $queryId );
456
457 3
		$this->blobStore->save(
458
			$container
459 236
		);
460
	}
461 236
462 234
	private function getHashFrom( $subject ) {
463
464
		if ( $subject instanceof DIWikiPage ) {
465 236
			$subject = $subject->asBase()->getHash();
466
		}
467
468 4
		return md5( $subject . self::VERSION . $this->hashModifier );
469
	}
470 4
471 1
	private function log( $message, $context = array() ) {
472
473
		if ( $this->logger === null ) {
474 3
			return;
475 3
		}
476
477 2
		$this->logger->info( $message, $context );
478
	}
479 2
480
	private function getNoCacheId( $query ) {
481 2
482 1
		$id = 'noCache.misc';
483
484
		if ( !$this->canUse( $query ) ) {
485 2
			$id = 'noCache.disabled';
486 1
		}
487
488
		if ( $query->getLimit() < 1 ) {
489 2
			$id = 'noCache.byLimit';
490 1
		}
491
492
		if ( $query->getOption( Query::NO_CACHE ) === true ) {
493 2
			$id = 'noCache.byOption';
494
		}
495
496 235
		if ( ( $context = $query->getOption( Query::PROC_CONTEXT ) ) !== false ) {
497
			$id .= '.' . $context;
498 235
		}
499
500 235
		return $id;
501 235
	}
502 235
503 235
	private function initStats( $date ) {
0 ignored issues
show
Coding Style introduced by
initStats 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...
504 235
505 235
		$this->bufferedStatsdCollector->shouldRecord( $this->isEnabled() );
506 235
507 235
		$this->bufferedStatsdCollector->init( 'misses', array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|integer.

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...
508 235
		$this->bufferedStatsdCollector->init( 'hits', array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|integer.

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...
509 235
		$this->bufferedStatsdCollector->init( 'deletes', array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|integer.

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...
510 235
		$this->bufferedStatsdCollector->init( 'noCache', array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|integer.

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...
511
		$this->bufferedStatsdCollector->init( 'medianRetrievalResponseTime', array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|integer.

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...
512
		$this->bufferedStatsdCollector->set( 'meta.version', self::VERSION );
513
		$this->bufferedStatsdCollector->set( 'meta.cacheLifetime.embedded', $GLOBALS['smwgQueryResultCacheLifetime'] );
514
		$this->bufferedStatsdCollector->set( 'meta.cacheLifetime.nonEmbedded', $GLOBALS['smwgQueryResultNonEmbeddedCacheLifetime'] );
515
		$this->bufferedStatsdCollector->init( 'meta.collectionDate.start', $date );
516
		$this->bufferedStatsdCollector->set( 'meta.collectionDate.update', $date );
517
	}
518
519
	// http://stackoverflow.com/questions/3777995/php-array-recursive-sum
520
	private static function sum( $value, $container ) {
521
		return $value + ( is_array( $container ) ? array_reduce( $container, 'self::sum' ) : $container );
522
	}
523
524
}
525