Completed
Push — master ( 84255c...a7d7e4 )
by Thomas
14:38
created

ModuleManager   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 308
Duplicated Lines 6.82 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 45
c 1
b 0
f 0
lcom 1
cbo 7
dl 21
loc 308
rs 8.3673

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 19 3
A getSubscribedEvents() 0 9 1
A moduleUninstalled() 0 4 1
A moduleUpdated() 0 7 2
A moduleActivated() 0 4 1
A moduleDeactivated() 0 4 1
A isInstalled() 0 3 1
A isActivated() 0 3 1
B load() 0 30 5
A loadTranslations() 0 22 1
C installActions() 0 37 8
B getGroup() 21 21 7
D installApi() 0 41 10
A deactivate() 0 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ModuleManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ModuleManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace keeko\core\package;
3
4
use keeko\core\exceptions\ModuleException;
5
use keeko\core\model\Action;
6
use keeko\core\model\Api;
7
use keeko\core\model\Group;
8
use keeko\core\model\GroupQuery;
9
use keeko\core\model\Module;
10
use keeko\core\model\ModuleQuery;
11
use keeko\core\service\ServiceContainer;
12
use phootwork\collection\Map;
13
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
14
use keeko\core\events\ModuleEvent;
15
16
class ModuleManager implements EventSubscriberInterface {
17
	
18
	/** @var Map */
19
	private $loadedModules;
20
21
	/** @var Map */
22
	private $activatedModules;
23
24
	/** @var Map */
25
	private $installedModules;
26
	
27
	/** @var ServiceContainer */
28
	private $service;
29
	
30
	public function __construct(ServiceContainer $service) {
31
		$this->service = $service;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 10 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
32
		$this->loadedModules = new Map();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
33
		$this->activatedModules = new Map();
34
		$this->installedModules = new Map();
35
		
36
		$dispatcher = $service->getDispatcher();
37
		$dispatcher->addSubscriber($this);
38
		
39
		// load modules
40
		$modules = ModuleQuery::create()->find();
41
		
42
		foreach ($modules as $module) {
43
			$this->installedModules->set($module->getName(), $module);
44
			if ($module->getActivatedVersion() !== null) {
45
				$this->activatedModules->set($module->getName(), $module);
46
			}
47
		}
48
	}
49
	
50
	/**
51
	 * {@inheritDoc}
52
	 */
53
	public static function getSubscribedEvents() {
54
		return [
55
			ModuleEvent::INSTALLED => 'moduleUpdated',
56
			ModuleEvent::UNINSTALLED => 'moduleUninstalled',
57
			ModuleEvent::UPDATED => 'moduleUpdated',
58
			ModuleEvent::ACTIVATED => 'moduleActivated',
59
			ModuleEvent::DEACTIVATED => 'moduleDeactivated'
60
		];
61
	}
62
	
63
	public function moduleUninstalled(ModuleEvent $e) {
64
		$module = $e->getModule();
65
		$this->installedModules->remove($module->getName());
66
	}
67
	
68
	public function moduleUpdated(ModuleEvent $e) {
69
		$module = $e->getModule();
70
		$this->installedModules->set($module->getName(), $module);
71
		if ($this->activatedModules->has($module->getName())) {
72
			$this->activatedModules->set($module->getName(), $module);
73
		}
74
	}
75
	
76
	public function moduleActivated(ModuleEvent $e) {
77
		$module = $e->getModule();
78
		$this->activatedModules->set($module->getName(), $module);
79
	}
80
	
81
	public function moduleDeactivated(ModuleEvent $e) {
82
		$module = $e->getModule();
83
		$this->activatedModules->remove($module->getName());
84
	}
85
	
86
	/**
87
	 * Returns whether the given package name is an installed module
88
	 *
89
	 * @param string $packageName
90
	 * @return boolean
91
	 */
92
	public function isInstalled($packageName) {
93
		return $this->installedModules->has($packageName);
94
	}
95
	
96
	/**
97
	 * Returns whether the given package name is an activated module
98
	 *
99
	 * @param string $packageName
100
	 * @return boolean
101
	 */
102
	public function isActivated($packageName) {
103
		return $this->activatedModules->has($packageName);
104
	}
105
106
	
107
	// public function getInstalledModules() {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
108
	// return $this->installedModules;
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
109
	// }
110
	
111
	// public function getActivatedModules() {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
112
	// return $this->activatedModules;
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
113
	// }
114
	
115
	/**
116
	 * Loads a module and returns the associated class or returns if already loaded
117
	 *
118
	 * @param String $packageName
119
	 * @throws ModuleException
120
	 * @return AbstractModule
121
	 */
122
	public function load($packageName) {
123
		if ($this->loadedModules->has($packageName)) {
124
			return $this->loadedModules->get($packageName);
125
		}
126
		
127
		// check existence
128
		if (!$this->installedModules->has($packageName)) {
129
			throw new ModuleException(sprintf('Module (%s) does not exist.', $packageName), 500);
130
		}
131
		
132
		// check activation
133
		if (!$this->activatedModules->has($packageName)) {
134
			throw new ModuleException(sprintf('Module (%s) not activated', $packageName), 501);
135
		}
136
		
137
		$model = $this->activatedModules->get($packageName);
138
		
139
		if ($model->getInstalledVersion() > $model->getActivatedVersion()) {
140
			throw new ModuleException(sprintf('Module Version Mismatch (%s). Module needs to be updated by the Administrator', $packageName), 500);
141
		}
142
		
143
		// load
144
		$className = $model->getClassName();
145
		
146
		/* @var $module AbstractModule */
147
		$module = new $className($model, $this->service);
148
		$this->loadedModules->set($packageName, $module);
149
		
150
		return $module;
151
	}
152
	
153
	/**
154
	 * @TODO still old api
155
	 * @param string $packageName
156
	 */
157
	public function loadTranslations($packageName) {
0 ignored issues
show
Unused Code introduced by
The parameter $packageName 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...
158
		// load l10n
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
159
// 		$app = $this->service->getKernel()->getApplication();
160
// 		$translator = $this->service->getTranslator();
161
// 		$lang = $app->getLocalization()->getLanguage()->getAlpha2();
162
// 		$country = $app->getLocalization()->getCountry()->getAlpha2();
163
// 		$l10n = $mod->getPath() . 'l10n/';
164
// 		$locale = $lang . '_' . $country;
165
		
166
		
167
		
168
// 		$langPath = sprintf('%s%s/module.json', $l10n, $lang);
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
169
// 		$localePath = sprintf('%s%s/module.json', $l10n, $locale);
170
		
171
// 		if (file_exists($langPath)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
172
// 			$translator->addResource('json', $langPath, $lang, $mod->getCanonicalName());
173
// 		}
174
		
175
// 		if (file_exists($localePath)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
176
// 			$translator->addResource('json', $langPath, $locale, $mod->getCanonicalName());
177
// 		}
178
	}
179
180
// 	public function update($packageName) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
181
// 		if (!$this->installedModules->has($packageName)) {
182
// 			throw new ModuleException(sprintf('Module (%s) not installed for activation', $packageName));
183
// 		}
184
// 		$model = $this->installedModules->get($packageName);
185
// 		$model->setActivatedVersion($model->getInstalledVersion());
186
// 		$model->save();
187
// 		$module = $this->service->getPackageManager()->getModuleSchema($packageName);
188
		
189
// 		// install actions
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
190
// 		$extra = $package->getExtra();
191
// 		if (isset($extra['keeko']) && isset($extra['keeko']['module'])) {
192
// 			$actions = $this->installActions($model, $extra['keeko']['module']);
193
// 			$this->installApi($model, $extra['keeko']['module'], $actions);
194
// 		}
195
// 	}
196
197
	private function installActions(Module $module, $data) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
198
		if (!isset($data['actions'])) {
199
			return;
200
		}
201
		
202
		$actions = [];
203
		
204
		foreach ($data['actions'] as $name => $options) {
205
			$a = new Action();
206
			$a->setName($name);
207
			$a->setModule($module);
208
			
209
			if (isset($options['title'])) {
210
				$a->setTitle($options['title']);
211
			}
212
			
213
			if (isset($options['description'])) {
214
				$a->setDescription($options['description']);
215
			}
216
			
217
			if (isset($options['class'])) {
218
				$a->setClassName($options['class']);
219
			}
220
			
221
			// add acl
222
			if (isset($options['acl'])) {
223
				foreach ($options['acl'] as $group) {
224
					$a->addGroup($this->getGroup($group));
225
				}
226
			}
227
			
228
			$a->save();
229
			$actions[$name] = $a->getId();
230
		}
231
		
232
		return $actions;
233
	}
