diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ca9ab5..396a06a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fix: correct viewPath error in LoginWidget (niciz) - Enh: possibility to call all the api endpoints with either id or username or email (liviuk2) - Fix: use configured User model in SecurityController 2FA confirmation (jussiaho) +- Enh: possibility to get user ids from roles recursively (mp1509) ## 1.6.0 January 9, 2023 diff --git a/src/User/Component/AuthDbManagerComponent.php b/src/User/Component/AuthDbManagerComponent.php index 49f7686..11e9d4f 100644 --- a/src/User/Component/AuthDbManagerComponent.php +++ b/src/User/Component/AuthDbManagerComponent.php @@ -12,8 +12,11 @@ namespace Da\User\Component; use Da\User\Contracts\AuthManagerInterface; +use yii\base\InvalidArgumentException; +use yii\db\Expression; use yii\db\Query; use yii\rbac\DbManager; +use yii\rbac\Role; class AuthDbManagerComponent extends DbManager implements AuthManagerInterface { @@ -80,4 +83,74 @@ class AuthDbManagerComponent extends DbManager implements AuthManagerInterface { return parent::getItem($name); } + + + /** + * @inheritdoc + * @param bool $recursive + * @override to add possibility to get the ids of users assigned to roles that are parents of the given one. + * @since 1.6.1 + */ + public function getUserIdsByRole($roleName, $recursive = false) + { + if(!$recursive || empty($roleName)) { + return parent::getUserIdsByRole($roleName); + } + + $roles = $this->getParentRoles($roleName); + $userIds = array_reduce($roles, function ($ids, $role) { + $roleIds = parent::getUserIdsByRole($role->name); + return array_merge($ids, $roleIds); + }, []); + return array_unique($userIds); + } + + + /** + * Returns parent roles of the role specified. Depth isn't limited. + * @param string $roleName name of the role to file parent roles for + * @return Role[] Child roles. The array is indexed by the role names. + * First element is an instance of the parent Role itself. + * @throws \yii\base\InvalidParamException if Role was not found that are getting by $roleName + * @since 1.6.1 + */ + public function getParentRoles($roleName) + { + $role = $this->getRole($roleName); + + if ($role === null) { + throw new InvalidArgumentException("Role \"$roleName\" not found."); + } + + $result = []; + $this->getParentsRecursive($roleName, $result); + + $roles = [$roleName => $role]; + + $roles += $result; + + return $roles; + } + + /** + * Recursively finds all parents and grandparents of the specified item. + * @param string $name the name of the item whose children are to be looked for. + * @param array $result the children and grand children (in array keys) + * @since 1.6.1 + */ + protected function getParentsRecursive($name, &$result = []) + { + $query = (new Query()) + ->select(['name', 'type', 'description', 'rule_name', 'data', 'created_at', 'updated_at']) + ->from([$this->itemTable, $this->itemChildTable]) + ->where(['child' => $name, 'name' => new Expression('[[parent]]')]); + + foreach ($query->all($this->db) as $row) { + if(isset($result[$row['name']])) { + continue; + } + $result[$row['name']] = $this->populateItem($row); + $this->getParentsRecursive($row['name'], $result); + } + } }