Completed
Pull Request — master (#93)
by mw
01:17
created

HookRegistry::setOption()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
namespace SCI;
4
5
use SMW\Store;
6
use Onoi\Cache\Cache;
7
use SMW\ApplicationFactory;
8
use SMW\DIWikiPage;
9
use SMWDataItem as DataItem;
10
use Hooks;
11
12
/**
13
 * @license GNU GPL v2+
14
 * @since 1.0
15
 *
16
 * @author mwjames
17
 */
18
class HookRegistry {
19
20
	/**
21
	 * @var array
22
	 */
23
	private $handlers = [];
24
25
	/**
26
	 * @var Options
27
	 */
28
	private $options;
29
30
	/**
31
	 * @var CitationReferencePositionJournal
32
	 */
33
	private $citationReferencePositionJournal;
34
35
	/**
36
	 * @since 1.0
37
	 *
38
	 * @param Store $store
39
	 * @param Cache $cache
40
	 * @param Options $options
41
	 */
42 16
	public function __construct( Store $store, Cache $cache, Options $options ) {
43 16
		$this->options = $options;
44
45 16
		$this->addCallbackHandlers(
46 16
			$store,
47 16
			$cache,
48 16
			$this->options
49
		);
50 16
	}
51
52
	/**
53
	 * @note Usually only used during unit/integration testing
54
	 *
55
	 * @since  1.0
56
	 *
57
	 * @param string $key
58
	 * @param mixed $value
59
	 */
60 14
	public function setOption( $key, $value ) {
61 14
		$this->options->set( $key, $value );
62 14
	}
63
64
	/**
65
	 * @since  1.0
66
	 *
67
	 * @param string $name
68
	 *
69
	 * @return boolean
70
	 */
71 1
	public function isRegistered( $name ) {
72 1
		return Hooks::isRegistered( $name );
73
	}
74
75
	/**
76
	 * @since  1.0
77
	 */
78 14
	public function clear() {
79
80 14
		if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
81
			return;
82
		}
83
84 14
		foreach ( $this->handlers as $name => $callback ) {
85
			if (
86 14
				!class_exists( '\MediaWiki\MediaWikiServices' ) ||
87 14
				!method_exists( \MediaWiki\MediaWikiServices::getInstance(), 'getHookContainer' ) ) {
88 14
				\Hooks::clear( $name );
89
			} else {
90 14
				\MediaWiki\MediaWikiServices::getInstance()->getHookContainer()->clear( $name );
91
			}
92
		}
93 14
	}
94
95
	/**
96
	 * @since  1.0
97
	 *
98
	 * @param string $name
99
	 *
100
	 * @return Callable|false
101
	 */
102 1
	public function getHandlerFor( $name ) {
103 1
		return isset( $this->handlers[$name] ) ? $this->handlers[$name] : false;
104
	}
105
106
	/**
107
	 * @since  1.0
108
	 */
109 14
	public function register() {
110
111 14
		if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
112
			return;
113
		}
114
115 14
		foreach ( $this->handlers as $name => $callback ) {
116
			if (
117 14
				!class_exists( '\MediaWiki\MediaWikiServices' ) ||
118 14
				!method_exists( \MediaWiki\MediaWikiServices::getInstance(), 'getHookContainer' ) ) {
119 14
				\Hooks::register( $name, $callback );
120
			} else {
121 14
				\MediaWiki\MediaWikiServices::getInstance()->getHookContainer()->register( $name, $callback );
122
			}
123
		}
124 14
	}
125
126
	/**
127
	 * @since  1.3
128
	 *
129
	 * @param array &$config
130
	 */
131
	public static function onBeforeConfigCompletion( &$config ) {
132
133
		if ( !isset( $config['smwgFulltextSearchPropertyExemptionList'] ) ) {
134
			return;
135
		}
136
137
		// Exclude those properties from indexing
138
		$config['smwgFulltextSearchPropertyExemptionList'] = array_merge(
139
			$config['smwgFulltextSearchPropertyExemptionList'],
140
			[ PropertyRegistry::SCI_CITE ]
141
		);
142
	}
143
144
	/**
145
	 * @since 2.0
146
	 *
147
	 * @param array &$vars
148
	 */
