1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Itstructure\RbacModule\models; |
4
|
|
|
|
5
|
|
|
use Yii; |
6
|
|
|
use yii\base\{Model, InvalidConfigException}; |
7
|
|
|
use yii\rbac\{Item, ManagerInterface}; |
8
|
|
|
use Itstructure\RbacModule\Module; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Class Rbac |
12
|
|
|
* Model Rbac to work with roles and permissions. |
13
|
|
|
* |
14
|
|
|
* @property string $name |
15
|
|
|
* @property string $description |
16
|
|
|
* @property ManagerInterface $authManager |
17
|
|
|
* |
18
|
|
|
* @package Itstructure\RbacModule\models |
19
|
|
|
*/ |
20
|
|
|
abstract class Rbac extends Model |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* Role name. |
24
|
|
|
* |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
public $name; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Role description. |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
public $description; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Auth manager. |
38
|
|
|
* |
39
|
|
|
* @var ManagerInterface |
40
|
|
|
*/ |
41
|
|
|
private $authManager; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Create new item (Role or permission). |
45
|
|
|
* |
46
|
|
|
* @param string $name |
47
|
|
|
* |
48
|
|
|
* @return Item |
49
|
|
|
*/ |
50
|
|
|
abstract protected function createItem(string $name): Item; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Create child item. |
54
|
|
|
* Example: parent - role, child - permission. |
55
|
|
|
* |
56
|
|
|
* @param string $name |
57
|
|
|
* |
58
|
|
|
* @return Item |
59
|
|
|
*/ |
60
|
|
|
abstract protected function createChild(string $name): Item; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Get current child items. |
64
|
|
|
* |
65
|
|
|
* @return array |
66
|
|
|
*/ |
67
|
|
|
abstract protected function getCurrentChildren(): array ; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Get new child items. |
71
|
|
|
* |
72
|
|
|
* @return array |
73
|
|
|
*/ |
74
|
|
|
abstract protected function getNewChildren(): array ; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Returns old name in current object, which is set before new value. |
78
|
|
|
* |
79
|
|
|
* @return mixed |
80
|
|
|
*/ |
81
|
|
|
abstract protected function getOldName(); |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Returns item object: Role or Permission. |
85
|
|
|
* |
86
|
|
|
* @param string $key |
87
|
|
|
* |
88
|
|
|
* @return Item|null |
89
|
|
|
*/ |
90
|
|
|
abstract protected function getItem(string $key); |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Set item (role or permission) for instance of Rbac. |
94
|
|
|
* |
95
|
|
|
* @param Rbac $instance |
96
|
|
|
* @param Item $item |
97
|
|
|
* |
98
|
|
|
* @return Rbac |
99
|
|
|
*/ |
100
|
|
|
abstract protected function setItemForInstance(Rbac $instance, Item $item): Rbac; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Set children for instance of Rbac (for Role or Permission). |
104
|
|
|
* |
105
|
|
|
* @param Rbac $instance |
106
|
|
|
* |
107
|
|
|
* @return Rbac |
108
|
|
|
*/ |
109
|
|
|
abstract protected function setChildrenForInstance(Rbac $instance): Rbac; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Initialize. |
113
|
|
|
*/ |
114
|
|
View Code Duplication |
public function init() |
|
|
|
|
115
|
|
|
{ |
116
|
|
|
if (null === $this->authManager) { |
117
|
|
|
$this->setAuthManager(Yii::$app->authManager); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
if (null === $this->authManager) { |
121
|
|
|
throw new InvalidConfigException('The authManager is not defined.'); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @inheritdoc |
127
|
|
|
*/ |
128
|
|
|
public function rules() |
129
|
|
|
{ |
130
|
|
|
return [ |
131
|
|
|
[ |
132
|
|
|
[ |
133
|
|
|
'name', |
134
|
|
|
'description', |
135
|
|
|
], |
136
|
|
|
'required', |
137
|
|
|
], |
138
|
|
|
[ |
139
|
|
|
[ |
140
|
|
|
'name', |
141
|
|
|
], |
142
|
|
|
'string', |
143
|
|
|
'min' => 3, |
144
|
|
|
'max' => 64, |
145
|
|
|
], |
146
|
|
|
[ |
147
|
|
|
'name', |
148
|
|
|
'match', |
149
|
|
|
'pattern' => '/^[a-z]\w*$/i', |
150
|
|
|
'message' => Module::t('rbac', 'Name must contain latin symbols and numeric without spaces.') |
151
|
|
|
], |
152
|
|
|
[ |
153
|
|
|
[ |
154
|
|
|
'description', |
155
|
|
|
], |
156
|
|
|
'string', |
157
|
|
|
], |
158
|
|
|
[ |
159
|
|
|
[ |
160
|
|
|
'name', |
161
|
|
|
], |
162
|
|
|
'checkNameForUnique', |
163
|
|
|
], |
164
|
|
|
]; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Set auth manager. |
169
|
|
|
* |
170
|
|
|
* @param ManagerInterface $authManager |
171
|
|
|
* |
172
|
|
|
* @return $this |
173
|
|
|
*/ |
174
|
|
|
public function setAuthManager(ManagerInterface $authManager) |
175
|
|
|
{ |
176
|
|
|
$this->authManager = $authManager; |
|
|
|
|
177
|
|
|
return $this; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Get auth manager. |
182
|
|
|
* |
183
|
|
|
* @return ManagerInterface |
184
|
|
|
*/ |
185
|
|
|
public function getAuthManager(): ManagerInterface |
186
|
|
|
{ |
187
|
|
|
return $this->authManager; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param string $key |
192
|
|
|
* |
193
|
|
|
* @return static |
194
|
|
|
*/ |
195
|
|
|
public function findOne(string $key) |
196
|
|
|
{ |
197
|
|
|
$item = $this->getItem($key); |
198
|
|
|
|
199
|
|
|
$instance = new static(); |
200
|
|
|
$instance->name = $item->name; |
201
|
|
|
$instance->description = $item->description; |
202
|
|
|
|
203
|
|
|
return $this->setChildrenForInstance($this->setItemForInstance($instance, $item)); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Save item data. |
208
|
|
|
* |
209
|
|
|
* @return bool |
210
|
|
|
*/ |
211
|
|
|
public function save(): bool |
212
|
|
|
{ |
213
|
|
|
if (!$this->validate()) { |
214
|
|
|
return false; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$item = $this->createItem($this->name); |
218
|
|
|
$item->description = $this->description; |
219
|
|
|
|
220
|
|
|
if ($this->checkForNewRecord()) { |
221
|
|
|
return $this->createData($item); |
222
|
|
|
} else { |
223
|
|
|
return $this->updateData($item); |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Returns current model id. |
229
|
|
|
* |
230
|
|
|
* @return string |
231
|
|
|
*/ |
232
|
|
|
public function getId(): string |
233
|
|
|
{ |
234
|
|
|
return $this->name; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Delete current role. |
239
|
|
|
* |
240
|
|
|
* @return bool |
241
|
|
|
*/ |
242
|
|
|
public function delete(): bool |
243
|
|
|
{ |
244
|
|
|
return $this->authManager->remove($this->createItem($this->name)); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* Delete from general list children items, which can't be assigned to parent. |
249
|
|
|
* |
250
|
|
|
* @param array $chlidren |
251
|
|
|
* |
252
|
|
|
* @return array |
253
|
|
|
*/ |
254
|
|
|
public function filterChlidrenBeforeAdd(array $chlidren): array |
255
|
|
|
{ |
256
|
|
|
if (null === $this->getOldName()) { |
257
|
|
|
return $chlidren; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
foreach ($chlidren as $key => $value) { |
261
|
|
|
|
262
|
|
|
$parent = $this->createItem($this->getOldName()); |
263
|
|
|
|
264
|
|
|
$child = $this->createChild($key); |
265
|
|
|
|
266
|
|
|
if (!$this->authManager->canAddChild($parent, $child)) { |
267
|
|
|
unset($chlidren[$key]); |
268
|
|
|
} |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
return $chlidren; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Check name for unique. |
276
|
|
|
* |
277
|
|
|
* @param $attribute |
278
|
|
|
* |
279
|
|
|
* @return bool |
280
|
|
|
*/ |
281
|
|
|
public function checkNameForUnique($attribute): bool |
282
|
|
|
{ |
283
|
|
|
$item = $this->getItem($this->name); |
284
|
|
|
|
285
|
|
|
if (null !== $item && $this->getOldName() !== $item->name) { |
286
|
|
|
$this->addError($attribute, Module::t('rbac', 'This name already exists.')); |
287
|
|
|
return false; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
return true; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Check if current model is new record. |
295
|
|
|
* Return true if there is a new record. |
296
|
|
|
* |
297
|
|
|
* @return bool |
298
|
|
|
*/ |
299
|
|
|
private function checkForNewRecord(): bool |
300
|
|
|
{ |
301
|
|
|
return null === $this->getOldName(); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
/** |
305
|
|
|
* Function for creating record. |
306
|
|
|
* |
307
|
|
|
* @param Item $item |
308
|
|
|
* |
309
|
|
|
* @return bool |
310
|
|
|
*/ |
311
|
|
|
private function createData(Item $item): bool |
312
|
|
|
{ |
313
|
|
|
if (!$this->authManager->add($item)) { |
314
|
|
|
return false; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
$newChildren = $this->getNewChildren(); |
318
|
|
|
|
319
|
|
|
if (count($newChildren) > 0) { |
320
|
|
|
$this->addChildren($newChildren); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
return true; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Function for updating record. |
328
|
|
|
* |
329
|
|
|
* @param Item $item |
330
|
|
|
* |
331
|
|
|
* @return bool |
332
|
|
|
*/ |
333
|
|
|
private function updateData(Item $item): bool |
334
|
|
|
{ |
335
|
|
|
if (!$this->authManager->update($this->getOldName(), $item)) { |
336
|
|
|
return false; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
$this->authManager->removeChildren($item); |
340
|
|
|
|
341
|
|
|
$newChildren = $this->getNewChildren(); |
342
|
|
|
|
343
|
|
|
if (count($newChildren) > 0) { |
344
|
|
|
$this->addChildren($newChildren); |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
return true; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* Add childs items for parent item. |
352
|
|
|
* |
353
|
|
|
* @param array $childs |
354
|
|
|
*/ |
355
|
|
|
private function addChildren(array $childs): void |
356
|
|
|
{ |
357
|
|
|
foreach ($childs as $child) { |
358
|
|
|
|
359
|
|
|
$this->authManager->addChild( |
360
|
|
|
$this->createItem($this->name), |
361
|
|
|
$this->createChild($child) |
362
|
|
|
); |
363
|
|
|
} |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
|
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.