public function testCanConstructEntityIdListRelevanceDetectionFilter()
 {
     $store = $this->getMockBuilder('\\SMW\\Store')->disableOriginalConstructor()->getMockForAbstractClass();
     $compositePropertyTableDiffIterator = $this->getMockBuilder('\\SMW\\SQLStore\\CompositePropertyTableDiffIterator')->disableOriginalConstructor()->getMock();
     $instance = new QueryDependencyLinksStoreFactory();
     $this->assertInstanceOf('\\SMW\\SQLStore\\QueryDependency\\EntityIdListRelevanceDetectionFilter', $instance->newEntityIdListRelevanceDetectionFilter($store, $compositePropertyTableDiffIterator));
 }
 private function registerHooksForInternalUse(ApplicationFactory $applicationFactory, DeferredRequestDispatchManager $deferredRequestDispatchManager)
 {
     $queryDependencyLinksStoreFactory = new QueryDependencyLinksStoreFactory();
     $queryDependencyLinksStore = $queryDependencyLinksStoreFactory->newQueryDependencyLinksStore($applicationFactory->getStore());
     $transitionalDiffStore = $applicationFactory->singleton('TransitionalDiffStore');
     /**
      * @see https://www.semantic-mediawiki.org/wiki/Hooks#SMW::SQLStore::AfterDataUpdateComplete
      */
     $this->handlers['SMW::SQLStore::AfterDataUpdateComplete'] = function ($store, $semanticData, $compositePropertyTableDiffIterator) use($queryDependencyLinksStoreFactory, $queryDependencyLinksStore, $deferredRequestDispatchManager, $transitionalDiffStore) {
         // When in commandLine mode avoid deferred execution and run a process
         // within the same transaction
         $deferredRequestDispatchManager->isCommandLineMode($store->getOptions()->has('isCommandLineMode') ? $store->getOptions()->get('isCommandLineMode') : $GLOBALS['wgCommandLineMode']);
         $queryDependencyLinksStore->setStore($store);
         $subject = $semanticData->getSubject();
         $slot = $transitionalDiffStore->createSlotFrom($compositePropertyTableDiffIterator);
         $queryDependencyLinksStore->pruneOutdatedTargetLinks($subject, $compositePropertyTableDiffIterator);
         $entityIdListRelevanceDetectionFilter = $queryDependencyLinksStoreFactory->newEntityIdListRelevanceDetectionFilter($store, $compositePropertyTableDiffIterator);
         $jobParameters = $queryDependencyLinksStore->buildParserCachePurgeJobParametersFrom($entityIdListRelevanceDetectionFilter);
         $deferredRequestDispatchManager->scheduleParserCachePurgeJobWith($subject->getTitle(), $jobParameters);
         $fulltextSearchTableFactory = new FulltextSearchTableFactory();
         $textByChangeUpdater = $fulltextSearchTableFactory->newTextByChangeUpdater($store);
         $textByChangeUpdater->pushUpdates($compositePropertyTableDiffIterator, $deferredRequestDispatchManager, $slot);
         // Since we cannot predict as to when the slot is used and by whom,
         // schedule a job to ensure to be the last in-line to clean-up
         // any remaining slots for this transaction
         $deferredRequestDispatchManager->scheduleChronologyPurgeJobWith($subject->getTitle(), array('slot:id' => $slot));
         return true;
     };
     /**
      * @see https://www.semantic-mediawiki.org/wiki/Hooks#SMW::Store::AfterQueryResultLookupComplete
      */
     $this->handlers['SMW::Store::AfterQueryResultLookupComplete'] = function ($store, &$result) use($queryDependencyLinksStore, $applicationFactory) {
         $queryDependencyLinksStore->setStore($store);
         $queryDependencyLinksStore->doUpdateDependenciesFrom($result);
         $applicationFactory->singleton('CachedQueryResultPrefetcher')->recordStats();
         return true;
     };
 }
 /**
  * Based on the CHUNK_SIZE, target links are purged in an instant if those
  * selected entities are < CHUNK_SIZE which should be enough for most
  * common queries that only share a limited amount of dependencies, yet for
  * queries that expect a large subject/dependency pool, doing an online update
  * for all at once is not feasible hence the iterative process of creating
  * batches that run through the job scheduler.
  *
  * @param array|string $idList
  */
 private function findEmbeddedQueryTargetLinksBatches($idList)
 {
     if (is_string($idList) && strpos($idList, '|') !== false) {
         $idList = explode('|', $idList);
     }
     if ($idList === array()) {
         return true;
     }
     $queryDependencyLinksStoreFactory = new QueryDependencyLinksStoreFactory();
     $queryDependencyLinksStore = $queryDependencyLinksStoreFactory->newQueryDependencyLinksStore($this->store);
     $requestOptions = new RequestOptions();
     // +1 to look ahead
     $requestOptions->setLimit($this->limit + 1);
     $requestOptions->setOffset($this->offset);
     $hashList = $queryDependencyLinksStore->findEmbeddedQueryTargetLinksHashListFor($idList, $requestOptions);
     if ($hashList === array()) {
         return true;
     }
     $countedHashListEntries = count($hashList);
     // If more results are available then use an iterative increase to fetch
     // the remaining updates by creating successive jobs
     if ($countedHashListEntries > $this->limit) {
         $job = new self($this->getTitle(), array('idlist' => $idList, 'limit' => $this->limit, 'offset' => $this->offset + self::CHUNK_SIZE));
         $job->run();
     }
     wfDebugLog('smw', __METHOD__ . " counted: {$countedHashListEntries} | offset: {$this->offset}  for " . $this->getTitle()->getPrefixedDBKey() . "\n");
     list($hashList, $queryList) = $this->doBuildUniqueTargetLinksHashList($hashList);
     $this->applicationFactory->singleton('CachedQueryResultPrefetcher')->resetCacheBy($queryList);
     $this->addPagesToUpdater($hashList);
 }