149
	public static function initExtension( &$vars ) {
150
151 15
		$vars['wgHooks']['SMW::Config::BeforeCompletion'][] = function( &$config ) {
152
153
			$exemptionlist = [
154 15
				PropertyRegistry::SCI_CITE
155
			];
156
157
			// Exclude listed properties from indexing
158 15
			if ( isset( $config['smwgFulltextSearchPropertyExemptionList'] ) ) {
159 15
				$config['smwgFulltextSearchPropertyExemptionList'] = array_merge(
160 15
					$config['smwgFulltextSearchPropertyExemptionList'],
161 15
					$exemptionlist
162
				);
163
			}
164
165
			// Exclude listed properties from dependency detection as each of the
166
			// selected object would trigger an automatic change without the necessary
167
			// human intervention and can therefore produce unwanted query updates
168
169 15
			if ( isset( $config['smwgQueryDependencyPropertyExemptionList'] ) ) {
170 15
				$config['smwgQueryDependencyPropertyExemptionList'] = array_merge(
171 15
					$config['smwgQueryDependencyPropertyExemptionList'],
172 15
					$exemptionlist
173
				);
174
			}
175
176 15
			return true;
177
		};
178 1
	}
179
180 15
	public function onDataTypeInit( $dataTypeRegistry ) {
181
182 15
		$dataTypeRegistry->registerDatatype(
183 15
			'_sci_ref',
184 15
			'\SCI\DataValues\CitationReferenceValue',
185 15
			DataItem::TYPE_BLOB
186
		);
187
188
		$types = [
189 15
			'_sci_doi',
190
			'_sci_pmcid',
191
			'_sci_pmid',
192
			'_sci_oclc',
193
			'_sci_viaf',
194
			'_sci_olid'
195
		];
196
197 15
		foreach ( $types as $type ) {
198 15
			$dataTypeRegistry->registerDatatype(
199 15
				$type,
200 15
				'\SCI\DataValues\ResourceIdentifierStringValue',
201 15
				DataItem::TYPE_BLOB
202
			);
203
		}
204
205 15
		$callback = function() {
206 8
			return $this->citationReferencePositionJournal;
207 15
		};
208
209
		// SMW 3.1+
210 15
		if ( method_exists( $dataTypeRegistry, 'registerCallable' ) ) {
211 15
			$dataTypeRegistry->registerCallable( '_sci_ref', 'sci.citationreferencepositionjournal', $callback );
212
		} else {
213
			$dataTypeRegistry->registerExtraneousFunction(
214
				'\SCI\CitationReferencePositionJournal',
215
				$callback
216
			);
217
		}
218
219 15
		return true;
220
	}
