1 | <?php |
||
2 | /** |
||
3 | * @link https://www.yiiframework.com/ |
||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
5 | * @license https://www.yiiframework.com/license/ |
||
6 | */ |
||
7 | |||
8 | namespace yii\rbac; |
||
9 | |||
10 | use yii\base\Component; |
||
11 | use yii\base\InvalidArgumentException; |
||
12 | use yii\base\InvalidConfigException; |
||
13 | use yii\base\InvalidValueException; |
||
14 | |||
15 | /** |
||
16 | * BaseManager is a base class implementing [[ManagerInterface]] for RBAC management. |
||
17 | * |
||
18 | * For more details and usage information on DbManager, see the [guide article on security authorization](guide:security-authorization). |
||
19 | * |
||
20 | * @property-read Role[] $defaultRoleInstances Default roles. The array is indexed by the role names. |
||
21 | * @property string[] $defaultRoles Default roles. Note that the type of this property differs in getter and |
||
22 | * setter. See [[getDefaultRoles()]] and [[setDefaultRoles()]] for details. |
||
23 | * |
||
24 | * @author Qiang Xue <[email protected]> |
||
25 | * @since 2.0 |
||
26 | */ |
||
27 | abstract class BaseManager extends Component implements ManagerInterface |
||
28 | { |
||
29 | /** |
||
30 | * @var array a list of role names that are assigned to every user automatically without calling [[assign()]]. |
||
31 | * Note that these roles are applied to users, regardless of their state of authentication. |
||
32 | */ |
||
33 | protected $defaultRoles = []; |
||
34 | |||
35 | |||
36 | /** |
||
37 | * Returns the named auth item. |
||
38 | * @param string $name the auth item name. |
||
39 | * @return Item|null the auth item corresponding to the specified name. Null is returned if no such item. |
||
40 | */ |
||
41 | abstract protected function getItem($name); |
||
42 | |||
43 | /** |
||
44 | * Returns the items of the specified type. |
||
45 | * @param int $type the auth item type (either [[Item::TYPE_ROLE]] or [[Item::TYPE_PERMISSION]] |
||
46 | * @return Item[] the auth items of the specified type. |
||
47 | */ |
||
48 | abstract protected function getItems($type); |
||
49 | |||
50 | /** |
||
51 | * Adds an auth item to the RBAC system. |
||
52 | * @param Item $item the item to add |
||
53 | * @return bool whether the auth item is successfully added to the system |
||
54 | * @throws \Exception if data validation or saving fails (such as the name of the role or permission is not unique) |
||
55 | */ |
||
56 | abstract protected function addItem($item); |
||
57 | |||
58 | /** |
||
59 | * Adds a rule to the RBAC system. |
||
60 | * @param Rule $rule the rule to add |
||
61 | * @return bool whether the rule is successfully added to the system |
||
62 | * @throws \Exception if data validation or saving fails (such as the name of the rule is not unique) |
||
63 | */ |
||
64 | abstract protected function addRule($rule); |
||
65 | |||
66 | /** |
||
67 | * Removes an auth item from the RBAC system. |
||
68 | * @param Item $item the item to remove |
||
69 | * @return bool whether the role or permission is successfully removed |
||
70 | * @throws \Exception if data validation or saving fails (such as the name of the role or permission is not unique) |
||
71 | */ |
||
72 | abstract protected function removeItem($item); |
||
73 | |||
74 | /** |
||
75 | * Removes a rule from the RBAC system. |
||
76 | * @param Rule $rule the rule to remove |
||
77 | * @return bool whether the rule is successfully removed |
||
78 | * @throws \Exception if data validation or saving fails (such as the name of the rule is not unique) |
||
79 | */ |
||
80 | abstract protected function removeRule($rule); |
||
81 | |||
82 | /** |
||
83 | * Updates an auth item in the RBAC system. |
||
84 | * @param string $name the name of the item being updated |
||
85 | * @param Item $item the updated item |
||
86 | * @return bool whether the auth item is successfully updated |
||
87 | * @throws \Exception if data validation or saving fails (such as the name of the role or permission is not unique) |
||
88 | */ |
||
89 | abstract protected function updateItem($name, $item); |
||
90 | |||
91 | /** |
||
92 | * Updates a rule to the RBAC system. |
||
93 | * @param string $name the name of the rule being updated |
||
94 | * @param Rule $rule the updated rule |
||
95 | * @return bool whether the rule is successfully updated |
||
96 | * @throws \Exception if data validation or saving fails (such as the name of the rule is not unique) |
||
97 | */ |
||
98 | abstract protected function updateRule($name, $rule); |
||
99 | |||
100 | /** |
||
101 | * {@inheritdoc} |
||
102 | */ |
||
103 | 270 | public function createRole($name) |
|
104 | { |
||
105 | 270 | $role = new Role(); |
|
106 | 270 | $role->name = $name; |
|
107 | 270 | return $role; |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * {@inheritdoc} |
||
112 | */ |
||
113 | 266 | public function createPermission($name) |
|
114 | { |
||
115 | 266 | $permission = new Permission(); |
|
116 | 266 | $permission->name = $name; |
|
117 | 266 | return $permission; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * {@inheritdoc} |
||
122 | */ |
||
123 | 284 | public function add($object) |
|
124 | { |
||
125 | 284 | if ($object instanceof Item) { |
|
126 | 278 | if ($object->ruleName && $this->getRule($object->ruleName) === null) { |
|
127 | 12 | $rule = \Yii::createObject($object->ruleName); |
|
128 | 12 | $rule->name = $object->ruleName; |
|
129 | 12 | $this->addRule($rule); |
|
130 | } |
||
131 | |||
132 | 278 | return $this->addItem($object); |
|
133 | 180 | } elseif ($object instanceof Rule) { |
|
134 | 180 | return $this->addRule($object); |
|
135 | } |
||
136 | |||
137 | throw new InvalidArgumentException('Adding unsupported object type.'); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * {@inheritdoc} |
||
142 | */ |
||
143 | 7 | public function remove($object) |
|
144 | { |
||
145 | 7 | if ($object instanceof Item) { |
|
146 | 7 | return $this->removeItem($object); |
|
147 | 6 | } elseif ($object instanceof Rule) { |
|
148 | 6 | return $this->removeRule($object); |
|
149 | } |
||
150 | |||
151 | throw new InvalidArgumentException('Removing unsupported object type.'); |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * {@inheritdoc} |
||
156 | */ |
||
157 | 22 | public function update($name, $object) |
|
158 | { |
||
159 | 22 | if ($object instanceof Item) { |
|
160 | 22 | if ($object->ruleName && $this->getRule($object->ruleName) === null) { |
|
161 | $rule = \Yii::createObject($object->ruleName); |
||
162 | $rule->name = $object->ruleName; |
||
163 | $this->addRule($rule); |
||
164 | } |
||
165 | |||
166 | 22 | return $this->updateItem($name, $object); |
|
167 | 6 | } elseif ($object instanceof Rule) { |
|
168 | 6 | return $this->updateRule($name, $object); |
|
169 | } |
||
170 | |||
171 | throw new InvalidArgumentException('Updating unsupported object type.'); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * {@inheritdoc} |
||
176 | */ |
||
177 | 62 | public function getRole($name) |
|
178 | { |
||
179 | 62 | $item = $this->getItem($name); |
|
180 | 62 | return $item instanceof Item && $item->type == Item::TYPE_ROLE ? $item : null; |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
181 | } |
||
182 | |||
183 | /** |
||
184 | * {@inheritdoc} |
||
185 | */ |
||
186 | 27 | public function getPermission($name) |
|
187 | { |
||
188 | 27 | $item = $this->getItem($name); |
|
189 | 27 | return $item instanceof Item && $item->type == Item::TYPE_PERMISSION ? $item : null; |
|
0 ignored issues
–
show
The expression
return $item instanceof ...RMISSION ? $item : null also could return the type yii\rbac\Item which includes types incompatible with the return type mandated by yii\rbac\ManagerInterface::getPermission() of null|yii\rbac\Permission . Consider adding a type-check to rule them out.
![]() |
|||
190 | } |
||
191 | |||
192 | /** |
||
193 | * {@inheritdoc} |
||
194 | */ |
||
195 | 24 | public function getRoles() |
|
196 | { |
||
197 | 24 | return $this->getItems(Item::TYPE_ROLE); |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * Set default roles |
||
202 | * @param string[]|\Closure $roles either array of roles or a callable returning it |
||
203 | * @throws InvalidArgumentException when $roles is neither array nor Closure |
||
204 | * @throws InvalidValueException when Closure return is not an array |
||
205 | * @since 2.0.14 |
||
206 | */ |
||
207 | 285 | public function setDefaultRoles($roles) |
|
208 | { |
||
209 | 285 | if (is_array($roles)) { |
|
210 | 285 | $this->defaultRoles = $roles; |
|
211 | 12 | } elseif ($roles instanceof \Closure) { |
|
0 ignored issues
–
show
|
|||
212 | 6 | $roles = call_user_func($roles); |
|
213 | 6 | if (!is_array($roles)) { |
|
214 | 6 | throw new InvalidValueException('Default roles closure must return an array'); |
|
215 | } |
||
216 | $this->defaultRoles = $roles; |
||
217 | } else { |
||
218 | 6 | throw new InvalidArgumentException('Default roles must be either an array or a callable'); |
|
219 | } |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Get default roles |
||
224 | * @return string[] default roles |
||
225 | * @since 2.0.14 |
||
226 | */ |
||
227 | public function getDefaultRoles() |
||
228 | { |
||
229 | return $this->defaultRoles; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Returns defaultRoles as array of Role objects. |
||
234 | * @since 2.0.12 |
||
235 | * @return Role[] default roles. The array is indexed by the role names |
||
236 | */ |
||
237 | 27 | public function getDefaultRoleInstances() |
|
238 | { |
||
239 | 27 | $result = []; |
|
240 | 27 | foreach ($this->defaultRoles as $roleName) { |
|
241 | 27 | $result[$roleName] = $this->createRole($roleName); |
|
242 | } |
||
243 | |||
244 | 27 | return $result; |
|
245 | } |
||
246 | |||
247 | /** |
||
248 | * {@inheritdoc} |
||
249 | */ |
||
250 | 18 | public function getPermissions() |
|
251 | { |
||
252 | 18 | return $this->getItems(Item::TYPE_PERMISSION); |
|
253 | } |
||
254 | |||
255 | /** |
||
256 | * Executes the rule associated with the specified auth item. |
||
257 | * |
||
258 | * If the item does not specify a rule, this method will return true. Otherwise, it will |
||
259 | * return the value of [[Rule::execute()]]. |
||
260 | * |
||
261 | * @param string|int $user the user ID. This should be either an integer or a string representing |
||
262 | * the unique identifier of a user. See [[\yii\web\User::id]]. |
||
263 | * @param Item $item the auth item that needs to execute its rule |
||
264 | * @param array $params parameters passed to [[CheckAccessInterface::checkAccess()]] and will be passed to the rule |
||
265 | * @return bool the return value of [[Rule::execute()]]. If the auth item does not specify a rule, true will be returned. |
||
266 | * @throws InvalidConfigException if the auth item has an invalid rule. |
||
267 | */ |
||
268 | 50 | protected function executeRule($user, $item, $params) |
|
269 | { |
||
270 | 50 | if ($item->ruleName === null) { |
|
271 | 50 | return true; |
|
272 | } |
||
273 | 39 | $rule = $this->getRule($item->ruleName); |
|
274 | 39 | if ($rule instanceof Rule) { |
|
275 | 39 | return $rule->execute($user, $item, $params); |
|
276 | } |
||
277 | |||
278 | throw new InvalidConfigException("Rule not found: {$item->ruleName}"); |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Checks whether array of $assignments is empty and [[defaultRoles]] property is empty as well. |
||
283 | * |
||
284 | * @param Assignment[] $assignments array of user's assignments |
||
285 | * @return bool whether array of $assignments is empty and [[defaultRoles]] property is empty as well |
||
286 | * @since 2.0.11 |
||
287 | */ |
||
288 | 58 | protected function hasNoAssignments(array $assignments) |
|
289 | { |
||
290 | 58 | return empty($assignments) && empty($this->defaultRoles); |
|
291 | } |
||
292 | } |
||
293 |