Completed
Push — master ( f0b491...11ee78 )
by Thomas
09:37
created

ModuleInstaller::updateApi()   C

Complexity

Conditions 10
Paths 11

Size

Total Lines 80
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 80
ccs 0
cts 0
cp 0
rs 5.5471
cc 10
eloc 35
nc 11
nop 3
crap 110

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace keeko\core\installer;
3
4
use Composer\IO\IOInterface;
5
use gossi\swagger\Parameter;
6
use gossi\swagger\Path;
7
use gossi\swagger\Swagger;
8
use keeko\core\events\ModuleEvent;
9
use keeko\core\model\Action;
10
use keeko\core\model\ActionQuery;
11
use keeko\core\model\Api;
12
use keeko\core\model\ApiQuery;
13
use keeko\core\model\Group;
14
use keeko\core\model\GroupQuery;
15
use keeko\core\model\Module;
16
use keeko\core\model\ModuleQuery;
17
use keeko\core\package\ModuleManager;
18
use keeko\core\schema\ModuleSchema;
19
use keeko\core\service\ServiceContainer;
20
use phootwork\json\Json;
21
use Propel\Runtime\ActiveQuery\Criteria;
22
23
class ModuleInstaller extends AbstractPackageInstaller {
24
	
25
	/** @var ModuleManager */
26
	private $manager;
27
	
28
	/** @var Group */
29
	private $guestGroup;
30
	
31
	/** @var Group */
32
	private $userGroup;
33
	
34
	/** @var Group */
35
	private $adminGroup;
36
	
37
	public function __construct(ServiceContainer $service) {
38
		parent::__construct($service);
39
		$this->manager = $this->service->getModuleManager();
40
	}
41
42
	public function install(IOInterface $io, $packageName) {
43
		$io->write('[Keeko] Install Module: ' . $packageName);
44
		
45
		$package = $this->getPackageSchema($packageName);
46
		$keeko = $package->getKeeko();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 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...
47
		
48
		if ($keeko->isModule()) {
49
			$pkg = $keeko->getModule();
50
51
			// create module
52
			$model = new Module();
53
			$model->setClassName($pkg->getClass());
54
			$model->setSlug($pkg->getSlug());
55
			$this->updatePackage($model, $pkg);
56
			
57
			// run module -> install
58
			$className = $pkg->getClass();
59
			$class = new $className($model, $this->service);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 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...
60
			$class->install();
61
			
62
			$this->dispatcher->dispatch(ModuleEvent::INSTALLED, new ModuleEvent($model));
63
		}
64
	}
65
66
	public function update(IOInterface $io, $packageName, $from, $to) {
67
		$io->write(sprintf('[Keeko] Update Module: %s from %s to %s', $packageName, $from, $to));
68
		
69
		// retrieve module
70
		$model = ModuleQuery::create()->findOneByName($packageName);
71
		$this->updatePackage($model, $packageName);
72
		
73
		// run module -> update
74
		$className = $model->getClass();
75
		$class = new $className($model, $this->service);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 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...
76
		$class->update($from, $to);
77
		
78
		// update api and actions
79
		if ($this->manager->isActivated($packageName)) {
80
			$this->updateModule($model);
81
		}
82
		
83
		$this->dispatcher->dispatch(ModuleEvent::UPDATED, new ModuleEvent($model));
84
	}
85
86
	public function uninstall(IOInterface $io, $packageName) {
87
		$io->write('[Keeko] Uninstall Module: ' . $packageName);
88
89
		// retrieve module
90
		$model = ModuleQuery::create()->findOneByName($packageName);
91
92
		// delete if found
93
		if ($model !== null) {
94
			$model->delete();
95
			
96
			// TODO: Check if api and actions are also deleted (by the call above)
97
		}
98
99
		$this->dispatcher->dispatch(ModuleEvent::UNINSTALLED, new ModuleEvent($model));
100
	}
101
	
102
	public function activate(IOInterface $io, $packageName) {
103
		$io->write('[Keeko] Activate Module: ' . $packageName);
104
		
105
		$package = $this->service->getPackageManager()->getComposerPackage($packageName);
106
		
107
		$model = ModuleQuery::create()->findOneByName($packageName);
108
		$model->setActivatedVersion($package->getPrettyVersion());
109
		$model->save();
110
		
111
		$this->updateModule($model);
112
	}
113
	
114
	private function updateModule(Module $model) {
115
		$package = $this->service->getPackageManager()->getPackage($model->getName());
116
		$keeko = $package->getKeeko();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 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...
117
118
		if ($keeko->isModule()) {
119
			$module = $keeko->getModule();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 2 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...
120
			$actions = $this->updateActions($model, $module);
121
			$this->updateApi($model, $module, $actions);
122
		}
123
	}
124
	
125
	private function updateActions(Module $model, ModuleSchema $module) {
126
		$actions = [];
127
	
128
		foreach ($module->getActionNames() as $name) {
129
			$action = $module->getAction($name);
130
			$a = new Action();
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...
131
			$a->setName($name);
132
			$a->setModule($model);
133
			$a->setTitle($action->getTitle());
134
			$a->setDescription($action->getDescription());
135
			$a->setClassName($action->getClass());
136
				
137
			// add acl
138
			foreach ($action->getAcl() as $group) {
139
				$a->addGroup($this->getGroup($group));
140
			}
141
				
142
			$a->save();
143
			$actions[$name] = $a->getId();
144
		}
145
		
146
		// remove obsolete actions
147
		ActionQuery::create()
148
			->filterByModule($model)
149
			->where('Action.Name NOT IN ?', $module->getActionNames()->toArray())
150
			->delete();
151
152
		return $actions;
153
	}
154
	
155
	/**
156
	 * @param string $name
157
	 * @return Group
158
	 */
159 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...
160
		switch ($name) {
161
			case 'guest':
162
				if ($this->guestGroup === null) {
163
					$this->guestGroup = GroupQuery::create()->filterByIsGuest(true)->findOne();
164
				}
165
				return $this->guestGroup;
166
	
167
			case 'user':
168
				if ($this->userGroup === null) {
169
					$this->userGroup = GroupQuery::create()->filterByIsDefault(true)->findOne();
170
				}
171
				return $this->userGroup;
172
	
173
			case 'admin':
174
				if ($this->adminGroup === null) {
175
					$this->adminGroup = GroupQuery::create()->findOneById(3);
176
				}
177
				return $this->adminGroup;
178
		}
179
	}
