Completed
Push — master ( 7aacb2...2b39b6 )
by
unknown
06:55
created

ApplicationFactory   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Test Coverage

Coverage 95.08%

Importance

Changes 0
Metric Value
wmc 24
lcom 2
cbo 4
dl 0
loc 222
ccs 58
cts 61
cp 0.9508
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 7 2
A __construct() 0 5 1
A getComponentLibrary() 0 3 1
A getNestingController() 0 3 1
A getNewAttributeManager() 0 3 1
A getNewModalBuilder() 0 3 1
A getNewParserRequest() 0 3 1
A getParserOutputHelper() 0 6 2
A registerApplication() 0 12 4
A resetLookup() 0 10 3
A getApplication() 0 18 4
A getApplicationClassRegister() 0 7 1
A getLogger() 0 6 2
1
<?php
2
/**
3
 * Contains the class controlling the references and creating necessary helper objects.
4
 *
5
 * @copyright (C) 2018, Tobias Oetterer, Paderborn University
6
 * @license       https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later)
7
 *
8
 * This file is part of the MediaWiki extension BootstrapComponents.
9
 * The BootstrapComponents extension is free software: you can redistribute it
10
 * and/or modify it under the terms of the GNU General Public License as published
11
 * by the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * The BootstrapComponents extension is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 *
22
 * @file
23
 * @ingroup       BootstrapComponents
24
 * @author        Tobias Oetterer
25
 */
26
27
namespace BootstrapComponents;
28
29
use MediaWiki\Logger\LoggerFactory;
30
use MWException;
31
use ReflectionClass;
32
33
/**
34
 * Class ApplicationFactory
35
 *
36
 * Manages access to application classes.
37
 *
38
 * @since 1.0
39
 */
