123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710 |
- <?php
- namespace common\modules\rbac\components;
- use Yii;
- use yii\caching\Cache;
- use yii\caching\TagDependency;
- use yii\db\Connection;
- use yii\db\Query;
- use yii\di\Instance;
- use yii\rbac\Assignment;
- use yii\rbac\Item;
- use yii\rbac\Permission;
- use yii\rbac\Role;
- use yii\rbac\Rule;
- /**
- * DbManager represents an authorization manager that stores authorization information in database.
- *
- * The database connection is specified by [[$db]]. The database schema could be initialized by applying migration:
- *
- * ~~~
- * yii migrate --migrationPath=@yii/rbac/migrations/
- * ~~~
- *
- * If you don't want to use migration and need SQL instead, files for all databases are in migrations directory.
- *
- * You may change the names of the three tables used to store the authorization data by setting [[\yii\rbac\DbManager::$itemTable]],
- * [[\yii\rbac\DbManager::$itemChildTable]] and [[\yii\rbac\DbManager::$assignmentTable]].
- *
- * @author Misbahul D Munir <misbahuldmunir@gmail.com>
- *
- * @since 1.0
- */
- class DbManager extends \yii\rbac\DbManager
- {
- const PART_ITEMS = 'mdm.admin.items';
- const PART_CHILDREN = 'mdm.admin.children';
- const PART_RULES = 'mdm.admin.rules';
- /**
- * @var bool Enable caching
- */
- public $enableCaching = false;
- /**
- * @var string|Cache Cache component
- */
- public $cache = 'cache';
- /**
- * @var int Cache duration
- */
- public $cacheDuration = 0;
- /**
- * @var Item[]
- * itemName => item
- */
- private $_items;
- /**
- * @var array
- * itemName => childName[]
- */
- private $_children;
- /**
- * @var array
- * userId => itemName[]
- */
- private $_assignments = [];
- /**
- * @var Rule[]
- * ruleName => rule
- */
- private $_rules;
- /**
- * {@inheritdoc}
- */
- public function init()
- {
- parent::init();
- $this->db = Instance::ensure($this->db, Connection::className());
- if ($this->enableCaching) {
- $this->cache = Instance::ensure($this->cache, Cache::className());
- } else {
- $this->cache = null;
- }
- }
- /**
- * {@inheritdoc}
- */
- public function checkAccess($userId, $permissionName, $params = [])
- {
- $this->loadItems();
- $this->loadChildren();
- $this->loadRules();
- $assignments = $this->getAssignments($userId);
- return $this->checkAccessRecursive($userId, $permissionName, $params, $assignments);
- }
- /**
- * {@inheritdoc}
- */
- public function getAssignments($userId)
- {
- $this->loadAssignments($userId);
- return isset($this->_assignments[$userId]) ? $this->_assignments[$userId] : [];
- }
- /**
- * {@inheritdoc}
- */
- protected function checkAccessRecursive($user, $itemName, $params, $assignments)
- {
- if (!isset($this->_items[$itemName])) {
- return false;
- }
- /** @var Item $item */
- $item = $this->_items[$itemName];
- 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;
- }
- foreach ($this->_children as $parentName => $children) {
- if (in_array($itemName, $children) && $this->checkAccessRecursive($user, $parentName, $params, $assignments)) {
- return true;
- }
- }
- return false;
- }
- /**
- * {@inheritdoc}
- */
- public function addChild($parent, $child)
- {
- $this->loadItems();
- $this->loadChildren();
- parent::addChild($parent, $child);
- $this->_children[$parent->name][] = $child->name;
- $this->invalidate(self::PART_CHILDREN);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- public function removeChild($parent, $child)
- {
- $result = parent::removeChild($parent, $child);
- if ($this->_children !== null) {
- $query = (new Query())
- ->select('child')
- ->from($this->itemChildTable)
- ->where(['parent' => $parent->name]);
- $this->_children[$parent->name] = $query->column($this->db);
- }
- $this->invalidate(self::PART_CHILDREN);
- return $result;
- }
- /**
- * {@inheritdoc}
- */
- public function hasChild($parent, $child)
- {
- $this->loadChildren();
- return isset($this->_children[$parent->name]) && in_array($child->name, $this->_children[$parent->name]);
- }
- /**
- * {@inheritdoc}
- */
- public function assign($role, $userId)
- {
- $assignment = parent::assign($role, $userId);
- if (isset($this->_assignments[$userId])) {
- $this->_assignments[$userId][$role->name] = $assignment;
- }
- return $assignment;
- }
- /**
- * {@inheritdoc}
- */
- public function revoke($role, $userId)
- {
- $result = parent::revoke($role, $userId);
- unset($this->_assignments[$userId]);
- return $result;
- }
- /**
- * {@inheritdoc}
- */
- public function revokeAll($userId)
- {
- if (empty($userId)) {
- return false;
- }
- $result = parent::revokeAll($userId);
- $this->_assignments[$userId] = [];
- return $result;
- }
- /**
- * {@inheritdoc}
- */
- public function getAssignment($roleName, $userId)
- {
- $this->loadItems();
- $this->loadAssignments($userId);
- if (isset($this->_assignments[$userId][$roleName], $this->_items[$roleName])) {
- return $this->_items[$roleName];
- }
- return;
- }
- /**
- * {@inheritdoc}
- */
- protected function getItems($type)
- {
- $this->loadItems();
- $items = [];
- foreach ($this->_items as $name => $item) {
- /** @var Item $item */
- if ($item->type == $type) {
- $items[$name] = $item;
- }
- }
- return $items;
- }
- /**
- * {@inheritdoc}
- */
- public function removeItem($item)
- {
- parent::removeItem($item);
- $this->_assignments = [];
- $this->_children = $this->_items = null;
- $this->invalidate([self::PART_ITEMS, self::PART_CHILDREN]);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- public function getItem($name)
- {
- $this->loadItems();
- return isset($this->_items[$name]) ? $this->_items[$name] : null;
- }
- /**
- * {@inheritdoc}
- */
- public function updateRule($name, $rule)
- {
- parent::updateRule($name, $rule);
- if ($rule->name !== $name) {
- $this->_items = null;
- $this->invalidate(self::PART_ITEMS);
- }
- if ($this->_rules !== null) {
- unset($this->_rules[$name]);
- $this->_rules[$rule->name] = $rule;
- }
- $this->invalidate(self::PART_RULES);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- public function getRule($name)
- {
- $this->loadRules();
- return isset($this->_rules[$name]) ? $this->_rules[$name] : null;
- }
- /**
- * {@inheritdoc}
- */
- public function getRules()
- {
- $this->loadRules();
- return $this->_rules;
- }
- /**
- * {@inheritdoc}
- */
- public function getRolesByUser($userId)
- {
- $this->loadItems();
- $roles = [];
- foreach ($this->getAssignments($userId) as $name => $asgn) {
- if (isset($this->_items[$name]) && $this->_items[$name]->type == Item::TYPE_ROLE) {
- $roles[$name] = $this->_items[$name];
- }
- }
- return $roles;
- }
- /**
- * {@inheritdoc}
- */
- public function getPermissionsByRole($roleName)
- {
- $childrenList = $this->getChildrenList();
- $result = [];
- $this->getChildrenRecursive($roleName, $childrenList, $result);
- if (empty($result)) {
- return [];
- }
- $this->loadItems();
- $permissions = [];
- foreach (array_keys($result) as $itemName) {
- if (isset($this->_items[$itemName]) && $this->_items[$itemName] instanceof Permission) {
- $permissions[$itemName] = $this->_items[$itemName];
- }
- }
- return $permissions;
- }
- /**
- * {@inheritdoc}
- */
- protected function getChildrenList()
- {
- $this->loadChildren();
- return $this->_children;
- }
- /**
- * {@inheritdoc}
- */
- public function getPermissionsByUser($userId)
- {
- $childrenList = $this->getChildrenList();
- $result = [];
- foreach ($this->getAssignments($userId) as $roleName => $asgn) {
- $this->getChildrenRecursive($roleName, $childrenList, $result);
- }
- if (empty($result)) {
- return [];
- }
- $this->loadItems();
- $permissions = [];
- foreach (array_keys($result) as $itemName) {
- if (isset($this->_items[$itemName]) && $this->_items[$itemName] instanceof Permission) {
- $permissions[$itemName] = $this->_items[$itemName];
- }
- }
- return $permissions;
- }
- /**
- * {@inheritdoc}
- */
- public function getChildren($name)
- {
- $this->loadItems();
- $this->loadChildren();
- $items = [];
- if (isset($this->_children[$name])) {
- foreach ($this->_children[$name] as $itemName) {
- $items[$itemName] = $this->_items[$itemName];
- }
- }
- return $items;
- }
- /**
- * {@inheritdoc}
- */
- public function removeAll()
- {
- $this->_children = [];
- $this->_items = [];
- $this->_assignments = [];
- $this->_rules = [];
- $this->removeAllAssignments();
- $this->db->createCommand()->delete($this->itemChildTable)->execute();
- $this->db->createCommand()->delete($this->itemTable)->execute();
- $this->db->createCommand()->delete($this->ruleTable)->execute();
- $this->invalidate([self::PART_ITEMS, self::PART_CHILDREN, self::PART_RULES]);
- }
- /**
- * {@inheritdoc}
- */
- protected function removeAllItems($type)
- {
- parent::removeAllItems($type);
- $this->_assignments = [];
- $this->_children = $this->_items = null;
- $this->invalidate([self::PART_ITEMS, self::PART_CHILDREN]);
- }
- /**
- * {@inheritdoc}
- */
- public function removeAllRules()
- {
- parent::removeAllRules();
- $this->_rules = [];
- $this->_items = null;
- $this->invalidate([self::PART_ITEMS, self::PART_RULES]);
- }
- /**
- * {@inheritdoc}
- */
- public function removeAllAssignments()
- {
- parent::removeAllAssignments();
- $this->_assignments = [];
- }
- /**
- * {@inheritdoc}
- */
- protected function removeRule($rule)
- {
- parent::removeRule($rule);
- if ($this->_rules !== null) {
- unset($this->_rules[$rule->name]);
- }
- $this->_items = null;
- $this->invalidate([self::PART_ITEMS, self::PART_RULES]);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- protected function addRule($rule)
- {
- parent::addRule($rule);
- if ($this->_rules !== null) {
- $this->_rules[$rule->name] = $rule;
- }
- $this->invalidate(self::PART_RULES);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- protected function updateItem($name, $item)
- {
- parent::updateItem($name, $item);
- if ($item->name !== $name) {
- $this->_assignments = [];
- $this->_children = null;
- $this->invalidate(self::PART_CHILDREN);
- }
- $this->_items = null;
- $this->invalidate(self::PART_RULES);
- return true;
- }
- /**
- * {@inheritdoc}
- */
- protected function addItem($item)
- {
- parent::addItem($item);
- if ($this->_items !== null) {
- $this->_items[$item->name] = $item;
- }
- $this->invalidate(self::PART_ITEMS);
- return true;
- }
- /**
- * Invalidate cache.
- *
- * @param string $parts
- */
- private function invalidate($parts)
- {
- if ($this->enableCaching) {
- TagDependency::invalidate($this->cache, $parts);
- }
- }
- /**
- * Build key cache.
- *
- * @param string $part
- *
- * @return mixed
- */
- private function buildKey($part)
- {
- return [__CLASS__, $part];
- }
- /**
- * Get data from cache.
- *
- * @param string $part
- *
- * @return mixed
- */
- private function getFromCache($part)
- {
- if ($this->enableCaching) {
- return $this->cache->get($this->buildKey($part));
- }
- return false;
- }
- /**
- * Save data to cache.
- *
- * @param string $part
- * @param mixed $data
- */
- private function saveToCache($part, $data)
- {
- if ($this->enableCaching) {
- $this->cache->set($this->buildKey($part), $data, $this->cacheDuration, new TagDependency([
- 'tags' => $part,
- ]));
- }
- }
- /**
- * Load data. If avaliable in memory, get from memory
- * If no, get from cache. If no avaliable, get from database.
- */
- private function loadItems()
- {
- $part = self::PART_ITEMS;
- if ($this->_items === null && ($this->_items = $this->getFromCache($part)) === false) {
- $query = (new Query())->from($this->itemTable);
- $this->_items = [];
- foreach ($query->all($this->db) as $row) {
- $this->_items[$row['name']] = $this->populateItem($row);
- }
- $this->saveToCache($part, $this->_items);
- }
- }
- /**
- * Load data. If avaliable in memory, get from memory
- * If no, get from cache. If no avaliable, get from database.
- */
- private function loadChildren()
- {
- $this->loadItems();
- $part = self::PART_CHILDREN;
- if ($this->_children === null && ($this->_children = $this->getFromCache($part)) === false) {
- $query = (new Query())->from($this->itemChildTable);
- $this->_children = [];
- foreach ($query->all($this->db) as $row) {
- if (isset($this->_items[$row['parent']], $this->_items[$row['child']])) {
- $this->_children[$row['parent']][] = $row['child'];
- }
- }
- $this->saveToCache($part, $this->_children);
- }
- }
- /**
- * Load data. If avaliable in memory, get from memory
- * If no, get from cache. If no avaliable, get from database.
- */
- private function loadRules()
- {
- $part = self::PART_RULES;
- if ($this->_rules === null && ($this->_rules = $this->getFromCache($part)) === false) {
- $query = (new Query())->from($this->ruleTable);
- $this->_rules = [];
- foreach ($query->all($this->db) as $row) {
- $rule = @unserialize($row['data']);
- if ($rule instanceof Rule) {
- $this->_rules[$row['name']] = $rule;
- }
- }
- $this->saveToCache($part, $this->_rules);
- }
- }
- /**
- * Load data. If avaliable in memory, get from memory
- * If no, get from cache. If no avaliable, get from database.
- */
- private function loadAssignments($userId)
- {
- if (!isset($this->_assignments[$userId]) && !empty($userId)) {
- $query = (new Query())
- ->from($this->assignmentTable)
- ->where(['user_id' => (string) $userId]);
- $this->_assignments[$userId] = [];
- foreach ($query->all($this->db) as $row) {
- $this->_assignments[$userId][$row['item_name']] = new Assignment([
- 'userId' => $row['user_id'],
- 'roleName' => $row['item_name'],
- 'createdAt' => $row['created_at'],
- ]);
- }
- }
- }
- /**
- * {@inheritdoc}
- */
- public function removeChildren($parent)
- {
- $result = parent::removeChildren($parent);
- if ($this->_children !== null) {
- unset($this->_children[$parent->name]);
- }
- $this->invalidate(self::PART_CHILDREN);
- return $result;
- }
- /**
- * Returns both roles and permissions assigned to user.
- *
- * @param integer $userId
- * @return array
- */
- public function getItemsByUser($userId)
- {
- if (empty($userId)) {
- return [];
- }
- $query = (new Query)->select('b.*')
- ->from(['a' => $this->assignmentTable, 'b' => $this->itemTable])
- ->where('{{a}}.[[item_name]]={{b}}.[[name]]')
- ->andWhere(['a.user_id' => (string) $userId]);
- $roles = [];
- foreach ($query->all($this->db) as $row) {
- $roles[$row['name']] = $this->populateItem($row);
- }
- return $roles;
- }
- }
|