This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Manager.php |
||
4 | * |
||
5 | * PHP version 5.6+ |
||
6 | * |
||
7 | * @author Philippe Gaultier <[email protected]> |
||
8 | * @copyright 2010-2017 Philippe Gaultier |
||
9 | * @license http://www.sweelix.net/license license |
||
10 | * @version XXX |
||
11 | * @link http://www.sweelix.net |
||
12 | * @package sweelix\rbac\redis |
||
13 | */ |
||
14 | |||
15 | namespace sweelix\rbac\redis; |
||
16 | |||
17 | use sweelix\guid\Guid; |
||
18 | use Yii; |
||
19 | use yii\base\InvalidCallException; |
||
20 | use yii\base\InvalidParamException; |
||
21 | use yii\di\Instance; |
||
22 | use yii\rbac\Assignment; |
||
23 | use yii\rbac\BaseManager; |
||
24 | use yii\rbac\Permission; |
||
25 | use yii\rbac\Role; |
||
26 | use yii\rbac\Item; |
||
27 | use yii\rbac\Rule; |
||
28 | use yii\redis\Connection; |
||
29 | |||
30 | /** |
||
31 | * REDIS Manager represents an authorization manager that stores |
||
32 | * authorization information in REDIS database |
||
33 | * |
||
34 | * database structure : |
||
35 | * * auth:users:<userId>:assignments : ZSET (string: roleName, score: createdAt) |
||
36 | * * auth:roles:<roleName>:assignments : ZSET (string|int: userId, score: createdAt) |
||
37 | * * auth:rules:<ruleName> : MAP (string: ruleName, string: data, integer: createdAt, integer: updatedAt) |
||
38 | * * auth:types:<typeId>:items : SET (string: itemName) |
||
39 | * * auth:items:<itemName> : MAP (string: itemName, int: typeId, string: description, integer: createdAt, integer: updatedAt, string: ruleName) |
||
40 | * * auth:rules:<ruleName>:items : SET (string: itemName) |
||
41 | * * auth:items:<itemName>:children : SET (string: itemName) |
||
42 | * * auth:items:<itemName>:parents : SET (string: itemName) |
||
43 | * * auth:mappings:items : MAP (string: itemName, string: guid) |
||
44 | * * auth:mappings:itemsguid : MAP (string: guid, string: itemName) |
||
45 | * * auth:mappings:rules : MAP (string: ruleName, string: guid) |
||
46 | * * auth:mappings:rulesguid : MAP (string: guid, string: ruleName) |
||
47 | * |
||
48 | * @author Philippe Gaultier <[email protected]> |
||
49 | * @copyright 2010-2017 Philippe Gaultier |
||
50 | * @license http://www.sweelix.net/license license |
||
51 | * @version XXX |
||
52 | * @link http://www.sweelix.net |
||
53 | * @package application\controllers |
||
54 | * @since XXX |
||
55 | */ |
||
56 | class Manager extends BaseManager |
||
57 | { |
||
58 | /** |
||
59 | * @var Connection|array|string the Redis DB connection object or the application component ID of the DB connection. |
||
60 | */ |
||
61 | public $db = 'redis'; |
||
62 | |||
63 | /** |
||
64 | * @var string |
||
65 | */ |
||
66 | public $globalMatchKey = 'auth:*'; |
||
67 | |||
68 | /** |
||
69 | * @var string |
||
70 | */ |
||
71 | public $userAssignmentsKey = 'auth:users:{id}:assignments'; |
||
72 | |||
73 | /** |
||
74 | * @var string |
||
75 | */ |
||
76 | public $roleAssignmentsKey = 'auth:roles:{id}:assignments'; |
||
77 | |||
78 | /** |
||
79 | * @var string |
||
80 | */ |
||
81 | public $ruleKey = 'auth:rules:{id}'; |
||
82 | |||
83 | /** |
||
84 | * @var string |
||
85 | */ |
||
86 | public $typeItemsKey = 'auth:types:{id}:items'; |
||
87 | |||
88 | /** |
||
89 | * @var string |
||
90 | */ |
||
91 | public $itemKey = 'auth:items:{id}'; |
||
92 | |||
93 | /** |
||
94 | * @var string |
||
95 | */ |
||
96 | public $ruleItemsKey = 'auth:rules:{id}:items'; |
||
97 | |||
98 | /** |
||
99 | * @var string |
||
100 | */ |
||
101 | public $itemChildrenKey = 'auth:items:{id}:children'; |
||
102 | |||
103 | /** |
||
104 | * @var string |
||
105 | */ |
||
106 | public $itemParentsKey = 'auth:items:{id}:parents'; |
||
107 | |||
108 | /** |
||
109 | * @var string |
||
110 | */ |
||
111 | public $itemMappings = 'auth:mappings:items'; |
||
112 | |||
113 | /** |
||
114 | * @var string |
||
115 | */ |
||
116 | public $itemMappingsGuid = 'auth:mappings:itemsguid'; |
||
117 | |||
118 | /** |
||
119 | * @var string |
||
120 | */ |
||
121 | public $ruleMappings = 'auth:mappings:rules'; |
||
122 | |||
123 | /** |
||
124 | * @var string |
||
125 | */ |
||
126 | public $ruleMappingsGuid = 'auth:mappings:rulesguid'; |
||
127 | |||
128 | |||
129 | /** |
||
130 | * @param string|integer $userId user id |
||
131 | * @return string the user assignments key |
||
132 | * @since XXX |
||
133 | */ |
||
134 | 20 | public function getUserAssignmentsKey($userId) |
|
135 | { |
||
136 | 20 | return str_replace('{id}', $userId, $this->userAssignmentsKey); |
|
137 | } |
||
138 | |||
139 | /** |
||
140 | * @param string $roleGuid role guid |
||
141 | * @return string the rule assignments key |
||
142 | * @since XXX |
||
143 | */ |
||
144 | 20 | public function getRoleAssignmentsKey($roleGuid) |
|
145 | { |
||
146 | 20 | return str_replace('{id}', $roleGuid, $this->roleAssignmentsKey); |
|
147 | } |
||
148 | |||
149 | /** |
||
150 | * @param string $ruleGuid rule guid |
||
151 | * @return string the rule key |
||
152 | * @since XXX |
||
153 | */ |
||
154 | 22 | public function getRuleKey($ruleGuid) |
|
155 | { |
||
156 | 22 | return str_replace('{id}', $ruleGuid, $this->ruleKey); |
|
157 | } |
||
158 | |||
159 | /** |
||
160 | * @param integer $typeId type id |
||
161 | * @return string the type id key |
||
162 | * @since XXX |
||
163 | */ |
||
164 | 29 | public function getTypeItemsKey($typeId) |
|
165 | { |
||
166 | 29 | return str_replace('{id}', $typeId, $this->typeItemsKey); |
|
167 | } |
||
168 | |||
169 | /** |
||
170 | * @param string $itemGuid item guid |
||
171 | * @return string |
||
172 | * @since XXX |
||
173 | */ |
||
174 | 29 | public function getItemKey($itemGuid) |
|
175 | { |
||
176 | 29 | return str_replace('{id}', $itemGuid, $this->itemKey); |
|
177 | } |
||
178 | |||
179 | /** |
||
180 | * @param string $ruleGuid rule guid |
||
181 | * @return string the rule items key |
||
182 | * @since XXX |
||
183 | */ |
||
184 | 4 | public function getRuleItemsKey($ruleGuid) |
|
185 | { |
||
186 | 4 | return str_replace('{id}', $ruleGuid, $this->ruleItemsKey); |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * @param string $itemGuid item guid |
||
191 | * @return string the item children key |
||
192 | * @since XXX |
||
193 | */ |
||
194 | 24 | public function getItemChildrenKey($itemGuid) |
|
195 | { |
||
196 | 24 | return str_replace('{id}', $itemGuid, $this->itemChildrenKey); |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * @param string $itemGuid item guid |
||
201 | * @return string the item parents key |
||
202 | * @since XXX |
||
203 | */ |
||
204 | 24 | public function getItemParentsKey($itemGuid) |
|
205 | { |
||
206 | 24 | return str_replace('{id}', $itemGuid, $this->itemParentsKey); |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * @return string the item mapping key |
||
211 | * @since XXX |
||
212 | */ |
||
213 | 29 | public function getItemMappingKey() |
|
214 | { |
||
215 | 29 | return $this->itemMappings; |
|
216 | } |
||
217 | |||
218 | /** |
||
219 | * @return string the rule mapping key |
||
220 | * @since XXX |
||
221 | */ |
||
222 | 29 | public function getRuleMappingKey() |
|
223 | { |
||
224 | 29 | return $this->ruleMappings; |
|
225 | } |
||
226 | |||
227 | /** |
||
228 | * @return string the item mapping key |
||
229 | * @since XXX |
||
230 | */ |
||
231 | 29 | public function getItemMappingGuidKey() |
|
232 | { |
||
233 | 29 | return $this->itemMappingsGuid; |
|
234 | } |
||
235 | |||
236 | /** |
||
237 | * @return string the rule mapping key |
||
238 | * @since XXX |
||
239 | */ |
||
240 | 22 | public function getRuleMappingGuidKey() |
|
241 | { |
||
242 | 22 | return $this->ruleMappingsGuid; |
|
243 | } |
||
244 | |||
245 | |||
246 | /** |
||
247 | * @inheritdoc |
||
248 | */ |
||
249 | 31 | public function init() |
|
250 | { |
||
251 | 31 | parent::init(); |
|
252 | 31 | $this->db = Instance::ensure($this->db, Connection::className()); |
|
253 | 31 | } |
|
254 | |||
255 | /** |
||
256 | * @inheritdoc |
||
257 | */ |
||
258 | 11 | protected function getItem($name) |
|
259 | { |
||
260 | 11 | $item = null; |
|
261 | 11 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); |
|
262 | 11 | if ($guid !== null) { |
|
263 | 11 | $item = $this->getItemByGuid($guid, $name); |
|
264 | 11 | } |
|
265 | 11 | return $item; |
|
266 | } |
||
267 | |||
268 | /** |
||
269 | * @param string $guid item guid |
||
270 | * @param string $name name if known to avoid additional call |
||
271 | * @return mixed |
||
272 | * @since XXX |
||
273 | */ |
||
274 | 25 | protected function getItemByGuid($guid, $name = null) |
|
275 | { |
||
276 | 25 | if ($name === null) { |
|
277 | 24 | $name = $this->db->executeCommand('HGET', [$this->getItemMappingGuidKey(), $guid]); |
|
278 | 24 | } |
|
279 | 25 | $data = $this->db->executeCommand('HGETALL', [$this->getItemKey($guid)]); |
|
280 | 25 | $dataRow = ['name' => $name]; |
|
281 | 25 | $nbProps = count($data); |
|
282 | 25 | for ($i = 0; $i < $nbProps; $i = $i + 2) { |
|
283 | 25 | $dataRow[$data[$i]] = $data[($i + 1)]; |
|
284 | 25 | } |
|
285 | 25 | if (isset($dataRow['ruleGuid']) === true) { |
|
286 | 20 | $dataRow['ruleName'] = $this->db->executeCommand('HGET', [$this->getRuleMappingGuidKey(), $dataRow['ruleGuid']]); |
|
287 | 20 | unset($dataRow['ruleGuid']); |
|
288 | 25 | } elseif(isset($dataRow['ruleClass']) === true) { |
|
289 | 1 | $dataRow['ruleName'] = $dataRow['ruleClass']; |
|
290 | 1 | unset($dataRow['ruleClass']); |
|
291 | 1 | } |
|
292 | 25 | $item = $this->populateItem($dataRow); |
|
293 | 25 | return $item; |
|
294 | } |
||
295 | |||
296 | /** |
||
297 | * @inheritdoc |
||
298 | */ |
||
299 | 3 | protected function getItems($type) |
|
300 | { |
||
301 | 3 | $itemGuids = $this->db->executeCommand('SMEMBERS', [$this->getTypeItemsKey($type)]); |
|
302 | 3 | $items = []; |
|
303 | 3 | foreach($itemGuids as $itemGuid) { |
|
304 | 3 | $item = $this->getItemByGuid($itemGuid); |
|
305 | 3 | $items[$item->name] = $item; |
|
306 | 3 | } |
|
307 | 3 | return $items; |
|
308 | } |
||
309 | |||
310 | /** |
||
311 | * @inheritdoc |
||
312 | */ |
||
313 | 29 | protected function addItem($item) |
|
314 | { |
||
315 | 29 | if (empty($item->name) === true) { |
|
316 | 1 | throw new InvalidParamException("Item name must be defined"); |
|
317 | } |
||
318 | 29 | $itemExists = (int)$this->db->executeCommand('HEXISTS', [$this->getItemMappingKey(), $item->name]); |
|
319 | 29 | if ($itemExists === 1) { |
|
320 | 1 | throw new DuplicateKeyException("Rule '{$item->name}' already defined"); |
|
321 | } |
||
322 | 29 | $guid = Guid::v4(); |
|
323 | 29 | $time = time(); |
|
324 | 29 | if ($item->createdAt === null) { |
|
325 | 29 | $item->createdAt = $time; |
|
326 | 29 | } |
|
327 | 29 | if ($item->updatedAt === null) { |
|
328 | 29 | $item->updatedAt = $time; |
|
329 | 29 | } |
|
330 | |||
331 | 29 | list($insertInRedis, ) = $this->prepareRedisItem($item, $guid); |
|
332 | 29 | $this->db->executeCommand('MULTI'); |
|
333 | // update mapping |
||
334 | 29 | $this->db->executeCommand('HSET', [$this->getItemMappingKey(), $item->name, $guid]); |
|
335 | 29 | $this->db->executeCommand('HSET', [$this->getItemMappingGuidKey(), $guid, $item->name]); |
|
336 | // insert item |
||
337 | 29 | $this->db->executeCommand('HMSET', $insertInRedis); |
|
338 | 29 | $this->db->executeCommand('SADD', [$this->getTypeItemsKey($item->type), $guid]); |
|
339 | // affect rule |
||
340 | 29 | if (isset($insertInRedis['ruleGuid']) === true) { |
|
341 | $this->db->executeCommand('SADD', [$this->getRuleItemsKey($insertInRedis['ruleGuid']), $guid]); |
||
342 | } |
||
343 | 29 | $this->db->executeCommand('EXEC'); |
|
344 | 29 | return true; |
|
345 | |||
346 | } |
||
347 | |||
348 | /** |
||
349 | * @param Item $item item to insert in DB |
||
350 | * @param string $guid guid generated |
||
351 | * @return array Redis command |
||
352 | * @since XXX |
||
353 | */ |
||
354 | 29 | private function prepareRedisItem($item, $guid) |
|
355 | { |
||
356 | 29 | $redisCleanItem = [$this->getItemKey($guid)]; |
|
357 | 29 | $redisItem = [$this->getItemKey($guid), |
|
358 | 29 | 'data', serialize($item->data), |
|
359 | 29 | 'type', $item->type, |
|
360 | 29 | 'createdAt', $item->createdAt, |
|
361 | 29 | 'updatedAt', $item->updatedAt |
|
362 | 29 | ]; |
|
363 | |||
364 | 29 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); |
|
365 | |||
366 | 29 | if ($ruleGuid !== null) { |
|
367 | 20 | $redisItem[] = 'ruleGuid'; |
|
368 | 20 | $redisItem[] = $ruleGuid; |
|
369 | 20 | $redisCleanItem[] = 'ruleClass'; |
|
370 | 29 | } elseif (class_exists($item->ruleName) || Yii::$container->has($item->ruleName)) { |
|
371 | 1 | $redisItem[] = 'ruleClass'; |
|
372 | 1 | $redisItem[] = $item->ruleName; |
|
373 | 1 | $redisCleanItem[] = 'ruleGuid'; |
|
374 | 1 | } |
|
375 | |||
376 | 29 | if ($item->description !== null) { |
|
377 | 23 | $redisItem[] = 'description'; |
|
378 | 23 | $redisItem[] = $item->description; |
|
379 | 23 | } else { |
|
380 | 25 | $redisCleanItem[] = 'description'; |
|
381 | } |
||
382 | 29 | return [$redisItem, $redisCleanItem]; |
|
383 | } |
||
384 | |||
385 | |||
386 | /** |
||
387 | * @inheritdoc |
||
388 | */ |
||
389 | 2 | protected function updateItem($name, $item) |
|
390 | { |
||
391 | 2 | $item->updatedAt = time(); |
|
392 | |||
393 | 2 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); |
|
394 | |||
395 | 2 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); |
|
396 | 2 | $newRule = $ruleGuid; |
|
397 | 2 | if (($ruleGuid === null) && (empty($item->ruleName) === false)) { |
|
398 | 1 | $newRule = $item->ruleName; |
|
399 | 1 | } |
|
400 | |||
401 | 2 | list($currentRuleGuid, $currentRuleClass, $currentType) = $this->db->executeCommand('HMGET', [$this->getItemKey($guid), 'ruleGuid', 'ruleClass', 'type']); |
|
402 | |||
403 | 2 | $oldRule = ($currentRuleGuid === null) ? $currentRuleClass : $currentRuleGuid; |
|
404 | 2 | $isUpdated = $newRule !== $oldRule; |
|
405 | |||
406 | 2 | $this->db->executeCommand('MULTI'); |
|
407 | 2 | if ($name !== $item->name) { |
|
408 | 2 | $this->remap($name, $item->name, $guid, false); |
|
409 | 2 | } |
|
410 | |||
411 | 2 | list($updateItem, $updateEmptyItem) = $this->prepareRedisItem($item, $guid); |
|
412 | |||
413 | 2 | if ($isUpdated && $currentRuleGuid !== null) { |
|
414 | $this->db->executeCommand('SREM', [$this->getRuleItemsKey($currentRuleGuid), $guid]); |
||
415 | } |
||
416 | 2 | if ($isUpdated && $ruleGuid !== null) { |
|
417 | $this->db->executeCommand('SADD', [$this->getRuleItemsKey($ruleGuid), $guid]); |
||
418 | } |
||
419 | 2 | if ($item->type !== $currentType) { |
|
420 | $this->db->executeCommand('SREM', [$this->getTypeItemsKey($currentType), $guid]); |
||
421 | $this->db->executeCommand('SADD', [$this->getTypeItemsKey($item->type), $guid]); |
||
422 | } |
||
423 | |||
424 | // update item |
||
425 | 2 | $this->db->executeCommand('HMSET', $updateItem); |
|
426 | // remove useless props |
||
427 | 2 | if (count($updateEmptyItem) > 1) { |
|
428 | 2 | $this->db->executeCommand('HDEL', $updateEmptyItem); |
|
429 | 2 | } |
|
430 | |||
431 | |||
432 | 2 | $this->db->executeCommand('EXEC'); |
|
433 | 2 | return true; |
|
434 | |||
435 | } |
||
436 | |||
437 | /** |
||
438 | * @param string $oldName old mapping name |
||
439 | * @param string $newName new mapping name |
||
440 | * @param string $guid unique ID |
||
441 | * @since XXX |
||
442 | */ |
||
443 | 2 | private function remap($oldName, $newName, $guid, $isRule = false) |
|
444 | { |
||
445 | 2 | if ($isRule) { |
|
446 | 1 | $mappingKey = $this->getRuleMappingKey(); |
|
447 | 1 | $mappingGuidKey = $this->getRuleMappingGuidKey(); |
|
448 | 1 | } else { |
|
449 | 2 | $mappingKey = $this->getItemMappingKey(); |
|
450 | 2 | $mappingGuidKey = $this->getItemMappingGuidKey(); |
|
451 | } |
||
452 | 2 | $this->db->executeCommand('HDEL', [$mappingKey, $oldName]); |
|
453 | // add new mapping |
||
454 | 2 | $this->db->executeCommand('HSET', [$mappingKey, $newName, $guid]); |
|
455 | 2 | $this->db->executeCommand('HSET', [$mappingGuidKey, $guid, $newName]); |
|
456 | 2 | } |
|
457 | |||
458 | /** |
||
459 | * @inheritdoc |
||
460 | */ |
||
461 | 3 | protected function removeItem($item) |
|
462 | { |
||
463 | 3 | $mappingKey = $this->getItemMappingKey(); |
|
464 | |||
465 | 3 | $guid = $this->db->executeCommand('HGET', [$mappingKey, $item->name]); |
|
466 | 3 | $ruleGuid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $item->ruleName]); |
|
467 | |||
468 | 3 | $parentGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemParentsKey($guid)]); |
|
469 | 3 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); |
|
470 | |||
471 | 3 | $this->db->executeCommand('MULTI'); |
|
472 | // delete mapping |
||
473 | 3 | $this->db->executeCommand('HDEL', [$mappingKey, $item->name]); |
|
474 | 3 | $this->db->executeCommand('HDEL', [$this->getItemMappingGuidKey(), $guid]); |
|
475 | // delete rule <-> item link |
||
476 | 3 | $this->db->executeCommand('SREM', [$this->getRuleItemsKey($ruleGuid), $guid]); |
|
477 | 3 | $this->db->executeCommand('SREM', [$this->getTypeItemsKey($item->type), $guid]); |
|
478 | // detach from hierarchy |
||
479 | 3 | foreach($parentGuids as $parentGuid) { |
|
480 | 3 | $this->db->executeCommand('SREM', [$this->getItemChildrenKey($parentGuid), $guid]); |
|
481 | 3 | } |
|
482 | // detach children |
||
483 | 3 | foreach($childrenGuids as $childGuid) { |
|
484 | 1 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $guid]); |
|
485 | 3 | } |
|
486 | 3 | $this->db->executeCommand('DEL', [$this->getItemParentsKey($guid)]); |
|
487 | 3 | $this->db->executeCommand('DEL', [$this->getItemChildrenKey($guid)]); |
|
488 | // delete rule |
||
489 | 3 | $this->db->executeCommand('DEL', [$this->getItemKey($guid)]); |
|
490 | 3 | $this->db->executeCommand('EXEC'); |
|
491 | 3 | return true; |
|
492 | |||
493 | } |
||
494 | |||
495 | /** |
||
496 | * @inheritdoc |
||
497 | */ |
||
498 | 22 | protected function addRule($rule) |
|
499 | { |
||
500 | 22 | if(empty($rule->name) === true) { |
|
501 | 1 | throw new InvalidParamException("Rule name must be defined"); |
|
502 | } |
||
503 | 22 | $ruleExists = (int)$this->db->executeCommand('HEXISTS', [$this->getRuleMappingKey(), $rule->name]); |
|
504 | 22 | if ($ruleExists === 1) |
|
505 | 22 | { |
|
506 | 1 | throw new DuplicateKeyException("Rule '{$rule->name}' already defined"); |
|
507 | } |
||
508 | 22 | $guid = Guid::v4(); |
|
509 | 22 | $time = time(); |
|
510 | 22 | if ($rule->createdAt === null) { |
|
511 | 22 | $rule->createdAt = $time; |
|
512 | 22 | } |
|
513 | 22 | if ($rule->updatedAt === null) { |
|
514 | 22 | $rule->updatedAt = $time; |
|
515 | 22 | } |
|
516 | 22 | $this->db->executeCommand('MULTI'); |
|
517 | 22 | $this->db->executeCommand('HSET', [$this->getRuleMappingKey(), $rule->name, $guid]); |
|
518 | 22 | $this->db->executeCommand('HSET', [$this->getRuleMappingGuidKey(),$guid, $rule->name]); |
|
519 | 22 | $this->db->executeCommand('HMSET', [$this->getRuleKey($guid), |
|
520 | 22 | 'data', serialize($rule), |
|
521 | 22 | 'createdAt', $rule->createdAt, |
|
522 | 22 | 'updatedAt', $rule->updatedAt |
|
523 | 22 | ]); |
|
524 | |||
525 | 22 | $this->db->executeCommand('EXEC'); |
|
526 | 22 | return true; |
|
527 | |||
528 | } |
||
529 | |||
530 | /** |
||
531 | * @inheritdoc |
||
532 | */ |
||
533 | 1 | protected function updateRule($name, $rule) |
|
534 | { |
||
535 | 1 | $rule->updatedAt = time(); |
|
536 | |||
537 | 1 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $name]); |
|
538 | |||
539 | 1 | $this->db->executeCommand('MULTI'); |
|
540 | 1 | if ($name !== $rule->name) { |
|
541 | 1 | $this->remap($name, $rule->name, $guid, true); |
|
542 | 1 | } |
|
543 | 1 | $this->db->executeCommand('HMSET', [$this->getRuleKey($guid), |
|
544 | 1 | 'data', serialize($rule), |
|
545 | 1 | 'createdAt', $rule->createdAt, |
|
546 | 1 | 'updatedAt', $rule->updatedAt |
|
547 | 1 | ]); |
|
548 | |||
549 | 1 | $this->db->executeCommand('EXEC'); |
|
550 | 1 | return true; |
|
551 | } |
||
552 | |||
553 | /** |
||
554 | * @inheritdoc |
||
555 | */ |
||
556 | 2 | protected function removeRule($rule) |
|
557 | { |
||
558 | 2 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $rule->name]); |
|
559 | |||
560 | 2 | $ruleMembers = $this->db->executeCommand('SMEMBERS', [$this->getRuleItemsKey($guid)]); |
|
561 | |||
562 | 2 | $this->db->executeCommand('MULTI'); |
|
563 | // delete mapping |
||
564 | 2 | $this->db->executeCommand('HDEL', [$this->getRuleMappingKey(), $rule->name]); |
|
565 | 2 | $this->db->executeCommand('HDEL', [$this->getRuleMappingGuidKey(), $guid]); |
|
566 | // detach items |
||
567 | 2 | foreach($ruleMembers as $itemGuid) |
|
568 | { |
||
569 | $this->db->executeCommand('HDEL', [$this->getItemKey($itemGuid), 'ruleGuid']); |
||
570 | 2 | } |
|
571 | // delete rule <-> item link |
||
572 | 2 | $this->db->executeCommand('DEL', [$this->getRuleItemsKey($guid)]); |
|
573 | // delete rule |
||
574 | 2 | $this->db->executeCommand('DEL', [$this->getRuleKey($guid)]); |
|
575 | 2 | $this->db->executeCommand('EXEC'); |
|
576 | 2 | return true; |
|
577 | } |
||
578 | |||
579 | /** |
||
580 | * @inheritdoc |
||
581 | */ |
||
582 | 5 | public function getRules() |
|
583 | { |
||
584 | 5 | $ruleNames = $this->db->executeCommand('HKEYS', [$this->getRuleMappingKey()]); |
|
585 | 5 | $rules = []; |
|
586 | 5 | foreach ($ruleNames as $ruleName) |
|
587 | { |
||
588 | 4 | $rules[$ruleName] = $this->getRule($ruleName); |
|
589 | 5 | } |
|
590 | 5 | return $rules; |
|
591 | } |
||
592 | |||
593 | /** |
||
594 | * @inheritdoc |
||
595 | */ |
||
596 | 20 | public function getRule($name) |
|
597 | { |
||
598 | 20 | $rule = null; |
|
599 | 20 | $guid = $this->db->executeCommand('HGET', [$this->getRuleMappingKey(), $name]); |
|
600 | 20 | if ($guid !== null) { |
|
601 | 20 | $rule = $this->getRuleGuid($guid); |
|
602 | 20 | } elseif(class_exists($name) === true) { |
|
603 | 1 | $rule = new $name; |
|
604 | 3 | } elseif(Yii::$container->has($name) === true) { |
|
605 | 1 | $rule = Yii::$container->get($name); |
|
606 | 1 | } |
|
607 | 20 | return $rule; |
|
608 | } |
||
609 | |||
610 | /** |
||
611 | * @param string $guid rule unique ID |
||
612 | * @return Rule |
||
613 | * @since XXX |
||
614 | */ |
||
615 | 20 | protected function getRuleGuid($guid) |
|
616 | { |
||
617 | 20 | $data = $this->db->executeCommand('HGET', [$this->getRuleKey($guid), 'data']); |
|
618 | 20 | $rule = unserialize($data); |
|
619 | 20 | return $rule; |
|
620 | } |
||
621 | |||
622 | /** |
||
623 | * @inheritdoc |
||
624 | */ |
||
625 | 24 | public function addChild($parent, $child) |
|
626 | { |
||
627 | 24 | if ($parent->name === $child->name) { |
|
628 | 1 | throw new InvalidParamException("Cannot add '{$parent->name}' as a child of itself."); |
|
629 | } |
||
630 | 24 | if ($parent instanceof Permission && $child instanceof Role) { |
|
631 | 1 | throw new InvalidParamException('Cannot add a role as a child of a permission.'); |
|
632 | } |
||
633 | 24 | if ($this->detectLoop($parent, $child)) { |
|
634 | 1 | throw new InvalidCallException("Cannot add '{$child->name}' as a child of '{$parent->name}'. A loop has been detected."); |
|
635 | } |
||
636 | |||
637 | 24 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); |
|
638 | |||
639 | 24 | $this->db->executeCommand('MULTI'); |
|
640 | 24 | $this->db->executeCommand('SADD', [$this->getItemParentsKey($childGuid), $parentGuid]); |
|
641 | 24 | $this->db->executeCommand('SADD', [$this->getItemChildrenKey($parentGuid), $childGuid]); |
|
642 | 24 | $this->db->executeCommand('EXEC'); |
|
643 | 24 | return true; |
|
644 | } |
||
645 | |||
646 | /** |
||
647 | * @inheritdoc |
||
648 | */ |
||
649 | 1 | public function removeChild($parent, $child) |
|
650 | { |
||
651 | 1 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); |
|
652 | 1 | $this->db->executeCommand('MULTI'); |
|
653 | 1 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $parentGuid]); |
|
654 | 1 | $this->db->executeCommand('SREM', [$this->getItemChildrenKey($parentGuid), $childGuid]); |
|
655 | 1 | $this->db->executeCommand('EXEC'); |
|
656 | 1 | return true; |
|
657 | |||
658 | } |
||
659 | |||
660 | /** |
||
661 | * @inheritdoc |
||
662 | */ |
||
663 | 1 | public function removeChildren($parent) |
|
664 | { |
||
665 | 1 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $parent->name]); |
|
666 | 1 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); |
|
667 | |||
668 | 1 | $this->db->executeCommand('MULTI'); |
|
669 | 1 | foreach($childrenGuids as $childGuid) |
|
670 | { |
||
671 | 1 | $this->db->executeCommand('SREM', [$this->getItemParentsKey($childGuid), $guid]); |
|
672 | 1 | } |
|
673 | 1 | $this->db->executeCommand('DEL', [$this->getItemChildrenKey($guid)]); |
|
674 | 1 | $this->db->executeCommand('EXEC'); |
|
675 | 1 | return true; |
|
676 | |||
677 | } |
||
678 | |||
679 | /** |
||
680 | * @inheritdoc |
||
681 | */ |
||
682 | 24 | public function getChildren($name) |
|
683 | { |
||
684 | 24 | $guid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $name]); |
|
685 | 24 | return $this->getChildrenByGuid($guid); |
|
686 | |||
687 | } |
||
688 | |||
689 | /** |
||
690 | * @param string $guid item guid |
||
691 | * @return Item[] |
||
692 | * @since XXX |
||
693 | */ |
||
694 | 24 | protected function getChildrenByGuid($guid) |
|
695 | { |
||
696 | 24 | $childrenGuids = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($guid)]); |
|
697 | 24 | $children = []; |
|
698 | 24 | if (count($childrenGuids) > 0) { |
|
699 | 24 | foreach($childrenGuids as $childGuid) { |
|
700 | 24 | $children[] = $this->getItemByGuid($childGuid); |
|
701 | 24 | } |
|
702 | 24 | } |
|
703 | 24 | return $children; |
|
704 | } |
||
705 | |||
706 | /** |
||
707 | * @inheritdoc |
||
708 | */ |
||
709 | 5 | public function hasChild($parent, $child) |
|
710 | { |
||
711 | 5 | list($parentGuid, $childGuid) = $this->db->executeCommand('HMGET', [$this->getItemMappingKey(), $parent->name, $child->name]); |
|
712 | 5 | $result = (int)$this->db->executeCommand('SISMEMBER', [$this->getItemChildrenKey($parentGuid), $childGuid]); |
|
713 | |||
714 | 5 | return $result === 1; |
|
715 | |||
716 | } |
||
717 | |||
718 | /** |
||
719 | * @inheritdoc |
||
720 | */ |
||
721 | 1 | public function revokeAll($userId) |
|
722 | { |
||
723 | 1 | if (empty($userId) === true) { |
|
724 | 1 | return false; |
|
725 | } |
||
726 | 1 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); |
|
727 | 1 | $this->db->executeCommand('MULTI'); |
|
728 | 1 | if (count($roleGuids) > 0) { |
|
729 | 1 | foreach ($roleGuids as $roleGuid) { |
|
730 | 1 | $this->db->executeCommand('ZREM', [$this->getRoleAssignmentsKey($roleGuid), $userId]); |
|
731 | 1 | } |
|
732 | 1 | } |
|
733 | 1 | $this->db->executeCommand('DEL', [$this->getUserAssignmentsKey($userId)]); |
|
734 | 1 | $this->db->executeCommand('EXEC'); |
|
735 | 1 | return true; |
|
736 | |||
737 | } |
||
738 | |||
739 | /** |
||
740 | * @inheritdoc |
||
741 | */ |
||
742 | 1 | public function revoke($role, $userId) |
|
743 | { |
||
744 | 1 | if (empty($userId) === true) { |
|
745 | 1 | return false; |
|
746 | } |
||
747 | 1 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $role->name]); |
|
748 | |||
749 | 1 | $this->db->executeCommand('MULTI'); |
|
750 | 1 | $this->db->executeCommand('ZREM', [$this->getUserAssignmentsKey($userId), $roleGuid]); |
|
751 | 1 | $this->db->executeCommand('ZREM', [$this->getRoleAssignmentsKey($roleGuid), $userId]); |
|
752 | 1 | $this->db->executeCommand('EXEC'); |
|
753 | 1 | return true; |
|
754 | } |
||
755 | |||
756 | /** |
||
757 | * @inheritdoc |
||
758 | */ |
||
759 | 1 | public function removeAllRoles() |
|
760 | { |
||
761 | 1 | $this->removeAllItems(Item::TYPE_ROLE); |
|
762 | 1 | } |
|
763 | |||
764 | /** |
||
765 | * @inheritdoc |
||
766 | */ |
||
767 | 1 | public function removeAllRules() |
|
768 | { |
||
769 | 1 | $rules = $this->getRules(); |
|
770 | 1 | foreach($rules as $rule) { |
|
771 | 1 | $this->removeRule($rule); |
|
772 | 1 | } |
|
773 | 1 | } |
|
774 | |||
775 | /** |
||
776 | * @inheritdoc |
||
777 | */ |
||
778 | 1 | public function removeAllPermissions() |
|
779 | { |
||
780 | 1 | $this->removeAllItems(Item::TYPE_PERMISSION); |
|
781 | 1 | } |
|
782 | |||
783 | /** |
||
784 | * @inheritdoc |
||
785 | */ |
||
786 | 31 | public function removeAll() |
|
787 | { |
||
788 | 31 | $authKeys = []; |
|
789 | 31 | $nextCursor = 0; |
|
790 | do { |
||
791 | 31 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $this->globalMatchKey]); |
|
792 | 31 | $authKeys = array_merge($authKeys, $keys); |
|
793 | |||
794 | 31 | } while($nextCursor != 0); |
|
795 | |||
796 | 31 | if (count($authKeys) > 0) { |
|
797 | 29 | $this->db->executeCommand('DEL', $authKeys); |
|
798 | 29 | } |
|
799 | 31 | } |
|
800 | |||
801 | /** |
||
802 | * @inheritdoc |
||
803 | */ |
||
804 | 1 | public function removeAllAssignments() |
|
805 | { |
||
806 | 1 | $roleAssignKey = $this->getRoleAssignmentsKey('*'); |
|
807 | 1 | $userAssignKey = $this->getUserAssignmentsKey('*'); |
|
808 | 1 | $assignmentKeys = []; |
|
809 | |||
810 | 1 | $nextCursor = 0; |
|
811 | do { |
||
812 | 1 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $roleAssignKey]); |
|
813 | 1 | $assignmentKeys = array_merge($assignmentKeys, $keys); |
|
814 | |||
815 | 1 | } while($nextCursor != 0); |
|
816 | |||
817 | 1 | $nextCursor = 0; |
|
818 | do { |
||
819 | 1 | list($nextCursor, $keys) = $this->db->executeCommand('SCAN', [$nextCursor, 'MATCH', $userAssignKey]); |
|
820 | 1 | $assignmentKeys = array_merge($assignmentKeys, $keys); |
|
821 | |||
822 | 1 | } while($nextCursor != 0); |
|
823 | |||
824 | 1 | if (count($assignmentKeys) > 0) { |
|
825 | 1 | $this->db->executeCommand('DEL', $assignmentKeys); |
|
826 | 1 | } |
|
827 | 1 | } |
|
828 | |||
829 | /** |
||
830 | * @param integer $type |
||
831 | * @since XXX |
||
832 | */ |
||
833 | 2 | public function removeAllItems($type) |
|
834 | { |
||
835 | 2 | $items = $this->getItems($type); |
|
836 | 2 | foreach ($items as $item) { |
|
837 | 2 | $this->removeItem($item); |
|
838 | 2 | } |
|
839 | 2 | } |
|
840 | |||
841 | /** |
||
842 | * @inheritdoc |
||
843 | */ |
||
844 | 4 | public function getRolesByUser($userId) |
|
845 | { |
||
846 | 4 | if (!isset($userId) || $userId === '') { |
|
847 | 1 | return []; |
|
848 | } |
||
849 | 4 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); |
|
850 | 4 | $roles = []; |
|
851 | 4 | if (count($roleGuids) > 0) { |
|
852 | 4 | foreach ($roleGuids as $roleGuid) { |
|
853 | 4 | $isRole = (int)$this->db->executeCommand('SISMEMBER', [$this->getTypeItemsKey(Item::TYPE_ROLE), $roleGuid]); |
|
854 | 4 | if ($isRole === 1) { |
|
855 | 4 | $item = $this->getItemByGuid($roleGuid); |
|
856 | 4 | $roles[$item->name] = $item; |
|
857 | 4 | } |
|
858 | 4 | } |
|
859 | 4 | } |
|
860 | |||
861 | 4 | return $roles; |
|
862 | } |
||
863 | |||
864 | /** |
||
865 | * @inheritdoc |
||
866 | */ |
||
867 | 2 | public function getUserIdsByRole($roleName) |
|
868 | { |
||
869 | 2 | if (empty($roleName)) { |
|
870 | 1 | return []; |
|
871 | } |
||
872 | 1 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); |
|
873 | 1 | $userIds = []; |
|
874 | 1 | if ($roleGuid !== null) { |
|
875 | 1 | $userIds = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getRoleAssignmentsKey($roleGuid), '-inf', '+inf']); |
|
876 | 1 | } |
|
877 | 1 | return $userIds; |
|
878 | |||
879 | } |
||
880 | |||
881 | /** |
||
882 | * @inheritdoc |
||
883 | */ |
||
884 | 20 | public function assign($role, $userId) |
|
885 | { |
||
886 | 20 | $assignment = new Assignment([ |
|
887 | 20 | 'userId' => $userId, |
|
888 | 20 | 'roleName' => $role->name, |
|
889 | 20 | 'createdAt' => time(), |
|
890 | 20 | ]); |
|
891 | 20 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $role->name]); |
|
892 | |||
893 | 20 | $this->db->executeCommand('MULTI'); |
|
894 | 20 | $this->db->executeCommand('ZADD', [$this->getUserAssignmentsKey($userId), $assignment->createdAt, $roleGuid]); |
|
895 | 20 | $this->db->executeCommand('ZADD', [$this->getRoleAssignmentsKey($roleGuid), $assignment->createdAt, $userId]); |
|
896 | 20 | $this->db->executeCommand('EXEC'); |
|
897 | 20 | return $assignment; |
|
898 | } |
||
899 | |||
900 | /** |
||
901 | * @inheritdoc |
||
902 | */ |
||
903 | 1 | public function getPermissionsByUser($userId) |
|
904 | { |
||
905 | 1 | $rolesGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf']); |
|
906 | 1 | $permissions = []; |
|
907 | 1 | if (count($rolesGuids) > 0) { |
|
908 | 1 | $permissionsGuid = []; |
|
909 | 1 | foreach($rolesGuids as $roleGuid) { |
|
910 | 1 | $isPerm = (int)$this->db->executeCommand('SISMEMBER', [$this->getTypeItemsKey(Item::TYPE_PERMISSION), $roleGuid]); |
|
911 | 1 | if ($isPerm === 1) { |
|
912 | 1 | $permissionsGuid[] = $roleGuid; |
|
913 | 1 | } |
|
914 | 1 | } |
|
915 | 1 | foreach ($rolesGuids as $roleGuid) { |
|
916 | 1 | list(, $permGuids) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_PERMISSION); |
|
917 | 1 | $permissionsGuid = array_merge($permissionsGuid, $permGuids); |
|
918 | 1 | } |
|
919 | 1 | foreach($permissionsGuid as $permissionGuid) { |
|
920 | 1 | $item = $this->getItemByGuid($permissionGuid); |
|
921 | 1 | $permissions[$item->name] = $item; |
|
922 | 1 | } |
|
923 | 1 | } |
|
924 | 1 | return $permissions; |
|
925 | } |
||
926 | |||
927 | /** |
||
928 | * @inheritdoc |
||
929 | */ |
||
930 | 1 | public function getChildRoles($roleName) |
|
931 | { |
||
932 | 1 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); |
|
933 | 1 | if (is_null($roleGuid)) { |
|
934 | throw new InvalidParamException("Role \"$roleName\" not found."); |
||
935 | } |
||
936 | 1 | list(, $rolesGuid) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_ROLE); |
|
937 | |||
938 | 1 | $roles[$roleName] = $this->getRole($roleName); |
|
0 ignored issues
–
show
|
|||
939 | 1 | foreach($rolesGuid as $roleGuid) { |
|
940 | 1 | $item = $this->getItemByGuid($roleGuid); |
|
941 | 1 | $roles[$item->name] = $item; |
|
942 | 1 | } |
|
943 | 1 | return $roles; |
|
0 ignored issues
–
show
The expression
return $roles; seems to be an array , but some of its elements' types (null ) are incompatible with the return type declared by the interface yii\rbac\ManagerInterface::getChildRoles of type yii\rbac\Role[] .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class BlogPost extends Post {
public function getAuthor() {
return 'Johannes';
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
944 | } |
||
945 | |||
946 | /** |
||
947 | * @inheritdoc |
||
948 | */ |
||
949 | 1 | public function getPermissionsByRole($roleName) |
|
950 | { |
||
951 | 1 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); |
|
952 | 1 | $permissions = []; |
|
953 | 1 | list(, $permissionsGuid) = $this->getChildrenRecursiveGuid($roleGuid, Item::TYPE_PERMISSION); |
|
954 | 1 | foreach($permissionsGuid as $permissionGuid) { |
|
955 | 1 | $item = $this->getItemByGuid($permissionGuid); |
|
956 | 1 | $permissions[$item->name] = $item; |
|
957 | 1 | } |
|
958 | 1 | return $permissions; |
|
959 | } |
||
960 | |||
961 | /** |
||
962 | * @param string $itemGuid item unique ID |
||
963 | * @param integer $type Item type |
||
964 | * @return array |
||
965 | * @since XXX |
||
966 | */ |
||
967 | 3 | protected function getChildrenRecursiveGuid($itemGuid, $type) |
|
968 | { |
||
969 | 3 | $childrenGuid = $this->db->executeCommand('SMEMBERS', [$this->getItemChildrenKey($itemGuid)]); |
|
970 | 3 | $typedChildrenGuid = $this->db->executeCommand('SINTER', [$this->getItemChildrenKey($itemGuid), $this->getTypeItemsKey($type)]); |
|
971 | 3 | foreach($childrenGuid as $childGuid) { |
|
972 | 3 | list($subChildrenGuid, $subTypedChildrenGuid) = $this->getChildrenRecursiveGuid($childGuid, $type); |
|
973 | 3 | $childrenGuid = array_merge($childrenGuid, $subChildrenGuid); |
|
974 | 3 | $typedChildrenGuid = array_merge($typedChildrenGuid, $subTypedChildrenGuid); |
|
975 | 3 | } |
|
976 | 3 | return [$childrenGuid, $typedChildrenGuid]; |
|
977 | } |
||
978 | |||
979 | /** |
||
980 | * @param Item $parent parent item |
||
981 | * @param Item $child child item |
||
982 | * @return bool |
||
983 | * @since XXX |
||
984 | */ |
||
985 | 24 | protected function detectLoop(Item $parent, Item $child) |
|
986 | { |
||
987 | 24 | if ($child->name === $parent->name) { |
|
988 | 2 | return true; |
|
989 | } |
||
990 | 24 | foreach ($this->getChildren($child->name) as $grandchild) { |
|
991 | 20 | if ($this->detectLoop($parent, $grandchild)) { |
|
992 | 2 | return true; |
|
993 | } |
||
994 | 24 | } |
|
995 | 24 | return false; |
|
996 | } |
||
997 | |||
998 | /** |
||
999 | * @param string $itemName item name |
||
1000 | * @return array |
||
1001 | * @since XXX |
||
1002 | */ |
||
1003 | 1 | public function getParents($itemName) |
|
1004 | { |
||
1005 | 1 | $itemGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $itemName]); |
|
1006 | 1 | return $this->getParentsGuid($itemGuid); |
|
1007 | } |
||
1008 | |||
1009 | 1 | protected function getParentsGuid($itemGuid) |
|
1010 | { |
||
1011 | 1 | $parentsGuid = $this->db->executeCommand('SMEMBERS', [$this->getItemParentsKey($itemGuid)]); |
|
1012 | 1 | $parents = []; |
|
1013 | 1 | if (count($parentsGuid) > 0) { |
|
1014 | 1 | array_unshift($parentsGuid, $this->getItemMappingGuidKey()); |
|
1015 | 1 | $parents = $this->db->executeCommand('HMGET', $parentsGuid); |
|
1016 | 1 | } |
|
1017 | 1 | return $parents; |
|
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * @inheritdoc |
||
1022 | */ |
||
1023 | 3 | public function getAssignments($userId) |
|
1024 | { |
||
1025 | 3 | $roleGuids = $this->db->executeCommand('ZRANGEBYSCORE', [$this->getUserAssignmentsKey($userId), '-inf', '+inf', 'WITHSCORES']); |
|
1026 | 3 | $assignments = []; |
|
1027 | 3 | if (count($roleGuids) > 0) { |
|
1028 | 3 | $guids = []; |
|
1029 | 3 | $dates = []; |
|
1030 | 3 | $nbRolesGuids = count($roleGuids); |
|
1031 | 3 | for($i=0; $i < $nbRolesGuids; $i = $i + 2) { |
|
1032 | 3 | $guids[] = $roleGuids[$i]; |
|
1033 | 3 | $dates[] = $roleGuids[($i + 1)]; |
|
1034 | 3 | } |
|
1035 | 3 | array_unshift($guids, $this->getItemMappingGuidKey()); |
|
1036 | 3 | $names = $this->db->executeCommand('HMGET', $guids); |
|
1037 | 3 | foreach ($names as $i => $name) { |
|
1038 | 3 | $assignments[$name] = new Assignment([ |
|
1039 | 3 | 'userId' => $userId, |
|
1040 | 3 | 'roleName' => $name, |
|
1041 | 3 | 'createdAt' => $dates[$i], |
|
1042 | 3 | ]); |
|
1043 | 3 | } |
|
1044 | 3 | } |
|
1045 | |||
1046 | 3 | return $assignments; |
|
1047 | |||
1048 | } |
||
1049 | |||
1050 | /** |
||
1051 | * @inheritdoc |
||
1052 | */ |
||
1053 | public function getAssignment($roleName, $userId) |
||
1054 | { |
||
1055 | $roleGuid = $this->db->executeCommand('HGET', [$this->getItemMappingKey(), $roleName]); |
||
1056 | $assignment = null; |
||
1057 | if ($roleGuid !== null) { |
||
1058 | $assignmentScore = $this->db->executeCommand('ZSCORE', [$this->getUserAssignmentsKey($userId), $roleGuid]); |
||
1059 | if ($assignmentScore !== null) { |
||
1060 | $assignment = new Assignment([ |
||
1061 | 'userId' => $userId, |
||
1062 | 'roleName' => $roleName, |
||
1063 | 'createdAt' => $assignmentScore, |
||
1064 | ]); |
||
1065 | } |
||
1066 | } |
||
1067 | return $assignment; |
||
1068 | } |
||
1069 | |||
1070 | /** |
||
1071 | * @inheritdoc |
||
1072 | */ |
||
1073 | 2 | public function checkAccess($userId, $permissionName, $params = []) |
|
1074 | { |
||
1075 | 2 | $assignments = $this->getAssignments($userId); |
|
1076 | 2 | return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments); |
|
1077 | } |
||
1078 | |||
1079 | |||
1080 | /** |
||
1081 | * @param Item $parent parent item |
||
1082 | * @param Item $child child item |
||
1083 | * @return bool |
||
1084 | * @since XXX |
||
1085 | */ |
||
1086 | 1 | public function canAddChild($parent, $child) |
|
1087 | { |
||
1088 | 1 | return !$this->detectLoop($parent, $child); |
|
1089 | } |
||
1090 | |||
1091 | /** |
||
1092 | * @param string|integer $user user ID |
||
1093 | * @param string $itemName current item name |
||
1094 | * @param array $params parameters applied in rule |
||
1095 | * @param Assignment[] $assignments |
||
1096 | * @return bool |
||
1097 | * @since XXX |
||
1098 | * @throws \yii\base\InvalidConfigException |
||
1099 | */ |
||
1100 | 2 | protected function checkAccessRecursive($user, $itemName, $params, $assignments) |
|
1101 | { |
||
1102 | 2 | if (($item = $this->getItem($itemName)) === null) { |
|
1103 | 1 | return false; |
|
1104 | } |
||
1105 | 2 | Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__); |
|
1106 | 2 | if (!$this->executeRule($user, $item, $params)) { |
|
1107 | 2 | return false; |
|
1108 | } |
||
1109 | 2 | if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) { |
|
1110 | 2 | return true; |
|
1111 | } |
||
1112 | 1 | $parents = $this->getParents($itemName); |
|
1113 | 1 | foreach ($parents as $parent) { |
|
1114 | 1 | if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) { |
|
1115 | 1 | return true; |
|
1116 | } |
||
1117 | 1 | } |
|
1118 | 1 | return false; |
|
1119 | } |
||
1120 | |||
1121 | /** |
||
1122 | * @param array $dataRow |
||
1123 | * @return Permission|Role |
||
1124 | * @since XXX |
||
1125 | */ |
||
1126 | 25 | protected function populateItem($dataRow) |
|
1127 | { |
||
1128 | 25 | $class = $dataRow['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); |
|
1129 | 25 | if (!isset($dataRow['data']) || ($data = @unserialize($dataRow['data'])) === false) { |
|
1130 | $data = null; |
||
1131 | } |
||
1132 | |||
1133 | 25 | return new $class([ |
|
1134 | 25 | 'name' => $dataRow['name'], |
|
1135 | 25 | 'type' => $dataRow['type'], |
|
1136 | 25 | 'description' => isset($dataRow['description']) ? $dataRow['description'] : null, |
|
1137 | 25 | 'ruleName' => isset($dataRow['ruleName']) ? $dataRow['ruleName'] : null, |
|
1138 | 25 | 'data' => $data, |
|
1139 | 25 | 'createdAt' => $dataRow['createdAt'], |
|
1140 | 25 | 'updatedAt' => $dataRow['updatedAt'], |
|
1141 | 25 | ]); |
|
1142 | } |
||
1143 | } |
||
1144 |
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.
Let’s take a look at an example:
As you can see in this example, the array
$myArray
is initialized the first time when the foreach loop is entered. You can also see that the value of thebar
key is only written conditionally; thus, its value might result from a previous iteration.This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.