40
class ApplicationFactory {
41
42
	/**
43
	 * @var ApplicationFactory $instance
44
	 */
45
	private static $instance = null;
46
47
	/**
48
	 * Holds the application singletons
49
	 *
50
	 * @var array $applicationStore
51
	 */
52
	private $applicationStore;
53
54
	/**
55
	 * Library, that tells the ApplicationFactory, which class to use to instantiate which application
56
	 *
57
	 * @var array $applicationClassRegister
58
	 */
59
	private $applicationClassRegister;
60
61
	/**
62
	 * @var \Psr\Log\LoggerInterface $logger
63
	 */
64
	private $logger;
65 20
66 20
	/**
67 20
	 * Returns the singleton instance
68
	 *
69
	 * @return ApplicationFactory
70
	 */
71
	public static function getInstance() {
72
		if ( self::$instance !== null ) {
73
			return self::$instance;
74
		}
75
76
		return self::$instance = new self();
77
	}
78
79
	/**
80
	 * ApplicationFactory constructor.
81 18
	 *
82 18
	 * Do not instantiate directly, but use {@see ApplicationFactory::getInstance}
83 18
	 * instead.
84 18
	 *
85
	 * @see ApplicationFactory::getInstance
86
	 */
87
	public function __construct() {
88
		$this->applicationStore = [];
89
		$this->applicationClassRegister = $this->getApplicationClassRegister();
90
		$this->getLogger()->info( 'ApplicationFactory was build!' );
91
	}
92
93 18
	/**
94 18
	 * @param null|bool|array $componentWhiteList
95
	 *
96
	 * @throws MWException  cascading {@see \BootstrapComponents\ApplicationFactory::getApplication}
97
	 *
98
	 * @return ComponentLibrary
99
	 */
100
	public function getComponentLibrary( $componentWhiteList = null ) {
101
		return $this->getApplication( 'ComponentLibrary', $componentWhiteList );
102
	}
103
104 21
	/**
105 21
	 * @throws MWException  cascading {@see \BootstrapComponents\ApplicationFactory::getApplication}
106
	 *
107
	 * @return NestingController
108
	 */
109
	public function getNestingController() {
110
		return $this->getApplication( 'NestingController' );
111
	}
112
113
	/**
114
	 * @param string[] $validAttributes
115
	 * @param string[] $aliases
116
	 *
117
	 * @see AttributeManager::__construct
118 7
	 *
119 7
	 * @return AttributeManager
120
	 */
121
	public function getNewAttributeManager( $validAttributes, $aliases ) {
122
		return new AttributeManager( $validAttributes, $aliases );
123
	}
124
125
	/**
126
	 * @param string             $id
127 21
	 * @param string             $trigger must be safe raw html (best run through {@see Parser::recursiveTagParse})
128 21
	 * @param string             $content must be safe raw html (best run through {@see Parser::recursiveTagParse})
129
	 * @param ParserOutputHelper $parserOutputHelper
130
	 *
131
	 * @see ModalBuilder::__construct
132
	 *
133
	 * @return ModalBuilder
134
	 */
135
	public function getNewModalBuilder( $id, $trigger, $content, $parserOutputHelper ) {
136
		return new ModalBuilder( $id, $trigger, $content, $parserOutputHelper );
137
	}
138
139
	/**
140
	 * @param array  $argumentsPassedByParser
141
	 * @param bool   $isParserFunction
142 24
	 * @param string $componentName
143 24
	 *
144
	 * @see ParserRequest::__construct
145
	 *
146
	 * @throws \MWException cascading {@see ParserRequest::__construct}
147
	 *
148
	 * @return ParserRequest
149
	 */
150
	public function getNewParserRequest( $argumentsPassedByParser, $isParserFunction, $componentName = 'unknown' ) {
151
		return new ParserRequest( $argumentsPassedByParser, $isParserFunction, $componentName );
152
	}
153
154
	/**
155 22
	 * @param \Parser $parser
156 22
	 *
157 21
	 * @see ParserOutputHelper
158 21
	 *
159 22
	 * @throws MWException  cascading {@see \BootstrapComponents\ApplicationFactory::getApplication}
160
	 *
161
	 * @return ParserOutputHelper
162
	 */
163
	public function getParserOutputHelper( $parser = null ) {
164
		if ( $parser === null ) {
165
			$parser = $GLOBALS['wgParser'];
166
		}
167
		return $this->getApplication( 'ParserOutputHelper', $parser );
168
	}
169
170
	/**
171
	 * Registers an application with the ApplicationFactory.
172 3
	 *
173 3
	 * @param string $name
174 3
	 * @param string $class
175 3
	 *
176 1
	 * @throws MWException when class to register does not exist
177 1
	 *
178 2
	 * @return bool
179 1
	 */
180
	public function registerApplication( $name, $class ) {
181 1
		$application = trim( $name );
182 1
		$applicationClass = trim( $class );
183 1
		if ( $application != '' && class_exists( $applicationClass ) ) {
184 1
			$this->applicationClassRegister[$application] = $applicationClass;
185 1
			return true;
186
		} elseif ( $application != '' ) {
187
			throw new MWException( 'ApplicationFactory was requested to register non existing class "' . $applicationClass . '"!' );
188
		}
189
		$this->getLogger()->error( 'ApplicationFactory was requested to register invalid application for class ' . $applicationClass . '!' );
190
		return false;
191
	}
192
193
	/**
194
	 * Resets the application $application (or all, if $application is null), so that the next call to
195
	 * {@see ApplicationFactory::getApplication} will create a new object.
196 24
	 *
197 24
	 * @param null|string $application
198 1
	 *
199 1
	 * @return bool
200 24
	 */
201 23
	public function resetLookup( $application = null ) {
202 23
		if ( is_null( $application ) ) {
203
			$this->applicationStore = [];
204 1
			return true;
205
		} elseif ( isset( $this->applicationStore[$application] ) ) {
206
			unset( $this->applicationStore[$application] );
207
			return true;
208
		}
209
		return false;
210
	}
211
212
	/**
213
	 * This returns the application $name. Creates a new instance and stores the singleton, if not already in store.
214
	 * You can supply any number of additional arguments to this function, they will be passed to the constructor.
215
	 *
216
	 * @param string $name
217 24
	 *
218 24
	 * @throws MWException  when no class is registered for the requested application or the creation of the object fails.
219 23
	 *
220
	 * @return mixed|object
221 24
	 */
222
	protected function getApplication( $name ) {
223
		if ( isset( $this->applicationStore[$name] ) ) {
224 24
			return $this->applicationStore[$name];
225 24
		}
226
		if ( !isset( $this->applicationClassRegister[$name] ) ) {
227
			throw new MWException( 'ApplicationFactory was requested to return application "' . $name . '". No appropriate class registered!' );
228 24
		}
229 24
		$args = func_get_args();
230
		array_shift( $args ); # because, we already used the first argument $name
231
232 24
		try {
233 24
			$objectReflection = new ReflectionClass( $this->applicationClassRegister[$name] );
234
		} catch ( \ReflectionException $e ) {
235
			throw new MWException( 'Error while trying to build application "' . $name . '" with class ' . $this->applicationClassRegister[$name] );
236
		}
237
		$this->getLogger()->info( 'ApplicationFactory successfully build application ' . $name );
238
		return $this->applicationStore[$name] = $objectReflection->newInstanceArgs( $args );
239 18
	}
240
241 18
	/**
242 18
	 * @return array
243 18
	 */
244 18
	protected function getApplicationClassRegister() {
245
		return [
246
			'ComponentLibrary'   => 'BootstrapComponents\\ComponentLibrary',
247
			'NestingController'  => 'BootstrapComponents\\NestingController',
248
			'ParserOutputHelper' => 'BootstrapComponents\\ParserOutputHelper',
249
		];
250
	}
251
252
	/**
253
	 * @return \Psr\Log\LoggerInterface
254
	 */
255
	protected function getLogger() {
256
		if ( !empty( $this->logger ) ) {
257
			return $this->logger;
258
		}
259
		return $this->logger = LoggerFactory::getInstance( 'BootstrapComponents' );
260
	}
261
}
262