234
	
235
	/**
236
	 * @param string $name
237
	 * @return Group
238
	 */
239 View Code Duplication
	private function getGroup($name) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
		switch ($name) {
241
			case 'guest':
242
				if ($this->guestGroup === null) {
243
					$this->guestGroup = GroupQuery::create()->filterByIsGuest(true)->findOne();
244
				}
245
				return $this->guestGroup;
246
247
			case 'user':
248
				if ($this->userGroup === null) {
249
					$this->userGroup = GroupQuery::create()->filterByIsDefault(true)->findOne();
250
				}
251
				return $this->userGroup;
252
				
253
			case 'admin':
254
				if ($this->adminGroup === null) {
255
					$this->adminGroup = GroupQuery::create()->findOneById(3);
256
				}
257
				return $this->adminGroup;
258
		}
259
	}
260
261
	private function installApi(Module $module, $data, $actionMap) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
262
		if (!isset($data['api'])) {
263
			return;
264
		}
265
		
266
		if (!isset($data['api']['apis'])) {
267
			return;
268
		}
269
		
270
		$base = '/';
271
		if (isset($data['api']['resourcePath'])) {
272
			$base = $data['api']['resourcePath'];
273
		}
274
		
275
		foreach ($data['api']['apis'] as $apis) {
276
			$path = $apis['path'];
277
			foreach ($apis['operations'] as $op) {
278
				// fetch required params
279
				$required = [];
280
				if (isset($op['parameters'])) {
281
					foreach ($op['parameters'] as $param) {
282
						if (isset($param['paramType']) && $param['paramType'] == 'path') {
283
							$required[] = $param['name'];
284
						}
285
					}
286
				}
287
				
288
				// create record
289
				$fullPath = str_replace('//', '/', $base . '/' . $path);
290
				$api = new Api();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
291
				$api->setMethod($op['method']);
292
				$api->setRoute($fullPath);
293
				$api->setActionId($actionMap[$op['nickname']]);
294
				$api->setRequiredParams(implode(',', $required));
295
				$api->save();
296
			}
297
		}
298
		
299
		$module->setApi(true);
300
		$module->save();
301
	}
302
303
	public function deactivate($packageName) {
304
		if (array_key_exists($packageName, $this->activatedModules) && !array_key_exists($packageName, $this->installedModules)) {
305
			
306
			$mod = ModuleQuery::create()->filterByName($packageName)->findOne();
307
			$mod->setActivatedVersion(null);
308
			$mod->save();
309
			
310
			unset($this->activatedModules[$packageName]);
311
		}
312
	}
313
	
314
	// /**
315
	// * Returns wether a module was loaded
316
	// *
317
	// * @param String $packageName
318
	// * @return boolean true if loaded, false if not
319
	// */
320
	// public function isLoaded($packageName) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
321
	// return array_key_exists($packageName, $this->loadedModules);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
322
	// }
323
}
324