PermissionsExtension   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 191
Duplicated Lines 12.57 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 86.49%

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 4
dl 24
loc 191
ccs 64
cts 74
cp 0.8649
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
C loadConfiguration() 24 67 11
A beforeCompile() 0 31 4
A register() 0 6 1
B registerPermissionsResources() 0 47 9

How to fix   Duplicated Code   

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:

1
<?php
2
/**
3
 * PermissionsExtension.php
4
 *
5
 * @copyright      More in license.md
6
 * @license        https://www.ipublikuj.eu
7
 * @author         Adam Kadlec <[email protected]>
8
 * @package        iPublikuj:Permissions!
9
 * @subpackage     DI
10
 * @since          1.0.0
11
 *
12
 * @date           10.10.14
13
 */
14
15
declare(strict_types = 1);
16
17
namespace IPub\Permissions\DI;
18
19
use Nette;
20
use Nette\DI;
21
use Nette\Security as NS;
22
use Nette\Utils;
23
24
use IPub\Permissions;
25
use IPub\Permissions\Access;
26
use IPub\Permissions\Entities;
27
use IPub\Permissions\Exceptions;
28
use IPub\Permissions\Providers;
29
use IPub\Permissions\Security;
30
31
/**
32
 * Permission extension container
33
 *
34
 * @package        iPublikuj:Permissions!
35
 * @subpackage     DI
36
 *
37
 * @author         Adam Kadlec <[email protected]>
38
 */
