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) { |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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
|
|
|
|
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.