221
222 16
	private function addCallbackHandlers( $store, $cache, $options ) {
223
224 16
		$propertyRegistry = new PropertyRegistry();
225 16
		$namespaceExaminer = ApplicationFactory::getInstance()->getNamespaceExaminer();
226
227 16
		$cacheKeyProvider = new CacheKeyProvider();
228 16
		$cacheKeyProvider->setCachePrefix( $options->get( 'cachePrefix' ) );
229
230 16
		$this->citationReferencePositionJournal = new CitationReferencePositionJournal(
231 16
			$cache,
232 16
			$cacheKeyProvider
233
		);
234
235 16
		$referenceBacklinksLookup = new ReferenceBacklinksLookup( $store );
236
237
		/**
238
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks/SMW::Property::initProperties
239
		 */
240 15
		$this->handlers['SMW::Property::initProperties'] = function ( $corePropertyRegistry ) use ( $propertyRegistry ) {
241 15
			return $propertyRegistry->registerTo( $corePropertyRegistry );
242
		};
243
244
		/**
245
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks/SMW::DataType::initTypes
246
		 */
247 16
		$this->handlers['SMW::DataType::initTypes'] = [ $this, 'onDataTypeInit' ];
248
249
		/**
250
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks/SMW::Browse::AfterIncomingPropertiesLookupComplete
251
		 */
252 1
		$this->handlers['SMW::Browse::AfterIncomingPropertiesLookupComplete'] = function ( $store, $semanticData, $requestOptions ) use ( $referenceBacklinksLookup ) {
253
254 1
			$referenceBacklinksLookup->setRequestOptions( $requestOptions );
255 1
			$referenceBacklinksLookup->setStore( $store );
256
257 1
			$referenceBacklinksLookup->addReferenceBacklinksTo(
258 1
				$semanticData
259
			);
260
261 1
			return true;
262
		};
263
264 1
		$this->handlers['SMW::Browse::BeforeIncomingPropertyValuesFurtherLinkCreate'] = function ( $property, $subject, &$html ) use ( $referenceBacklinksLookup ) {
265 1
			return $referenceBacklinksLookup->getSpecialPropertySearchFurtherLink( $property, $subject, $html );
266
		};
267
268
		/**
269
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks/SMW::Parser::BeforeMagicWordsFinder
270
		 */
271 15
		$this->handlers['SMW::Parser::BeforeMagicWordsFinder'] = function( array &$magicWords ) {
272 15
			$magicWords = array_merge( $magicWords, [ 'SCI_NOREFERENCELIST' ] );
273 15
			return true;
274
		};
275
276
		/**
277
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks/SMW::SQLStore::AddCustomFixedPropertyTables
278
		 */
279 14
		$this->handlers['SMW::SQLStore::AddCustomFixedPropertyTables'] = function( array &$customFixedProperties ) use( $propertyRegistry ) {
280
281
			$properties = [
282 14
				$propertyRegistry::SCI_CITE_KEY,
283 14
				$propertyRegistry::SCI_CITE_REFERENCE,
284 14
				$propertyRegistry::SCI_CITE_TEXT,
285 14
				$propertyRegistry::SCI_CITE,
286 14
				$propertyRegistry::SCI_DOI,
287 14
				$propertyRegistry::SCI_PMCID,
288 14
				$propertyRegistry::SCI_PMID,
289 14
				$propertyRegistry::SCI_OCLC,
290 14
				$propertyRegistry::SCI_VIAF,
291 14
				$propertyRegistry::SCI_OLID
292
			];
293
294 14
			foreach ( $properties as $property ) {
295 14
				$customFixedProperties[$property] = str_replace( '__', '_', $property );
296
			}
297
298 14
			return true;
299
		};
300
301
		/**
302
		 * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforePageDisplay
303
		 */
304 1
		$this->handlers['BeforePageDisplay'] = function ( &$outputPage, &$skin ) use( $namespaceExaminer ) {
0 ignored issues
show
Unused Code introduced by
The parameter $skin 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...
305
306 1
			if ( !$namespaceExaminer->isSemanticEnabled( $outputPage->getTitle()->getNamespace() ) ) {
307
				return true;
308
			}
309
310 1
			$outputPage->addModuleStyles( 'ext.scite.styles' );
311
312 1
			$outputPage->addModules(
313
				[
314 1
					'ext.scite.styles',
315
					'ext.scite.tooltip'
316
				]
317
			);
318
319 1
			return true;
320
		};
321
322
		/**
323
		 * @note This is bit of a hack but there is no other way to get access to
324
		 * the ParserOutput so that it can be used in OutputPageBeforeHTML
325
		 *
326
		 * @see https://www.mediawiki.org/wiki/Manual:Hooks/OutputPageParserOutput
327
		 */
328 10
		$this->handlers['OutputPageParserOutput'] = function( &$outputPage, $parserOutput ) {
329 10
			$outputPage->smwmagicwords = $parserOutput->getExtensionData( 'smwmagicwords' );
330 10
			return true;
331
		};
332
333
		/**
334
		 * @see https://www.mediawiki.org/wiki/Manual:Hooks/OutputPageBeforeHTML
335
		 */
336 10
		$this->handlers['OutputPageBeforeHTML'] = function( &$outputPage, &$text ) use ( $store, $namespaceExaminer, $cache, $cacheKeyProvider, $options ) {
337
338 10
			$referenceListFactory = new ReferenceListFactory(
339 10
				$store,
340 10
				$namespaceExaminer,
341 10
				$this->citationReferencePositionJournal
342
			);
343
344 10
			$cachedReferenceListOutputRenderer = $referenceListFactory->newCachedReferenceListOutputRenderer(
345 10
				new MediaWikiContextInteractor( $outputPage->getContext() ),
346 10
				$cache,
347 10
				$cacheKeyProvider,
348 10
				$options
349
			);
350
351 10
			$cachedReferenceListOutputRenderer->addReferenceListToText( $text );
352
353 10
			return true;
354
		};
355
356
		/**
357
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks#SMWStore::updateDataBefore
358
		 */
359 15
		$this->handlers['SMWStore::updateDataBefore'] = function ( $store, $semanticData ) use ( $cache, $cacheKeyProvider ) {
360
361 15
			$hash = $semanticData->getSubject()->getHash();
362
363
			// No remaining reference means it is time to purge the cache once
364
			// more because as long as a CiteRef exists, CitationReferencePositionJournal
365
			// is able recompute and update the entries but with no CiteRef left
366
			// the last entry will remain and needs to be purged at this point
367 15
			if ( !$this->citationReferencePositionJournal->hasCitationReference( $semanticData ) ) {
368 14
				$cache->delete(
369 14
					$cacheKeyProvider->getCacheKeyForCitationReference( $hash )
370
				);
371
			}
372
373 15
			$cache->delete(
374 15
				$cacheKeyProvider->getCacheKeyForReferenceList( $hash )
375
			);
376
377 15
			return true;
378
		};
379
380
		/**
381
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks#SMW::SQLStore::AfterDeleteSubjectComplete
382
		 */
383 15
		$this->handlers['SMW::SQLStore::AfterDeleteSubjectComplete'] = function ( $store, $title ) use ( $cache, $cacheKeyProvider ) {
384
385 15
			$hash = DIWikiPage::newFromTitle( $title )->getHash();
386
387 15
			$cache->delete(
388 15
				$cacheKeyProvider->getCacheKeyForCitationReference( $hash )
389
			);
390
391 15
			$cache->delete(
392 15
				$cacheKeyProvider->getCacheKeyForReferenceList( $hash )
393
			);
394
395 15
			return true;
396
		};
397
398
		/**
399
		 * @see https://www.semantic-mediawiki.org/wiki/Hooks#SMW::SQLStore::AfterDataUpdateComplete
400
		 */
401 15
		$this->handlers['SMW::SQLStore::AfterDataUpdateComplete'] = function ( $store, $semanticData, $compositePropertyTableDiffIterator ) use ( $referenceBacklinksLookup, $options ) {
402
403 15
			$referenceBacklinksLookup->setStore( $store );
404
405 15
			$citationTextChangeUpdateJobDispatcher = new CitationTextChangeUpdateJobDispatcher(
406 15
				$store,
407 15
				$referenceBacklinksLookup
408
			);
409
410 15
			$citationTextChangeUpdateJobDispatcher->setEnabledUpdateJobState(
411 15
				$options->get( 'enabledCitationTextChangeUpdateJob' )
412
			);
413
414 15
			$citationTextChangeUpdateJobDispatcher->dispatchUpdateJobFor(
415 15
				$semanticData->getSubject(),
416 15
				$compositePropertyTableDiffIterator
417
			);
418
419 15
			return true;
420
		};
421
422
		/**
423
		 * @see https://www.mediawiki.org/wiki/Manual:Hooks/ResourceLoaderGetConfigVars
424
		 */
425 1
		$this->handlers['ResourceLoaderGetConfigVars'] = function ( &$vars ) use ( $options ) {
426
427 1
			$vars['ext.scite.config'] = [
428 1
				'showTooltipForCitationReference' => $options->get( 'showTooltipForCitationReference' ),
429 1
				'tooltipRequestCacheTTL' => $options->get( 'tooltipRequestCacheTTL' ),
430 1
				'cachePrefix' => $options->get( 'cachePrefix' )
431
			];
432
433 1
			return true;
434
		};
435
436
		/**
437
		 * @see https://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit
438
		 */
439 1
		$this->handlers['ParserFirstCallInit'] = function ( &$parser ) use ( $namespaceExaminer, $options ) {
440
441 1
			$parserFunctionFactory = new ParserFunctionFactory();
442
443 1
			list( $name, $definition, $flag ) = $parserFunctionFactory->newSciteParserFunctionDefinition(
444 1
				$namespaceExaminer,
445 1
				$options
446
			);
447
448 1
			$parser->setFunctionHook( $name, $definition, $flag );
449
450 1
			list( $name, $definition, $flag ) = $parserFunctionFactory->newReferenceListParserFunctionDefinition();
451
452 1
			$parser->setFunctionHook( $name, $definition, $flag );
453
454 1
			return true;
455
		};
456 16
	}
457
458
}
459