1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\rbac; |
9
|
|
|
|
10
|
|
|
use Yii; |
11
|
|
|
use yii\base\InvalidArgumentException; |
12
|
|
|
use yii\base\InvalidCallException; |
13
|
|
|
use yii\caching\CacheInterface; |
14
|
|
|
use yii\db\Connection; |
15
|
|
|
use yii\db\Expression; |
16
|
|
|
use yii\db\Query; |
17
|
|
|
use yii\di\Instance; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* DbManager represents an authorization manager that stores authorization information in database. |
21
|
|
|
* |
22
|
|
|
* The database connection is specified by [[db]]. The database schema could be initialized by applying migration: |
23
|
|
|
* |
24
|
|
|
* ``` |
25
|
|
|
* yii migrate --migrationPath=@yii/rbac/migrations/ |
26
|
|
|
* ``` |
27
|
|
|
* |
28
|
|
|
* If you don't want to use migration and need SQL instead, files for all databases are in migrations directory. |
29
|
|
|
* |
30
|
|
|
* You may change the names of the tables used to store the authorization and rule data by setting [[itemTable]], |
31
|
|
|
* [[itemChildTable]], [[assignmentTable]] and [[ruleTable]]. |
32
|
|
|
* |
33
|
|
|
* For more details and usage information on DbManager, see the [guide article on security authorization](guide:security-authorization). |
34
|
|
|
* |
35
|
|
|
* @author Qiang Xue <[email protected]> |
36
|
|
|
* @author Alexander Kochetov <[email protected]> |
37
|
|
|
* @since 2.0 |
38
|
|
|
*/ |
39
|
|
|
class DbManager extends BaseManager |
40
|
|
|
{ |
41
|
|
|
/** |
42
|
|
|
* @var Connection|array|string the DB connection object or the application component ID of the DB connection. |
43
|
|
|
* After the DbManager object is created, if you want to change this property, you should only assign it |
44
|
|
|
* with a DB connection object. |
45
|
|
|
* Starting from version 2.0.2, this can also be a configuration array for creating the object. |
46
|
|
|
*/ |
47
|
|
|
public $db = 'db'; |
48
|
|
|
/** |
49
|
|
|
* @var string the name of the table storing authorization items. Defaults to "auth_item". |
50
|
|
|
*/ |
51
|
|
|
public $itemTable = '{{%auth_item}}'; |
52
|
|
|
/** |
53
|
|
|
* @var string the name of the table storing authorization item hierarchy. Defaults to "auth_item_child". |
54
|
|
|
*/ |
55
|
|
|
public $itemChildTable = '{{%auth_item_child}}'; |
56
|
|
|
/** |
57
|
|
|
* @var string the name of the table storing authorization item assignments. Defaults to "auth_assignment". |
58
|
|
|
*/ |
59
|
|
|
public $assignmentTable = '{{%auth_assignment}}'; |
60
|
|
|
/** |
61
|
|
|
* @var string the name of the table storing rules. Defaults to "auth_rule". |
62
|
|
|
*/ |
63
|
|
|
public $ruleTable = '{{%auth_rule}}'; |
64
|
|
|
/** |
65
|
|
|
* @var CacheInterface|array|string the cache used to improve RBAC performance. This can be one of the following: |
66
|
|
|
* |
67
|
|
|
* - an application component ID (e.g. `cache`) |
68
|
|
|
* - a configuration array |
69
|
|
|
* - a [[\yii\caching\Cache]] object |
70
|
|
|
* |
71
|
|
|
* When this is not set, it means caching is not enabled. |
72
|
|
|
* |
73
|
|
|
* Note that by enabling RBAC cache, all auth items, rules and auth item parent-child relationships will |
74
|
|
|
* be cached and loaded into memory. This will improve the performance of RBAC permission check. However, |
75
|
|
|
* it does require extra memory and as a result may not be appropriate if your RBAC system contains too many |
76
|
|
|
* auth items. You should seek other RBAC implementations (e.g. RBAC based on Redis storage) in this case. |
77
|
|
|
* |
78
|
|
|
* Also note that if you modify RBAC items, rules or parent-child relationships from outside of this component, |
79
|
|
|
* you have to manually call [[invalidateCache()]] to ensure data consistency. |
80
|
|
|
* |
81
|
|
|
* @since 2.0.3 |
82
|
|
|
*/ |
83
|
|
|
public $cache; |
84
|
|
|
/** |
85
|
|
|
* @var string the key used to store RBAC data in cache |
86
|
|
|
* @see cache |
87
|
|
|
* @since 2.0.3 |
88
|
|
|
*/ |
89
|
|
|
public $cacheKey = 'rbac'; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* @var Item[] all auth items (name => Item) |
93
|
|
|
*/ |
94
|
|
|
protected $items; |
95
|
|
|
/** |
96
|
|
|
* @var Rule[] all auth rules (name => Rule) |
97
|
|
|
*/ |
98
|
|
|
protected $rules; |
99
|
|
|
/** |
100
|
|
|
* @var array auth item parent-child relationships (childName => list of parents) |
101
|
|
|
*/ |
102
|
|
|
protected $parents; |
103
|
|
|
|
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Initializes the application component. |
107
|
|
|
* This method overrides the parent implementation by establishing the database connection. |
108
|
|
|
*/ |
109
|
245 |
|
public function init() |
110
|
|
|
{ |
111
|
245 |
|
parent::init(); |
112
|
245 |
|
$this->db = Instance::ensure($this->db, Connection::className()); |
|
|
|
|
113
|
245 |
|
if ($this->cache !== null) { |
114
|
98 |
|
$this->cache = Instance::ensure($this->cache, 'yii\caching\CacheInterface'); |
115
|
|
|
} |
116
|
245 |
|
} |
117
|
|
|
|
118
|
|
|
private $_checkAccessAssignments = []; |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* {@inheritdoc} |
122
|
|
|
*/ |
123
|
30 |
|
public function checkAccess($userId, $permissionName, $params = []) |
124
|
|
|
{ |
125
|
30 |
|
if (isset($this->_checkAccessAssignments[(string) $userId])) { |
126
|
30 |
|
$assignments = $this->_checkAccessAssignments[(string) $userId]; |
127
|
|
|
} else { |
128
|
30 |
|
$assignments = $this->getAssignments($userId); |
129
|
30 |
|
$this->_checkAccessAssignments[(string) $userId] = $assignments; |
130
|
|
|
} |
131
|
|
|
|
132
|
30 |
|
if ($this->hasNoAssignments($assignments)) { |
133
|
|
|
return false; |
134
|
|
|
} |
135
|
|
|
|
136
|
30 |
|
$this->loadFromCache(); |
137
|
30 |
|
if ($this->items !== null) { |
138
|
15 |
|
return $this->checkAccessFromCache($userId, $permissionName, $params, $assignments); |
139
|
|
|
} |
140
|
|
|
|
141
|
15 |
|
return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Performs access check for the specified user based on the data loaded from cache. |
146
|
|
|
* This method is internally called by [[checkAccess()]] when [[cache]] is enabled. |
147
|
|
|
* @param string|int $user the user ID. This should can be either an integer or a string representing |
148
|
|
|
* the unique identifier of a user. See [[\yii\web\User::id]]. |
149
|
|
|
* @param string $itemName the name of the operation that need access check |
150
|
|
|
* @param array $params name-value pairs that would be passed to rules associated |
151
|
|
|
* with the tasks and roles assigned to the user. A param with name 'user' is added to this array, |
152
|
|
|
* which holds the value of `$userId`. |
153
|
|
|
* @param Assignment[] $assignments the assignments to the specified user |
154
|
|
|
* @return bool whether the operations can be performed by the user. |
155
|
|
|
* @since 2.0.3 |
156
|
|
|
*/ |
157
|
15 |
|
protected function checkAccessFromCache($user, $itemName, $params, $assignments) |
158
|
|
|
{ |
159
|
15 |
|
if (!isset($this->items[$itemName])) { |
160
|
2 |
|
return false; |
161
|
|
|
} |
162
|
|
|
|
163
|
15 |
|
$item = $this->items[$itemName]; |
164
|
|
|
|
165
|
15 |
|
Yii::debug($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__); |
166
|
|
|
|
167
|
15 |
|
if (!$this->executeRule($user, $item, $params)) { |
168
|
10 |
|
return false; |
169
|
|
|
} |
170
|
|
|
|
171
|
15 |
|
if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) { |
172
|
11 |
|
return true; |
173
|
|
|
} |
174
|
|
|
|
175
|
11 |
|
if (!empty($this->parents[$itemName])) { |
176
|
7 |
|
foreach ($this->parents[$itemName] as $parent) { |
177
|
7 |
|
if ($this->checkAccessFromCache($user, $parent, $params, $assignments)) { |
178
|
7 |
|
return true; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
11 |
|
return false; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Performs access check for the specified user. |
188
|
|
|
* This method is internally called by [[checkAccess()]]. |
189
|
|
|
* @param string|int $user the user ID. This should can be either an integer or a string representing |
190
|
|
|
* the unique identifier of a user. See [[\yii\web\User::id]]. |
191
|
|
|
* @param string $itemName the name of the operation that need access check |
192
|
|
|
* @param array $params name-value pairs that would be passed to rules associated |
193
|
|
|
* with the tasks and roles assigned to the user. A param with name 'user' is added to this array, |
194
|
|
|
* which holds the value of `$userId`. |
195
|
|
|
* @param Assignment[] $assignments the assignments to the specified user |
196
|
|
|
* @return bool whether the operations can be performed by the user. |
197
|
|
|
*/ |
198
|
15 |
|
protected function checkAccessRecursive($user, $itemName, $params, $assignments) |
199
|
|
|
{ |
200
|
15 |
|
if (($item = $this->getItem($itemName)) === null) { |
201
|
3 |
|
return false; |
202
|
|
|
} |
203
|
|
|
|
204
|
15 |
|
Yii::debug($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__); |
205
|
|
|
|
206
|
15 |
|
if (!$this->executeRule($user, $item, $params)) { |
207
|
15 |
|
return false; |
208
|
|
|
} |
209
|
|
|
|
210
|
15 |
|
if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) { |
211
|
9 |
|
return true; |
212
|
|
|
} |
213
|
|
|
|
214
|
9 |
|
$query = new Query(); |
215
|
9 |
|
$parents = $query->select(['parent']) |
216
|
9 |
|
->from($this->itemChildTable) |
217
|
9 |
|
->where(['child' => $itemName]) |
218
|
9 |
|
->column($this->db); |
219
|
9 |
|
foreach ($parents as $parent) { |
220
|
3 |
|
if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) { |
221
|
3 |
|
return true; |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
|
225
|
9 |
|
return false; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* {@inheritdoc} |
230
|
|
|
*/ |
231
|
84 |
|
protected function getItem($name) |
232
|
|
|
{ |
233
|
84 |
|
if (empty($name)) { |
234
|
3 |
|
return null; |
235
|
|
|
} |
236
|
|
|
|
237
|
84 |
|
if (!empty($this->items[$name])) { |
238
|
9 |
|
return $this->items[$name]; |
239
|
|
|
} |
240
|
|
|
|
241
|
75 |
|
$row = (new Query())->from($this->itemTable) |
242
|
75 |
|
->where(['name' => $name]) |
243
|
75 |
|
->one($this->db); |
244
|
|
|
|
245
|
75 |
|
if ($row === false) { |
246
|
13 |
|
return null; |
247
|
|
|
} |
248
|
|
|
|
249
|
75 |
|
return $this->populateItem($row); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Returns a value indicating whether the database supports cascading update and delete. |
254
|
|
|
* The default implementation will return false for SQLite database and true for all other databases. |
255
|
|
|
* @return bool whether the database supports cascading update and delete. |
256
|
|
|
*/ |
257
|
35 |
|
protected function supportsCascadeUpdate() |
258
|
|
|
{ |
259
|
35 |
|
return strncmp($this->db->getDriverName(), 'sqlite', 6) !== 0; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* {@inheritdoc} |
264
|
|
|
*/ |
265
|
220 |
|
protected function addItem($item) |
266
|
|
|
{ |
267
|
220 |
|
$time = time(); |
268
|
220 |
|
if ($item->createdAt === null) { |
269
|
220 |
|
$item->createdAt = $time; |
270
|
|
|
} |
271
|
220 |
|
if ($item->updatedAt === null) { |
272
|
220 |
|
$item->updatedAt = $time; |
273
|
|
|
} |
274
|
220 |
|
$this->db->createCommand() |
275
|
220 |
|
->insert($this->itemTable, [ |
276
|
220 |
|
'name' => $item->name, |
277
|
220 |
|
'type' => $item->type, |
278
|
220 |
|
'description' => $item->description, |
279
|
220 |
|
'rule_name' => $item->ruleName, |
280
|
220 |
|
'data' => $item->data === null ? null : serialize($item->data), |
281
|
220 |
|
'created_at' => $item->createdAt, |
282
|
220 |
|
'updated_at' => $item->updatedAt, |
283
|
220 |
|
])->execute(); |
284
|
|
|
|
285
|
220 |
|
$this->invalidateCache(); |
286
|
|
|
|
287
|
220 |
|
return true; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* {@inheritdoc} |
292
|
|
|
*/ |
293
|
5 |
|
protected function removeItem($item) |
294
|
|
|
{ |
295
|
5 |
|
if (!$this->supportsCascadeUpdate()) { |
296
|
1 |
|
$this->db->createCommand() |
297
|
1 |
|
->delete($this->itemChildTable, ['or', '[[parent]]=:name', '[[child]]=:name'], [':name' => $item->name]) |
298
|
1 |
|
->execute(); |
299
|
1 |
|
$this->db->createCommand() |
300
|
1 |
|
->delete($this->assignmentTable, ['item_name' => $item->name]) |
301
|
1 |
|
->execute(); |
302
|
|
|
} |
303
|
|
|
|
304
|
5 |
|
$this->db->createCommand() |
305
|
5 |
|
->delete($this->itemTable, ['name' => $item->name]) |
306
|
5 |
|
->execute(); |
307
|
|
|
|
308
|
5 |
|
$this->invalidateCache(); |
309
|
|
|
|
310
|
5 |
|
return true; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* {@inheritdoc} |
315
|
|
|
*/ |
316
|
15 |
|
protected function updateItem($name, $item) |
317
|
|
|
{ |
318
|
15 |
|
if ($item->name !== $name && !$this->supportsCascadeUpdate()) { |
319
|
3 |
|
$this->db->createCommand() |
320
|
3 |
|
->update($this->itemChildTable, ['parent' => $item->name], ['parent' => $name]) |
321
|
3 |
|
->execute(); |
322
|
3 |
|
$this->db->createCommand() |
323
|
3 |
|
->update($this->itemChildTable, ['child' => $item->name], ['child' => $name]) |
324
|
3 |
|
->execute(); |
325
|
3 |
|
$this->db->createCommand() |
326
|
3 |
|
->update($this->assignmentTable, ['item_name' => $item->name], ['item_name' => $name]) |
327
|
3 |
|
->execute(); |
328
|
|
|
} |
329
|
|
|
|
330
|
15 |
|
$item->updatedAt = time(); |
331
|
|
|
|
332
|
15 |
|
$this->db->createCommand() |
333
|
15 |
|
->update($this->itemTable, [ |
334
|
15 |
|
'name' => $item->name, |
335
|
15 |
|
'description' => $item->description, |
336
|
15 |
|
'rule_name' => $item->ruleName, |
337
|
15 |
|
'data' => $item->data === null ? null : serialize($item->data), |
338
|
15 |
|
'updated_at' => $item->updatedAt, |
339
|
|
|
], [ |
340
|
15 |
|
'name' => $name, |
341
|
15 |
|
])->execute(); |
342
|
|
|
|
343
|
15 |
|
$this->invalidateCache(); |
344
|
|
|
|
345
|
15 |
|
return true; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
/** |
349
|
|
|
* {@inheritdoc} |
350
|
|
|
*/ |
351
|
130 |
|
protected function addRule($rule) |
352
|
|
|
{ |
353
|
130 |
|
$time = time(); |
354
|
130 |
|
if ($rule->createdAt === null) { |
355
|
130 |
|
$rule->createdAt = $time; |
356
|
|
|
} |
357
|
130 |
|
if ($rule->updatedAt === null) { |
358
|
130 |
|
$rule->updatedAt = $time; |
359
|
|
|
} |
360
|
130 |
|
$this->db->createCommand() |
361
|
130 |
|
->insert($this->ruleTable, [ |
362
|
130 |
|
'name' => $rule->name, |
363
|
130 |
|
'data' => serialize($rule), |
364
|
130 |
|
'created_at' => $rule->createdAt, |
365
|
130 |
|
'updated_at' => $rule->updatedAt, |
366
|
130 |
|
])->execute(); |
367
|
|
|
|
368
|
130 |
|
$this->invalidateCache(); |
369
|
|
|
|
370
|
130 |
|
return true; |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* {@inheritdoc} |
375
|
|
|
*/ |
376
|
5 |
|
protected function updateRule($name, $rule) |
377
|
|
|
{ |
378
|
5 |
|
if ($rule->name !== $name && !$this->supportsCascadeUpdate()) { |
379
|
1 |
|
$this->db->createCommand() |
380
|
1 |
|
->update($this->itemTable, ['rule_name' => $rule->name], ['rule_name' => $name]) |
381
|
1 |
|
->execute(); |
382
|
|
|
} |
383
|
|
|
|
384
|
5 |
|
$rule->updatedAt = time(); |
385
|
|
|
|
386
|
5 |
|
$this->db->createCommand() |
387
|
5 |
|
->update($this->ruleTable, [ |
388
|
5 |
|
'name' => $rule->name, |
389
|
5 |
|
'data' => serialize($rule), |
390
|
5 |
|
'updated_at' => $rule->updatedAt, |
391
|
|
|
], [ |
392
|
5 |
|
'name' => $name, |
393
|
5 |
|
])->execute(); |
394
|
|
|
|
395
|
5 |
|
$this->invalidateCache(); |
396
|
|
|
|
397
|
5 |
|
return true; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* {@inheritdoc} |
402
|
|
|
*/ |
403
|
5 |
|
protected function removeRule($rule) |
404
|
|
|
{ |
405
|
5 |
|
if (!$this->supportsCascadeUpdate()) { |
406
|
1 |
|
$this->db->createCommand() |
407
|
1 |
|
->update($this->itemTable, ['rule_name' => null], ['rule_name' => $rule->name]) |
408
|
1 |
|
->execute(); |
409
|
|
|
} |
410
|
|
|
|
411
|
5 |
|
$this->db->createCommand() |
412
|
5 |
|
->delete($this->ruleTable, ['name' => $rule->name]) |
413
|
5 |
|
->execute(); |
414
|
|
|
|
415
|
5 |
|
$this->invalidateCache(); |
416
|
|
|
|
417
|
5 |
|
return true; |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* {@inheritdoc} |
422
|
|
|
*/ |
423
|
20 |
|
protected function getItems($type) |
424
|
|
|
{ |
425
|
20 |
|
$query = (new Query()) |
426
|
20 |
|
->from($this->itemTable) |
427
|
20 |
|
->where(['type' => $type]); |
428
|
|
|
|
429
|
20 |
|
$items = []; |
430
|
20 |
|
foreach ($query->all($this->db) as $row) { |
431
|
20 |
|
$items[$row['name']] = $this->populateItem($row); |
432
|
|
|
} |
433
|
|
|
|
434
|
20 |
|
return $items; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Populates an auth item with the data fetched from database. |
439
|
|
|
* @param array $row the data from the auth item table |
440
|
|
|
* @return Item the populated auth item instance (either Role or Permission) |
441
|
|
|
*/ |
442
|
160 |
|
protected function populateItem($row) |
443
|
|
|
{ |
444
|
160 |
|
$class = $row['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); |
|
|
|
|
445
|
|
|
|
446
|
160 |
|
if (!isset($row['data']) || ($data = @unserialize(is_resource($row['data']) ? stream_get_contents($row['data']) : $row['data'])) === false) { |
447
|
160 |
|
$data = null; |
448
|
|
|
} |
449
|
|
|
|
450
|
160 |
|
return new $class([ |
451
|
160 |
|
'name' => $row['name'], |
452
|
160 |
|
'type' => $row['type'], |
453
|
160 |
|
'description' => $row['description'], |
454
|
160 |
|
'ruleName' => $row['rule_name'] ?: null, |
455
|
160 |
|
'data' => $data, |
456
|
160 |
|
'createdAt' => $row['created_at'], |
457
|
160 |
|
'updatedAt' => $row['updated_at'], |
458
|
|
|
]); |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* {@inheritdoc} |
463
|
|
|
* The roles returned by this method include the roles assigned via [[$defaultRoles]]. |
464
|
|
|
*/ |
465
|
25 |
|
public function getRolesByUser($userId) |
466
|
|
|
{ |
467
|
25 |
|
if ($this->isEmptyUserId($userId)) { |
468
|
5 |
|
return []; |
469
|
|
|
} |
470
|
|
|
|
471
|
20 |
|
$query = (new Query())->select('b.*') |
472
|
20 |
|
->from(['a' => $this->assignmentTable, 'b' => $this->itemTable]) |
473
|
20 |
|
->where('{{a}}.[[item_name]]={{b}}.[[name]]') |
474
|
20 |
|
->andWhere(['a.user_id' => (string) $userId]) |
475
|
20 |
|
->andWhere(['b.type' => Item::TYPE_ROLE]); |
476
|
|
|
|
477
|
20 |
|
$roles = $this->getDefaultRoleInstances(); |
478
|
20 |
|
foreach ($query->all($this->db) as $row) { |
479
|
20 |
|
$roles[$row['name']] = $this->populateItem($row); |
480
|
|
|
} |
481
|
|
|
|
482
|
20 |
|
return $roles; |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* {@inheritdoc} |
487
|
|
|
*/ |
488
|
5 |
|
public function getChildRoles($roleName) |
489
|
|
|
{ |
490
|
5 |
|
$role = $this->getRole($roleName); |
491
|
|
|
|
492
|
5 |
|
if ($role === null) { |
493
|
|
|
throw new InvalidArgumentException("Role \"$roleName\" not found."); |
494
|
|
|
} |
495
|
|
|
|
496
|
5 |
|
$result = []; |
497
|
5 |
|
$this->getChildrenRecursive($roleName, $this->getChildrenList(), $result); |
498
|
|
|
|
499
|
5 |
|
$roles = [$roleName => $role]; |
500
|
|
|
|
501
|
5 |
|
$roles += array_filter($this->getRoles(), function (Role $roleItem) use ($result) { |
502
|
5 |
|
return array_key_exists($roleItem->name, $result); |
503
|
5 |
|
}); |
504
|
|
|
|
505
|
5 |
|
return $roles; |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* {@inheritdoc} |
510
|
|
|
*/ |
511
|
5 |
|
public function getPermissionsByRole($roleName) |
512
|
|
|
{ |
513
|
5 |
|
$childrenList = $this->getChildrenList(); |
514
|
5 |
|
$result = []; |
515
|
5 |
|
$this->getChildrenRecursive($roleName, $childrenList, $result); |
516
|
5 |
|
if (empty($result)) { |
517
|
|
|
return []; |
518
|
|
|
} |
519
|
5 |
|
$query = (new Query())->from($this->itemTable)->where([ |
520
|
5 |
|
'type' => Item::TYPE_PERMISSION, |
521
|
5 |
|
'name' => array_keys($result), |
522
|
|
|
]); |
523
|
5 |
|
$permissions = []; |
524
|
5 |
|
foreach ($query->all($this->db) as $row) { |
525
|
5 |
|
$permissions[$row['name']] = $this->populateItem($row); |
526
|
|
|
} |
527
|
|
|
|
528
|
5 |
|
return $permissions; |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
/** |
532
|
|
|
* {@inheritdoc} |
533
|
|
|
*/ |
534
|
20 |
|
public function getPermissionsByUser($userId) |
535
|
|
|
{ |
536
|
20 |
|
if ($this->isEmptyUserId($userId)) { |
537
|
5 |
|
return []; |
538
|
|
|
} |
539
|
|
|
|
540
|
15 |
|
$directPermission = $this->getDirectPermissionsByUser($userId); |
541
|
15 |
|
$inheritedPermission = $this->getInheritedPermissionsByUser($userId); |
542
|
|
|
|
543
|
15 |
|
return array_merge($directPermission, $inheritedPermission); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Returns all permissions that are directly assigned to user. |
548
|
|
|
* @param string|int $userId the user ID (see [[\yii\web\User::id]]) |
549
|
|
|
* @return Permission[] all direct permissions that the user has. The array is indexed by the permission names. |
550
|
|
|
* @since 2.0.7 |
551
|
|
|
*/ |
552
|
15 |
|
protected function getDirectPermissionsByUser($userId) |
553
|
|
|
{ |
554
|
15 |
|
$query = (new Query())->select('b.*') |
555
|
15 |
|
->from(['a' => $this->assignmentTable, 'b' => $this->itemTable]) |
556
|
15 |
|
->where('{{a}}.[[item_name]]={{b}}.[[name]]') |
557
|
15 |
|
->andWhere(['a.user_id' => (string) $userId]) |
558
|
15 |
|
->andWhere(['b.type' => Item::TYPE_PERMISSION]); |
559
|
|
|
|
560
|
15 |
|
$permissions = []; |
561
|
15 |
|
foreach ($query->all($this->db) as $row) { |
562
|
15 |
|
$permissions[$row['name']] = $this->populateItem($row); |
563
|
|
|
} |
564
|
|
|
|
565
|
15 |
|
return $permissions; |
566
|
|
|
} |
567
|
|
|
|
568
|
|
|
/** |
569
|
|
|
* Returns all permissions that the user inherits from the roles assigned to him. |
570
|
|
|
* @param string|int $userId the user ID (see [[\yii\web\User::id]]) |
571
|
|
|
* @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names. |
572
|
|
|
* @since 2.0.7 |
573
|
|
|
*/ |
574
|
15 |
|
protected function getInheritedPermissionsByUser($userId) |
575
|
|
|
{ |
576
|
15 |
|
$query = (new Query())->select('item_name') |
577
|
15 |
|
->from($this->assignmentTable) |
578
|
15 |
|
->where(['user_id' => (string) $userId]); |
579
|
|
|
|
580
|
15 |
|
$childrenList = $this->getChildrenList(); |
581
|
15 |
|
$result = []; |
582
|
15 |
|
foreach ($query->column($this->db) as $roleName) { |
583
|
15 |
|
$this->getChildrenRecursive($roleName, $childrenList, $result); |
584
|
|
|
} |
585
|
|
|
|
586
|
15 |
|
if (empty($result)) { |
587
|
10 |
|
return []; |
588
|
|
|
} |
589
|
|
|
|
590
|
5 |
|
$query = (new Query())->from($this->itemTable)->where([ |
591
|
5 |
|
'type' => Item::TYPE_PERMISSION, |
592
|
5 |
|
'name' => array_keys($result), |
593
|
|
|
]); |
594
|
5 |
|
$permissions = []; |
595
|
5 |
|
foreach ($query->all($this->db) as $row) { |
596
|
5 |
|
$permissions[$row['name']] = $this->populateItem($row); |
597
|
|
|
} |
598
|
|
|
|
599
|
5 |
|
return $permissions; |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
/** |
603
|
|
|
* Returns the children for every parent. |
604
|
|
|
* @return array the children list. Each array key is a parent item name, |
605
|
|
|
* and the corresponding array value is a list of child item names. |
606
|
|
|
*/ |
607
|
25 |
|
protected function getChildrenList() |
608
|
|
|
{ |
609
|
25 |
|
$query = (new Query())->from($this->itemChildTable); |
610
|
25 |
|
$parents = []; |
611
|
25 |
|
foreach ($query->all($this->db) as $row) { |
612
|
15 |
|
$parents[$row['parent']][] = $row['child']; |
613
|
|
|
} |
614
|
|
|
|
615
|
25 |
|
return $parents; |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
/** |
619
|
|
|
* Recursively finds all children and grand children of the specified item. |
620
|
|
|
* @param string $name the name of the item whose children are to be looked for. |
621
|
|
|
* @param array $childrenList the child list built via [[getChildrenList()]] |
622
|
|
|
* @param array $result the children and grand children (in array keys) |
623
|
|
|
*/ |
624
|
25 |
|
protected function getChildrenRecursive($name, $childrenList, &$result) |
625
|
|
|
{ |
626
|
25 |
|
if (isset($childrenList[$name])) { |
627
|
15 |
|
foreach ($childrenList[$name] as $child) { |
628
|
15 |
|
$result[$child] = true; |
629
|
15 |
|
$this->getChildrenRecursive($child, $childrenList, $result); |
630
|
|
|
} |
631
|
|
|
} |
632
|
25 |
|
} |
633
|
|
|
|
634
|
|
|
/** |
635
|
|
|
* {@inheritdoc} |
636
|
|
|
*/ |
637
|
125 |
|
public function getRule($name) |
638
|
|
|
{ |
639
|
125 |
|
if ($this->rules !== null) { |
640
|
10 |
|
return isset($this->rules[$name]) ? $this->rules[$name] : null; |
641
|
|
|
} |
642
|
|
|
|
643
|
125 |
|
$row = (new Query())->select(['data']) |
644
|
125 |
|
->from($this->ruleTable) |
645
|
125 |
|
->where(['name' => $name]) |
646
|
125 |
|
->one($this->db); |
647
|
125 |
|
if ($row === false) { |
648
|
20 |
|
return null; |
649
|
|
|
} |
650
|
125 |
|
$data = $row['data']; |
651
|
125 |
|
if (is_resource($data)) { |
652
|
50 |
|
$data = stream_get_contents($data); |
653
|
|
|
} |
654
|
|
|
|
655
|
125 |
|
return unserialize($data); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* {@inheritdoc} |
660
|
|
|
*/ |
661
|
25 |
|
public function getRules() |
662
|
|
|
{ |
663
|
25 |
|
if ($this->rules !== null) { |
664
|
|
|
return $this->rules; |
665
|
|
|
} |
666
|
|
|
|
667
|
25 |
|
$query = (new Query())->from($this->ruleTable); |
668
|
|
|
|
669
|
25 |
|
$rules = []; |
670
|
25 |
|
foreach ($query->all($this->db) as $row) { |
671
|
15 |
|
$data = $row['data']; |
672
|
15 |
|
if (is_resource($data)) { |
673
|
6 |
|
$data = stream_get_contents($data); |
674
|
|
|
} |
675
|
15 |
|
$rules[$row['name']] = unserialize($data); |
676
|
|
|
} |
677
|
|
|
|
678
|
25 |
|
return $rules; |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
/** |
682
|
|
|
* {@inheritdoc} |
683
|
|
|
*/ |
684
|
15 |
|
public function getAssignment($roleName, $userId) |
685
|
|
|
{ |
686
|
15 |
|
if ($this->isEmptyUserId($userId)) { |
687
|
5 |
|
return null; |
688
|
|
|
} |
689
|
|
|
|
690
|
10 |
|
$row = (new Query())->from($this->assignmentTable) |
691
|
10 |
|
->where(['user_id' => (string) $userId, 'item_name' => $roleName]) |
692
|
10 |
|
->one($this->db); |
693
|
|
|
|
694
|
10 |
|
if ($row === false) { |
695
|
|
|
return null; |
696
|
|
|
} |
697
|
|
|
|
698
|
10 |
|
return new Assignment([ |
699
|
10 |
|
'userId' => $row['user_id'], |
700
|
10 |
|
'roleName' => $row['item_name'], |
701
|
10 |
|
'createdAt' => $row['created_at'], |
702
|
|
|
]); |
703
|
|
|
} |
704
|
|
|
|
705
|
|
|
/** |
706
|
|
|
* {@inheritdoc} |
707
|
|
|
*/ |
708
|
50 |
|
public function getAssignments($userId) |
709
|
|
|
{ |
710
|
50 |
|
if ($this->isEmptyUserId($userId)) { |
711
|
5 |
|
return []; |
712
|
|
|
} |
713
|
|
|
|
714
|
45 |
|
$query = (new Query()) |
715
|
45 |
|
->from($this->assignmentTable) |
716
|
45 |
|
->where(['user_id' => (string) $userId]); |
717
|
|
|
|
718
|
45 |
|
$assignments = []; |
719
|
45 |
|
foreach ($query->all($this->db) as $row) { |
720
|
35 |
|
$assignments[$row['item_name']] = new Assignment([ |
721
|
35 |
|
'userId' => $row['user_id'], |
722
|
35 |
|
'roleName' => $row['item_name'], |
723
|
35 |
|
'createdAt' => $row['created_at'], |
724
|
|
|
]); |
725
|
|
|
} |
726
|
|
|
|
727
|
45 |
|
return $assignments; |
728
|
|
|
} |
729
|
|
|
|
730
|
|
|
/** |
731
|
|
|
* {@inheritdoc} |
732
|
|
|
* @since 2.0.8 |
733
|
|
|
*/ |
734
|
5 |
|
public function canAddChild($parent, $child) |
735
|
|
|
{ |
736
|
5 |
|
return !$this->detectLoop($parent, $child); |
737
|
|
|
} |
738
|
|
|
|
739
|
|
|
/** |
740
|
|
|
* {@inheritdoc} |
741
|
|
|
*/ |
742
|
105 |
|
public function addChild($parent, $child) |
743
|
|
|
{ |
744
|
105 |
|
if ($parent->name === $child->name) { |
745
|
|
|
throw new InvalidArgumentException("Cannot add '{$parent->name}' as a child of itself."); |
746
|
|
|
} |
747
|
|
|
|
748
|
105 |
|
if ($parent instanceof Permission && $child instanceof Role) { |
749
|
|
|
throw new InvalidArgumentException('Cannot add a role as a child of a permission.'); |
750
|
|
|
} |
751
|
|
|
|
752
|
105 |
|
if ($this->detectLoop($parent, $child)) { |
753
|
|
|
throw new InvalidCallException("Cannot add '{$child->name}' as a child of '{$parent->name}'. A loop has been detected."); |
754
|
|
|
} |
755
|
|
|
|
756
|
105 |
|
$this->db->createCommand() |
757
|
105 |
|
->insert($this->itemChildTable, ['parent' => $parent->name, 'child' => $child->name]) |
758
|
105 |
|
->execute(); |
759
|
|
|
|
760
|
105 |
|
$this->invalidateCache(); |
761
|
|
|
|
762
|
105 |
|
return true; |
763
|
|
|
} |
764
|
|
|
|
765
|
|
|
/** |
766
|
|
|
* {@inheritdoc} |
767
|
|
|
*/ |
768
|
|
|
public function removeChild($parent, $child) |
769
|
|
|
{ |
770
|
|
|
$result = $this->db->createCommand() |
771
|
|
|
->delete($this->itemChildTable, ['parent' => $parent->name, 'child' => $child->name]) |
772
|
|
|
->execute() > 0; |
773
|
|
|
|
774
|
|
|
$this->invalidateCache(); |
775
|
|
|
|
776
|
|
|
return $result; |
777
|
|
|
} |
778
|
|
|
|
779
|
|
|
/** |
780
|
|
|
* {@inheritdoc} |
781
|
|
|
*/ |
782
|
|
|
public function removeChildren($parent) |
783
|
|
|
{ |
784
|
|
|
$result = $this->db->createCommand() |
785
|
|
|
->delete($this->itemChildTable, ['parent' => $parent->name]) |
786
|
|
|
->execute() > 0; |
787
|
|
|
|
788
|
|
|
$this->invalidateCache(); |
789
|
|
|
|
790
|
|
|
return $result; |
791
|
|
|
} |
792
|
|
|
|
793
|
|
|
/** |
794
|
|
|
* {@inheritdoc} |
795
|
|
|
*/ |
796
|
|
|
public function hasChild($parent, $child) |
797
|
|
|
{ |
798
|
|
|
return (new Query()) |
799
|
|
|
->from($this->itemChildTable) |
800
|
|
|
->where(['parent' => $parent->name, 'child' => $child->name]) |
801
|
|
|
->one($this->db) !== false; |
802
|
|
|
} |
803
|
|
|
|
804
|
|
|
/** |
805
|
|
|
* {@inheritdoc} |
806
|
|
|
*/ |
807
|
105 |
|
public function getChildren($name) |
808
|
|
|
{ |
809
|
105 |
|
$query = (new Query()) |
810
|
105 |
|
->select(['name', 'type', 'description', 'rule_name', 'data', 'created_at', 'updated_at']) |
811
|
105 |
|
->from([$this->itemTable, $this->itemChildTable]) |
812
|
105 |
|
->where(['parent' => $name, 'name' => new Expression('[[child]]')]); |
813
|
|
|
|
814
|
105 |
|
$children = []; |
815
|
105 |
|
foreach ($query->all($this->db) as $row) { |
816
|
105 |
|
$children[$row['name']] = $this->populateItem($row); |
817
|
|
|
} |
818
|
|
|
|
819
|
105 |
|
return $children; |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
/** |
823
|
|
|
* Checks whether there is a loop in the authorization item hierarchy. |
824
|
|
|
* @param Item $parent the parent item |
825
|
|
|
* @param Item $child the child item to be added to the hierarchy |
826
|
|
|
* @return bool whether a loop exists |
827
|
|
|
*/ |
828
|
105 |
|
protected function detectLoop($parent, $child) |
829
|
|
|
{ |
830
|
105 |
|
if ($child->name === $parent->name) { |
831
|
5 |
|
return true; |
832
|
|
|
} |
833
|
105 |
|
foreach ($this->getChildren($child->name) as $grandchild) { |
834
|
100 |
|
if ($this->detectLoop($parent, $grandchild)) { |
835
|
100 |
|
return true; |
836
|
|
|
} |
837
|
|
|
} |
838
|
|
|
|
839
|
105 |
|
return false; |
840
|
|
|
} |
841
|
|
|
|
842
|
|
|
/** |
843
|
|
|
* {@inheritdoc} |
844
|
|
|
*/ |
845
|
210 |
|
public function assign($role, $userId) |
846
|
|
|
{ |
847
|
210 |
|
$assignment = new Assignment([ |
848
|
210 |
|
'userId' => $userId, |
849
|
210 |
|
'roleName' => $role->name, |
850
|
210 |
|
'createdAt' => time(), |
851
|
|
|
]); |
852
|
|
|
|
853
|
210 |
|
$this->db->createCommand() |
854
|
210 |
|
->insert($this->assignmentTable, [ |
855
|
210 |
|
'user_id' => $assignment->userId, |
856
|
210 |
|
'item_name' => $assignment->roleName, |
857
|
210 |
|
'created_at' => $assignment->createdAt, |
858
|
210 |
|
])->execute(); |
859
|
|
|
|
860
|
210 |
|
unset($this->_checkAccessAssignments[(string) $userId]); |
861
|
210 |
|
return $assignment; |
862
|
|
|
} |
863
|
|
|
|
864
|
|
|
/** |
865
|
|
|
* {@inheritdoc} |
866
|
|
|
*/ |
867
|
30 |
|
public function revoke($role, $userId) |
868
|
|
|
{ |
869
|
30 |
|
if ($this->isEmptyUserId($userId)) { |
870
|
5 |
|
return false; |
871
|
|
|
} |
872
|
|
|
|
873
|
25 |
|
unset($this->_checkAccessAssignments[(string) $userId]); |
874
|
25 |
|
return $this->db->createCommand() |
875
|
25 |
|
->delete($this->assignmentTable, ['user_id' => (string) $userId, 'item_name' => $role->name]) |
876
|
25 |
|
->execute() > 0; |
877
|
|
|
} |
878
|
|
|
|
879
|
|
|
/** |
880
|
|
|
* {@inheritdoc} |
881
|
|
|
*/ |
882
|
20 |
|
public function revokeAll($userId) |
883
|
|
|
{ |
884
|
20 |
|
if ($this->isEmptyUserId($userId)) { |
885
|
5 |
|
return false; |
886
|
|
|
} |
887
|
|
|
|
888
|
15 |
|
unset($this->_checkAccessAssignments[(string) $userId]); |
889
|
15 |
|
return $this->db->createCommand() |
890
|
15 |
|
->delete($this->assignmentTable, ['user_id' => (string) $userId]) |
891
|
15 |
|
->execute() > 0; |
892
|
|
|
} |
893
|
|
|
|
894
|
|
|
/** |
895
|
|
|
* {@inheritdoc} |
896
|
|
|
*/ |
897
|
245 |
|
public function removeAll() |
898
|
|
|
{ |
899
|
245 |
|
$this->removeAllAssignments(); |
900
|
245 |
|
$this->db->createCommand()->delete($this->itemChildTable)->execute(); |
901
|
245 |
|
$this->db->createCommand()->delete($this->itemTable)->execute(); |
902
|
245 |
|
$this->db->createCommand()->delete($this->ruleTable)->execute(); |
903
|
245 |
|
$this->invalidateCache(); |
904
|
245 |
|
} |
905
|
|
|
|
906
|
|
|
/** |
907
|
|
|
* {@inheritdoc} |
908
|
|
|
*/ |
909
|
5 |
|
public function removeAllPermissions() |
910
|
|
|
{ |
911
|
5 |
|
$this->removeAllItems(Item::TYPE_PERMISSION); |
912
|
5 |
|
} |
913
|
|
|
|
914
|
|
|
/** |
915
|
|
|
* {@inheritdoc} |
916
|
|
|
*/ |
917
|
5 |
|
public function removeAllRoles() |
918
|
|
|
{ |
919
|
5 |
|
$this->removeAllItems(Item::TYPE_ROLE); |
920
|
5 |
|
} |
921
|
|
|
|
922
|
|
|
/** |
923
|
|
|
* Removes all auth items of the specified type. |
924
|
|
|
* @param int $type the auth item type (either Item::TYPE_PERMISSION or Item::TYPE_ROLE) |
925
|
|
|
*/ |
926
|
10 |
|
protected function removeAllItems($type) |
927
|
|
|
{ |
928
|
10 |
|
if (!$this->supportsCascadeUpdate()) { |
929
|
2 |
|
$names = (new Query()) |
930
|
2 |
|
->select(['name']) |
931
|
2 |
|
->from($this->itemTable) |
932
|
2 |
|
->where(['type' => $type]) |
933
|
2 |
|
->column($this->db); |
934
|
2 |
|
if (empty($names)) { |
935
|
|
|
return; |
936
|
|
|
} |
937
|
2 |
|
$key = $type == Item::TYPE_PERMISSION ? 'child' : 'parent'; |
938
|
2 |
|
$this->db->createCommand() |
939
|
2 |
|
->delete($this->itemChildTable, [$key => $names]) |
940
|
2 |
|
->execute(); |
941
|
2 |
|
$this->db->createCommand() |
942
|
2 |
|
->delete($this->assignmentTable, ['item_name' => $names]) |
943
|
2 |
|
->execute(); |
944
|
|
|
} |
945
|
10 |
|
$this->db->createCommand() |
946
|
10 |
|
->delete($this->itemTable, ['type' => $type]) |
947
|
10 |
|
->execute(); |
948
|
|
|
|
949
|
10 |
|
$this->invalidateCache(); |
950
|
10 |
|
} |
951
|
|
|
|
952
|
|
|
/** |
953
|
|
|
* {@inheritdoc} |
954
|
|
|
*/ |
955
|
5 |
|
public function removeAllRules() |
956
|
|
|
{ |
957
|
5 |
|
if (!$this->supportsCascadeUpdate()) { |
958
|
1 |
|
$this->db->createCommand() |
959
|
1 |
|
->update($this->itemTable, ['rule_name' => null]) |
960
|
1 |
|
->execute(); |
961
|
|
|
} |
962
|
|
|
|
963
|
5 |
|
$this->db->createCommand()->delete($this->ruleTable)->execute(); |
964
|
|
|
|
965
|
5 |
|
$this->invalidateCache(); |
966
|
5 |
|
} |
967
|
|
|
|
968
|
|
|
/** |
969
|
|
|
* {@inheritdoc} |
970
|
|
|
*/ |
971
|
245 |
|
public function removeAllAssignments() |
972
|
|
|
{ |
973
|
245 |
|
$this->_checkAccessAssignments = []; |
974
|
245 |
|
$this->db->createCommand()->delete($this->assignmentTable)->execute(); |
975
|
245 |
|
} |
976
|
|
|
|
977
|
245 |
|
public function invalidateCache() |
978
|
|
|
{ |
979
|
245 |
|
if ($this->cache !== null) { |
980
|
101 |
|
$this->cache->delete($this->cacheKey); |
981
|
101 |
|
$this->items = null; |
982
|
101 |
|
$this->rules = null; |
983
|
101 |
|
$this->parents = null; |
984
|
|
|
} |
985
|
245 |
|
$this->_checkAccessAssignments = []; |
986
|
245 |
|
} |
987
|
|
|
|
988
|
30 |
|
public function loadFromCache() |
989
|
|
|
{ |
990
|
30 |
|
if ($this->items !== null || !$this->cache instanceof CacheInterface) { |
991
|
30 |
|
return; |
992
|
|
|
} |
993
|
|
|
|
994
|
15 |
|
$data = $this->cache->get($this->cacheKey); |
995
|
15 |
|
if (is_array($data) && isset($data[0], $data[1], $data[2])) { |
996
|
|
|
list($this->items, $this->rules, $this->parents) = $data; |
997
|
|
|
return; |
998
|
|
|
} |
999
|
|
|
|
1000
|
15 |
|
$query = (new Query())->from($this->itemTable); |
1001
|
15 |
|
$this->items = []; |
1002
|
15 |
|
foreach ($query->all($this->db) as $row) { |
1003
|
15 |
|
$this->items[$row['name']] = $this->populateItem($row); |
1004
|
|
|
} |
1005
|
|
|
|
1006
|
15 |
|
$query = (new Query())->from($this->ruleTable); |
1007
|
15 |
|
$this->rules = []; |
1008
|
15 |
|
foreach ($query->all($this->db) as $row) { |
1009
|
15 |
|
$data = $row['data']; |
1010
|
15 |
|
if (is_resource($data)) { |
1011
|
7 |
|
$data = stream_get_contents($data); |
1012
|
|
|
} |
1013
|
15 |
|
$this->rules[$row['name']] = unserialize($data); |
1014
|
|
|
} |
1015
|
|
|
|
1016
|
15 |
|
$query = (new Query())->from($this->itemChildTable); |
1017
|
15 |
|
$this->parents = []; |
1018
|
15 |
|
foreach ($query->all($this->db) as $row) { |
1019
|
7 |
|
if (isset($this->items[$row['child']])) { |
1020
|
7 |
|
$this->parents[$row['child']][] = $row['parent']; |
1021
|
|
|
} |
1022
|
|
|
} |
1023
|
|
|
|
1024
|
15 |
|
$this->cache->set($this->cacheKey, [$this->items, $this->rules, $this->parents]); |
1025
|
15 |
|
} |
1026
|
|
|
|
1027
|
|
|
/** |
1028
|
|
|
* Returns all role assignment information for the specified role. |
1029
|
|
|
* @param string $roleName |
1030
|
|
|
* @return string[] the ids. An empty array will be |
1031
|
|
|
* returned if role is not assigned to any user. |
1032
|
|
|
* @since 2.0.7 |
1033
|
|
|
*/ |
1034
|
5 |
|
public function getUserIdsByRole($roleName) |
1035
|
|
|
{ |
1036
|
5 |
|
if (empty($roleName)) { |
1037
|
|
|
return []; |
1038
|
|
|
} |
1039
|
|
|
|
1040
|
5 |
|
return (new Query())->select('[[user_id]]') |
1041
|
5 |
|
->from($this->assignmentTable) |
1042
|
5 |
|
->where(['item_name' => $roleName])->column($this->db); |
1043
|
|
|
} |
1044
|
|
|
|
1045
|
|
|
/** |
1046
|
|
|
* Check whether $userId is empty. |
1047
|
|
|
* @param mixed $userId |
1048
|
|
|
* @return bool |
1049
|
|
|
*/ |
1050
|
140 |
|
private function isEmptyUserId($userId) |
1051
|
|
|
{ |
1052
|
140 |
|
return !isset($userId) || $userId === ''; |
1053
|
|
|
} |
1054
|
|
|
} |
1055
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.