I am using rbac for setting permissions to each user and check permission for each action using if Yii::$app->user->can() method.
For example, if (Yii::$app->user->can(‘View-all-Inventory’))
This was working properly until I recently added 2 new permissions in auth-item DB table and allotted them to parent Super-Administrator.
After this, I suddenly started getting following fatal error:
Allowed memory size of 134217728 bytes exhausted (tried to allocate 72 bytes) using rbac
I checked and applied many solutions for this, but this error remains as it. I can see this error on my localhost using xampp and also at live server.
I have increased memory limit to 256M and further increased upto 512M. Still I am getting same error. I disabled Yii2 debugger and set environment to LIVE. Still it didnot help. I was getting error in getChildrenRecursive function with logger. Further debugging, I found that when I comment code inside public function checkAccess and simply return true, everything seems to be working as before with no more errors. Commenting this is temporary solution, but i had to this on LIVE server to avoid errors on LIVE site.
But, I think the issue is with recursive function checkAccessRecursive. It is being recursively called many times which causes memory limit to exhaust. Can you please suggest how to optimize this function , I have only 2 level of hierarchy i.e one parent has many children but any child donot have further children.
I am struck and not sure how to sort this and allow access using permissions.
No , there are only 134 records in tblauth_item_child table. I have different parent names like admin, manager etc and completely different children name like edit-profile, view-inventory etc. So, same item and same child cannot be there.
I debugged a little and found the error occurs when this part of function is executed in protected function checkAccessRecursive { }
Both this recursive functions are causing memory limit when we check permission for each action in controller.
/**
* Performs access check for the specified user.
* This method is internally called by [[checkAccess()]].
* @param string|integer $user the user ID. This should can be either an integer or a string representing
* the unique identifier of a user. See [[\yii\web\User::id]].
* @param string $itemName the name of the operation that need access check
* @param array $params name-value pairs that would be passed to rules associated
* with the tasks and roles assigned to the user. A param with name 'user' is added to this array,
* which holds the value of `$userId`.
* @param Assignment[] $assignments the assignments to the specified user
* @return boolean whether the operations can be performed by the user.
*/
protected function checkAccessRecursive($user, $itemName, $params, $assignments)
{
if (($item = $this->getItem($itemName)) === null) {
return false;
}
Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission: $itemName", __METHOD__);
if (!$this->executeRule($user, $item, $params)) {
return false;
}
if (isset($assignments[$itemName]) || in_array($itemName, $this->defaultRoles)) {
return true;
}
$query = new Query;
$parents = $query->select(['parent'])
->from($this->itemChildTable)
->where(['child' => $itemName])
->column($this->db);
foreach ($parents as $parent) {
if ($this->checkAccessRecursive($user, $parent, $params, $assignments)) {
return true;
}
}
return false;
}
/**
* Recursively finds all children and grand children of the specified item.
* @param string $name the name of the item whose children are to be looked for.
* @param array $childrenList the child list built via [[getChildrenList()]]
* @param array $result the children and grand children (in array keys)
*/
protected function getChildrenRecursive($name, $childrenList, &$result)
{
if (isset($childrenList[$name])) {
foreach ($childrenList[$name] as $child) {
$result[$child] = true;
$this->getChildrenRecursive($child, $childrenList, $result);
}
}
}
May be they are getting into never ending loops which causes memory limit error.