Completed
Push — master ( 43acf6...5d1976 )
by mw
12s
created

ApplicationFactory::getCallbackInstantiator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace SMW;
4
5
use Closure;
6
use Onoi\CallbackContainer\CallbackLoader;
7
use Onoi\CallbackContainer\DeferredCallbackLoader;
8
use Parser;
9
use ParserOutput;
10
use SMW\Factbox\FactboxFactory;
11
use SMW\Maintenance\MaintenanceFactory;
12
use SMW\MediaWiki\Jobs\JobFactory;
13
use SMW\MediaWiki\MwCollaboratorFactory;
14
use SMW\MediaWiki\PageCreator;
15
use SMW\MediaWiki\TitleCreator;
16
use SMW\Query\ProfileAnnotator\QueryProfileAnnotatorFactory;
17
use SMWQueryParser as QueryParser;
18
use Title;
19
20
/**
21
 * Application instances access for internal and external use
22
 *
23
 * @license GNU GPL v2+
24
 * @since 2.0
25
 *
26
 * @author mwjames
27
 */
28
class ApplicationFactory {
29
30
	/**
31
	 * @var ApplicationFactory
32
	 */
33
	private static $instance = null;
34
35
	/**
36
	 * @var CallbackLoader
37
	 */
38
	private $callbackLoader = null;
39
40
	/**
41
	 * @since 2.0
42
	 */
43 267
	public function __construct( CallbackLoader $callbackLoader = null ) {
44 267
		$this->callbackLoader = $callbackLoader;
45 267
	}
46
47
	/**
48
	 * This method returns the global instance of the application factory.
49
	 *
50
	 * Reliance on global state is needed at entry points into SMW such as
51
	 * hook handlers, special pages and jobs, since there we tend to not
52
	 * have control over the object lifecycle. Pragmatically we might also
53
	 * want to use this when refactoring legacy code that already has the
54
	 * global state dependency. For new code very special justification is
55
	 * required to rely on global state.
56
	 *
57
	 * @since 2.0
58
	 *
59
	 * @return self
60
	 */
61 298
	public static function getInstance() {
62
63 298
		if ( self::$instance === null ) {
64 267
			self::$instance = new self( self::registerBuilder() );
65
		}
66
67 298
		return self::$instance;
68
	}
69
70
	/**
71
	 * @since 2.0
72
	 */
73 287
	public static function clear() {
74
75 287
		if ( self::$instance !== null ) {
76 287
			self::$instance->getSettings()->clear();
77
		}
78
79 287
		self::$instance = null;
80 287
	}
81
82
	/**
83
	 * @since 2.0
84
	 *
85
	 * @param string $objectName
86
	 * @param callable|array $objectSignature
87
	 */
88 245
	public function registerObject( $objectName, $objectSignature ) {
89 245
		$this->callbackLoader->registerObject( $objectName, $objectSignature );
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Onoi\CallbackContainer\CallbackLoader as the method registerObject() does only exist in the following implementations of said interface: Onoi\CallbackContainer\DeferredCallbackLoader.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
90 245
	}
91
92
	/**
93
	 * @private
94
	 *
95
	 * @since 2.4
96
	 *
97
	 * @return CallbackLoader
98
	 */
99 251
	public function getCallbackInstantiator() {
100 251
		return $this->callbackLoader;
101
	}
102
103
	/**
104
	 * @since 2.0
105
	 *
106
	 * @return SerializerFactory
107
	 */
108 166
	public function newSerializerFactory() {
109 166
		return new SerializerFactory();
110
	}
111
112
	/**
113
	 * @since 2.0
114
	 *
115
	 * @return FactboxFactory
116
	 */
117 4
	public function newFactboxFactory() {
118 4
		return $this->callbackLoader->load( 'FactboxFactory' );
119
	}
120
121
	/**
122
	 * @since 2.0
123
	 *
124
	 * @return PropertyAnnotatorFactory
125
	 */
126 155
	public function newPropertyAnnotatorFactory() {
127 155
		return new PropertyAnnotatorFactory();
128
	}
129
130
	/**
131
	 * @since 2.0
132
	 *
133
	 * @return JobFactory
134
	 */
135 169
	public function newJobFactory() {
136 169
		return $this->callbackLoader->load( 'JobFactory' );
137
	}
138
139
	/**
140
	 * @since 2.1
141
	 *
142
	 * @param Parser $parser
143
	 *
144
	 * @return ParserFunctionFactory
145
	 */
146 15
	public function newParserFunctionFactory( Parser $parser ) {
147 15
		return new ParserFunctionFactory( $parser );
148
	}
149
150
	/**
151
	 * @since 2.1
152
	 *
153
	 * @return QueryProfileAnnotatorFactory
154
	 */
155 53
	public function newQueryProfileAnnotatorFactory() {
156 53
		return new QueryProfileAnnotatorFactory();
157
	}
158
159
	/**
160
	 * @since 2.2
161
	 *
162
	 * @return MaintenanceFactory
163
	 */
164 6
	public function newMaintenanceFactory() {
165 6
		return new MaintenanceFactory();
166
	}
167
168
	/**
169
	 * @since 2.2
170
	 *
171
	 * @return CacheFactory
172
	 */
173 240
	public function newCacheFactory() {
174 240
		return $this->callbackLoader->load( 'CacheFactory', $this->getSettings()->get( 'smwgCacheType' ) );
0 ignored issues
show
Unused Code introduced by
The call to CallbackLoader::load() has too many arguments starting with $this->getSettings()->get('smwgCacheType').

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
175
	}
176
177
	/**
178
	 * @since 2.0
179
	 *
180
	 * @return Store
181
	 */
182 247
	public function getStore() {
183 247
		return $this->callbackLoader->singleton( 'Store' );
184
	}
185
186
	/**
187
	 * @since 2.0
188
	 *
189
	 * @return Settings
190
	 */
191 290
	public function getSettings() {
192 290
		return $this->callbackLoader->singleton( 'Settings' );
193
	}
194
195
	/**
196
	 * @since 2.0
197
	 *
198
	 * @return TitleCreator
199
	 */
200 6
	public function newTitleCreator() {
201 6
		return $this->callbackLoader->load( 'TitleCreator', $this->newPageCreator() );
0 ignored issues
show
Unused Code introduced by
The call to CallbackLoader::load() has too many arguments starting with $this->newPageCreator().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
202
	}
203
204
	/**
205
	 * @since 2.0
206
	 *
207
	 * @return PageCreator
208
	 */
209 159
	public function newPageCreator() {
210 159
		return $this->callbackLoader->load( 'PageCreator' );
211
	}
212
213
	/**
214
	 * @since 2.0
215
	 *
216
	 * @return Cache
217
	 */
218 146
	public function getCache() {
219 146
		return $this->callbackLoader->singleton( 'Cache' );
220
	}
221
222
	/**
223
	 * @since 2.0
224
	 *
225
	 * @return InTextAnnotationParser
226
	 */
227 153
	public function newInTextAnnotationParser( ParserData $parserData ) {
228
229 153
		$mwCollaboratorFactory = $this->newMwCollaboratorFactory();
230
231 153
		$inTextAnnotationParser = new InTextAnnotationParser(
232
			$parserData,
233 153
			$mwCollaboratorFactory->newMagicWordsFinder(),
234 153
			$mwCollaboratorFactory->newRedirectTargetFinder()
235
		);
236
237 153
		$inTextAnnotationParser->setStrictModeState(
238 153
			$this->getSettings()->get( 'smwgEnabledInTextAnnotationParserStrictMode' )
239
		);
240
241 153
		return $inTextAnnotationParser;
242
	}
243
244
	/**
245
	 * @since 2.0
246
	 *
247
	 * @return ParserData
248
	 */
249 169
	public function newParserData( Title $title, ParserOutput $parserOutput ) {
250 169
		return $this->callbackLoader->load( 'ParserData', $title, $parserOutput );
0 ignored issues
show
Unused Code introduced by
The call to CallbackLoader::load() has too many arguments starting with $title.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
251
	}
252
253
	/**
254
	 * @since 2.0
255
	 *
256
	 * @return ContentParser
257
	 */
258 30
	public function newContentParser( Title $title ) {
259 30
		return $this->callbackLoader->load( 'ContentParser', $title );
0 ignored issues
show
Unused Code introduced by
The call to CallbackLoader::load() has too many arguments starting with $title.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
260
	}
261
262
	/**
263
	 * @since 2.1
264
	 *
265
	 * @param SemanticData $semanticData
266
	 *
267
	 * @return StoreUpdater
268
	 */
269 155
	public function newStoreUpdater( SemanticData $semanticData ) {
270 155
		return new StoreUpdater( $this->getStore(), $semanticData );
271
	}
272
273
	/**
274
	 * @since 2.1
275
	 *
276
	 * @return MwCollaboratorFactory
277
	 */
278 209
	public function newMwCollaboratorFactory() {
279 209
		return new MwCollaboratorFactory( $this );
280
	}
281
282
	/**
283
	 * @since 2.1
284
	 *
285
	 * @return NamespaceExaminer
286
	 */
287 156
	public function getNamespaceExaminer() {
288 156
		return $this->callbackLoader->load( 'NamespaceExaminer' );
289
	}
290
291
	/**
292
	 * @since 2.4
293
	 *
294
	 * @return PropertySpecificationLookup
295
	 */
296 160
	public function getPropertySpecificationLookup() {
297 160
		return $this->callbackLoader->singleton( 'PropertySpecificationLookup' );
298
	}
299
300
	/**
301
	 * @since 2.4
302
	 *
303
	 * @return PropertyHierarchyLookup
304
	 */
305 93
	public function newPropertyHierarchyLookup() {
306 93
		return $this->callbackLoader->load( 'PropertyHierarchyLookup' );
307
	}
308
309
	/**
310
	 * @since 2.4
311
	 *
312
	 * @return CachedPropertyValuesPrefetcher
313
	 */
314 186
	public function getCachedPropertyValuesPrefetcher() {
315 186
		return $this->callbackLoader->singleton( 'CachedPropertyValuesPrefetcher' );
316
	}
317
318
	/**
319
	 * @since 2.4
320
	 *
321
	 * @return MediaWikiNsContentReader
322
	 */
323 166
	public function getMediaWikiNsContentReader() {
324 166
		return $this->callbackLoader->singleton( 'MediaWikiNsContentReader' );
325
	}
326
327
	/**
328
	 * @since 2.4
329
	 *
330
	 * @return InMemoryPoolCache
331
	 */
332 208
	public function getInMemoryPoolCache() {
333 208
		return InMemoryPoolCache::getInstance();
334
	}
335
336
	/**
337
	 * @since 2.4
338
	 *
339
	 * @param Closure $callback
340
	 *
341
	 * @return DeferredCallableUpdate
342
	 */
343 205
	public function newDeferredCallableUpdate( Closure  $callback ) {
344
345 205
		$deferredCallableUpdate = new DeferredCallableUpdate(
346
			$callback
347
		);
348
349 205
		$deferredCallableUpdate->enabledDeferredUpdate(
350 205
			$this->getSettings()->get( 'smwgEnabledDeferredUpdate' )
351
		);
352
353 205
		return $deferredCallableUpdate;
354
	}
355
356
	/**
357
	 * @since 2.1
358
	 *
359
	 * @return QueryParser
360
	 */
361 3
	public function newQueryParser() {
362 3
		return new QueryParser();
363
	}
364
365
	/**
366
	 * @since 2.4
367
	 *
368
	 * @return QueryFactory
369
	 */
370 167
	public function newQueryFactory() {
371 167
		return new QueryFactory();
372
	}
373
374 267
	private static function registerBuilder( CallbackLoader $callbackLoader = null ) {
375
376 267
		if ( $callbackLoader === null ) {
377 267
			$callbackLoader = new DeferredCallbackLoader( new SharedCallbackContainer() );
378
		}
379
380 267
		return $callbackLoader;
381
	}
382
383
}
384