39 1
final class PermissionsExtension extends DI\CompilerExtension
40
{
41
	/**
42
	 * @var array
43
	 */
44
	private $defaults = [
45
		'annotation'  => TRUE,
46
		'redirectUrl' => NULL,
47
		'providers'   => [
48
			'roles'       => TRUE,
49
			'resources'   => TRUE,
50
			'permissions' => TRUE,
51
		],
52
	];
53
54
	/**
55
	 * @return void
56
	 */
57
	public function loadConfiguration() : void
58
	{
59
		// Get container builder
60 1
		$builder = $this->getContainerBuilder();
61
		// Get extension configuration
62 1
		$configuration = $this->getConfig($this->defaults);
63
64
		// Application permissions
65 1
		$builder->addDefinition($this->prefix('permissions'))
66 1
			->setType(Security\Permission::class);
67
68 1
		$builder->addDefinition($this->prefix('config'))
69 1
			->setType(Permissions\Configuration::class)
70 1
			->setArguments([
71 1
				$configuration['redirectUrl'],
72
			]);
73
74
		/**
75
		 * Data providers
76
		 */
77
78 1 View Code Duplication
		if ($configuration['providers']['roles'] === TRUE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
79
			$builder->addDefinition($this->prefix('providers.roles'))
80
				->setType(Providers\RolesProvider::class);
81
82 1
		} elseif (is_string($configuration['providers']['roles']) && class_exists($configuration['providers']['roles'])) {
83
			$builder->addDefinition($this->prefix('providers.roles'))
84
				->setType($configuration['providers']['roles']);
85
		}
86
87 1 View Code Duplication
		if ($configuration['providers']['resources'] === TRUE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
88
			$builder->addDefinition($this->prefix('providers.resources'))
89
				->setType(Providers\ResourcesProvider::class);
90
91 1
		} elseif (is_string($configuration['providers']['resources']) && class_exists($configuration['providers']['resources'])) {
92 1
			$builder->addDefinition($this->prefix('providers.resources'))
93 1
				->setType($configuration['providers']['resources']);
94
		}
95
96 1 View Code Duplication
		if ($configuration['providers']['permissions'] === TRUE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
97
			$builder->addDefinition($this->prefix('providers.permissions'))
98
				->setType(Providers\PermissionsProvider::class);
99
100 1
		} elseif (is_string($configuration['providers']['permissions']) && class_exists($configuration['providers']['permissions'])) {
101 1
			$builder->addDefinition($this->prefix('providers.permissions'))
102 1
				->setType($configuration['providers']['permissions']);
103
		}
104
105
		/**
106
		 * Access checkers
107
		 */
108
109
		// Check if annotation checker is enabled
110 1
		if ($configuration['annotation'] === TRUE) {
111
			// Annotation access checkers
112 1
			$builder->addDefinition($this->prefix('checkers.annotation'))
113 1
				->setType(Access\AnnotationChecker::class);
114
		}
115
116
		// Latte access checker
117 1
		$builder->addDefinition($this->prefix('checkers.latte'))
118 1
			->setType(Access\LatteChecker::class);
119
120
		// Link access checker
121 1
		$builder->addDefinition($this->prefix('checkers.link'))
122 1
			->setType(Access\LinkChecker::class);
123 1
	}
124
125
	/**
126
	 * {@inheritdoc}
127
	 */
128
	public function beforeCompile() : void
129
	{
130 1
		parent::beforeCompile();
131
132
		// Get container builder
133 1
		$builder = $this->getContainerBuilder();
134
135
		// Get acl permissions service
136 1
		$permissionsProvider = $builder->findByType(Providers\IPermissionsProvider::class);
137 1
		$permissionsProvider = reset($permissionsProvider);
138
139
		// Get acl resources service
140 1
		$resourcesProvider = $builder->findByType(Providers\IResourcesProvider::class);
141 1
		$resourcesProvider = reset($resourcesProvider);
142
143
		// Check all extensions and search for permissions provider
144 1
		foreach ($this->compiler->getExtensions() as $extension) {
145 1
			if (!$extension instanceof IPermissionsProvider) {
146 1
				continue;
147
			}
148
149
			// Get permissions & details
150 1
			$this->registerPermissionsResources($extension->getPermissions(), $resourcesProvider, $permissionsProvider);
151
		}
152
153
		// Install extension latte macros
154 1
		$latteFactory = $builder->getDefinition($builder->getByType(Nette\Bridges\ApplicationLatte\ILatteFactory::class) ?: 'nette.latteFactory');
155
156
		$latteFactory
157 1
			->addSetup('IPub\Permissions\Latte\Macros::install(?->getCompiler())', ['@self']);
158 1
	}
159
160
	/**
161
	 * @param Nette\Configurator $config
162
	 * @param string $extensionName
163
	 *
164
	 * @return void
165
	 */
166
	public static function register(Nette\Configurator $config, $extensionName = 'permissions') : void
167
	{
168 1
		$config->onCompile[] = function (Nette\Configurator $config, Nette\DI\Compiler $compiler) use ($extensionName) {
169 1
			$compiler->addExtension($extensionName, new PermissionsExtension());
170 1
		};
171 1
	}
172
173
	/**
174
	 * @param array $permissions
175
	 * @param DI\ServiceDefinition|NULL $resourcesProvider
176
	 * @param DI\ServiceDefinition|NULL $permissionsProvider
177
	 *
178
	 * @return void
179
	 *
180
	 * @throws Exceptions\InvalidArgumentException
181
	 */
182
	private function registerPermissionsResources(
183
		array $permissions,
184
		DI\ServiceDefinition $resourcesProvider = NULL,
185
		DI\ServiceDefinition $permissionsProvider = NULL
186
	) : void {
187 1
		foreach ($permissions as $permission => $details) {
188 1
			if (is_string($permission) && Utils\Strings::contains($permission, Entities\IPermission::DELIMITER)) {
189
				// Parse resource & privilege from permission
190 1
				list($resource, $privilege) = explode(Entities\IPermission::DELIMITER, $permission);
191
192
				// Remove white spaces
193 1
				$resource = Utils\Strings::trim($resource);
194 1
				$privilege = Utils\Strings::trim($privilege);
195
196 1
				$resource = new Entities\Resource($resource);
197
198 1
			} elseif (is_array($details)) {
199 1
				if (!isset($details['resource']) || !isset($details['privilege'])) {
200 1
					throw new Exceptions\InvalidArgumentException('Permission must include resource & privilege.');
201
				}
202
203
				// Remove white spaces
204 1
				$resource = Utils\Strings::trim($details['resource']);
205 1
				$privilege = Utils\Strings::trim($details['privilege']);
206
207 1
				$resource = new Entities\Resource($resource);
208
209 1
				$details = NULL;
210
211
			} elseif ($details instanceof Entities\IPermission) {
212 1
				$resource = $details->getResource();
213 1
				$privilege = $details->getPrivilege();
214
215 1
				$details = NULL;
216
217
				// Resource & privilege is in string with delimiter
218
			} else {
219
				throw new Exceptions\InvalidArgumentException(sprintf('Permission must be only string with delimiter, array with resource & privilege or instance of IPub\Permissions\Entities\IPermission, %s given', gettype($permission)));
220
			}
221
222 1
			$privilege = $privilege === '' ? NS\IAuthorizator::ALL : $privilege;
223
224
			// Assign permission to service
225 1
			$permissionsProvider->addSetup('addPermission', [$resource, $privilege, $details]);
226 1
			$resourcesProvider->addSetup('addResource', [$resource->getResourceId()]);
227
		}
228 1
	}
229
}
230