Completed
Push — master ( 1dd58a...87fd77 )
by Karsten
06:09
created

HookRegistry::initExtension()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

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