Completed
Push — master ( 8cad24...404a00 )
by mw
07:20
created

HookRegistry::onDataTypeInit()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 3.0137

Importance

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