180
	
181
	private function updateApi(Module $model, ModuleSchema $module, $actions) {
182
		$repo = $this->service->getResourceRepository();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 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...
183
		$filename = sprintf('/packages/%s/api.json', $model->getName());
184
		if (!$repo->contains($filename)) {
185
			return;
186
		}
187
188
		// delete every api existent for the given module prior to create the new ones
189
		ApiQuery::create()
190
			->filterBy('ActionId', array_values($actions), Criteria::IN)
191
			->deleteAll()
192
		;
193
	
194
		$extensions = $this->service->getExtensionRegistry()->getExtensionsByPackage('keeko.api', $model->getName());
195
		$methods = ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'HEAD', 'PATCH'];
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...
196
		$json = Json::decode($repo->get($filename)->getBody());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Puli\Repository\Api\Resource\PuliResource as the method getBody() does only exist in the following implementations of said interface: Puli\Repository\Resource\FileResource.

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...
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 7 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...
197
		$swagger = new Swagger($json);
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...
198
		foreach ($swagger->getPaths() as $path) {
0 ignored issues
show
Bug introduced by
The expression $swagger->getPaths() of type object<gossi\swagger\collections\Paths> is not traversable.
Loading history...
199
			/* @var $path Path */
200
			foreach ($methods as $method) {
201
				if ($path->hasOperation($method)) {
202
					$op = $path->getOperation($method);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 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...
203
					$actionName = $op->getOperationId();
204
205
					if (!isset($actions[$actionName])) {
206
						continue;
207
					}
208
					
209
					// find required parameters
210
					$required = [];
211
					
212
					foreach ($op->getParameters() as $param) {
0 ignored issues
show
Bug introduced by
The expression $op->getParameters() of type object<gossi\swagger\collections\Parameters> is not traversable.
Loading history...
213
						/* @var $param Parameter */
214
						if ($param->getIn() == 'path' && $param->getRequired()) {
215
							$required[] = $param->getName();
216
						}
217
					}
218
					
219
					$prefix = isset($extensions[$actionName])
220
						? $extensions[$actionName]
221
						: $module->getSlug();
222
					
223
					$fullPath = str_replace('//', '/', $prefix . '/' . $path->getPath());
224
					$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...
225
					$api->setMethod($method);
226
					$api->setRoute($fullPath);
227
					$api->setActionId($actions[$actionName]);
228
					$api->setRequiredParams(implode(',', $required));
229
					$api->save();
230
				}
231
			}
232
		}
233
234
// 		foreach ($data['api']['apis'] as $apis) {
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...
235
// 			$path = $apis['path'];
236
// 			foreach ($apis['operations'] as $op) {
237
// 				// fetch required params
238
// 				$required = [];
239
// 				if (isset($op['parameters'])) {
240
// 					foreach ($op['parameters'] as $param) {
241
// 						if (isset($param['paramType']) && $param['paramType'] == 'path') {
242
// 							$required[] = $param['name'];
243
// 						}
244
// 					}
245
// 				}
246
	
247
// 				// create record
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...
248
// 				$fullPath = str_replace('//', '/', $base . '/' . $path);
249
// 				$api = new Api();
250
// 				$api->setMethod($op['method']);
251
// 				$api->setRoute($fullPath);
252
// 				$api->setActionId($actionMap[$op['nickname']]);
253
// 				$api->setRequiredParams(implode(',', $required));
254
// 				$api->save();
255
// 			}
256
// 		}
257
	
258
		$model->setApi(true);
259
		$model->save();
260
	}
261
	
262
	public function deactivate(IOInterface $io, $packageName) {
263
		$io->write('[Keeko] Deactivate Module: ' . $packageName);
264
		
265
		$mod = ModuleQuery::create()->filterByName($packageName)->findOne();
266
		$mod->setActivatedVersion(null);
267
		$mod->save();
268
	}
269
}