From 3eee7b8e4b62ad7c33b1482afe721ce4c1decea4 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 29 Jun 2014 02:59:19 +0400 Subject: [PATCH 1/2] Fixes #4072: `\yii\rbac\PhpManager` adjustments - Data is now stored in three separate files for items, assignments and rules. File format is simpler. - Removed `authFile`. Added `itemsFile`, `assignmentsFile` and `rulesFile`. - `createdAt` and `updatedAt` are now properly filled with corresponding file modification time. - `save()` and `load()` are now protected instead of public. - Added unit test for saving and loading data. --- framework/CHANGELOG.md | 6 + framework/UPGRADE.md | 48 +++ framework/rbac/Assignment.php | 2 - framework/rbac/PhpManager.php | 363 ++++++++++-------- .../unit/framework/rbac/ExposedPhpManager.php | 37 ++ tests/unit/framework/rbac/ManagerTestCase.php | 173 +-------- tests/unit/framework/rbac/PhpManagerTest.php | 62 ++- 7 files changed, 346 insertions(+), 345 deletions(-) create mode 100644 tests/unit/framework/rbac/ExposedPhpManager.php diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index cb3db25b6a..6b80ebce6a 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -120,6 +120,12 @@ Yii Framework 2 Change Log - Improved overall slug results. - Added note about the fact that intl is required for non-latin languages to requirements checker. - Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq) +- Enh #4072: `\yii\rbac\PhpManager` adjustments (samdark) + - Data is now stored in three separate files for items, assignments and rules. File format is simpler. + - Removed `authFile`. Added `itemsFile`, `assignmentsFile` and `rulesFile`. + - `createdAt` and `updatedAt` are now properly filled with corresponding file modification time. + - `save()` and `load()` are now protected instead of public. + - Added unit test for saving and loading data. - Enh #4080: Added proper handling and support of the symlinked directories in `FileHelper`, added $options parameter in `FileHelper::removeDirectory()` (resurtm) - Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue) - Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue) diff --git a/framework/UPGRADE.md b/framework/UPGRADE.md index 83fc0fc41c..494a263bf5 100644 --- a/framework/UPGRADE.md +++ b/framework/UPGRADE.md @@ -72,3 +72,51 @@ Upgrade from Yii 2.0 Beta * `mail` component was renamed to `mailer`, `yii\log\EmailTarget::$mail` was renamed to `yii\log\EmailTarget::$mailer`. Please update all references in the code and config files. + +* `\yii\rbac\PhpManager` now stores data in three separate files instead of one. In order to convert old file to +new ones save the following code as `convert.php` that should be placed in the same directory your `rbac.php` is in: + +```php + $data) { + if (isset($data['assignments'])) { + foreach ($data['assignments'] as $userId => $assignmentData) { + $assignments[$userId] = $assignmentData['roleName']; + } + unset($data['assignments']); + } + $items[$name] = $data; + } +} + +$rules = []; +if (isset($oldData['rules'])) { + $rules = $oldData['rules']; +} + +saveToFile($items, $itemsFile); +saveToFile($assignments, $assignmentsFile); +saveToFile($rules, $rulesFile); + +echo "Done!\n"; +``` + +Run it once, delete `rbac.php`. If you've configured `authFile` property, remove the line from config and instead +configure `itemsFile`, `assignmentsFile` and `rulesFile`. \ No newline at end of file diff --git a/framework/rbac/Assignment.php b/framework/rbac/Assignment.php index 2ae5efc538..5a13547236 100644 --- a/framework/rbac/Assignment.php +++ b/framework/rbac/Assignment.php @@ -13,8 +13,6 @@ use yii\base\Object; /** * Assignment represents an assignment of a role to a user. * - * It includes additional assignment information including [[ruleName]] and [[data]]. - * * @author Qiang Xue * @author Alexander Kochetov * @since 2.0 diff --git a/framework/rbac/PhpManager.php b/framework/rbac/PhpManager.php index 5e9c1dbfa7..d22d3bac80 100644 --- a/framework/rbac/PhpManager.php +++ b/framework/rbac/PhpManager.php @@ -26,34 +26,52 @@ use yii\helpers\VarDumper; * @author Qiang Xue * @author Alexander Kochetov * @author Christophe Boulain + * @author Alexander Makarov * @since 2.0 */ class PhpManager extends BaseManager { /** - * @var string the path of the PHP script that contains the authorization data. + * @var string the path of the PHP script that contains the authorization items. * This can be either a file path or a path alias to the file. * Make sure this file is writable by the Web server process if the authorization needs to be changed online. * @see loadFromFile() * @see saveToFile() */ - public $authFile = '@app/data/rbac.php'; + public $itemsFile = '@app/data/rbac-items.php'; + /** + * @var string the path of the PHP script that contains the authorization assignments. + * This can be either a file path or a path alias to the file. + * Make sure this file is writable by the Web server process if the authorization needs to be changed online. + * @see loadFromFile() + * @see saveToFile() + */ + public $assignmentsFile = '@app/data/rbac-assignments.php'; + + /** + * @var string the path of the PHP script that contains the authorization rules. + * This can be either a file path or a path alias to the file. + * Make sure this file is writable by the Web server process if the authorization needs to be changed online. + * @see loadFromFile() + * @see saveToFile() + */ + public $rulesFile = '@app/data/rbac-rules.php'; /** * @var Item[] */ - private $_items = []; // itemName => item + protected $items = []; // itemName => item /** * @var array */ - private $_children = []; // itemName, childName => child + protected $children = []; // itemName, childName => child /** * @var Assignment[] */ - private $_assignments = []; // userId, itemName => assignment + protected $assignments = []; // userId, itemName => assignment /** * @var Rule[] */ - private $_rules = []; // ruleName => rule + protected $rules = []; // ruleName => rule /** @@ -64,7 +82,9 @@ class PhpManager extends BaseManager public function init() { parent::init(); - $this->authFile = Yii::getAlias($this->authFile); + $this->itemsFile = Yii::getAlias($this->itemsFile); + $this->assignmentsFile = Yii::getAlias($this->assignmentsFile); + $this->rulesFile = Yii::getAlias($this->rulesFile); $this->load(); } @@ -82,7 +102,7 @@ class PhpManager extends BaseManager */ public function getAssignments($userId) { - return isset($this->_assignments[$userId]) ? $this->_assignments[$userId] : []; + return isset($this->assignments[$userId]) ? $this->assignments[$userId] : []; } /** @@ -100,12 +120,12 @@ class PhpManager extends BaseManager */ protected function checkAccessRecursive($user, $itemName, $params, $assignments) { - if (!isset($this->_items[$itemName])) { + if (!isset($this->items[$itemName])) { return false; } /* @var $item Item */ - $item = $this->_items[$itemName]; + $item = $this->items[$itemName]; Yii::trace($item instanceof Role ? "Checking role: $itemName" : "Checking permission : $itemName", __METHOD__); if (!$this->executeRule($user, $item, $params)) { @@ -116,7 +136,7 @@ class PhpManager extends BaseManager return true; } - foreach ($this->_children as $parentName => $children) { + foreach ($this->children as $parentName => $children) { if (isset($children[$itemName]) && $this->checkAccessRecursive($user, $parentName, $params, $assignments)) { return true; } @@ -130,7 +150,7 @@ class PhpManager extends BaseManager */ public function addChild($parent, $child) { - if (!isset($this->_items[$parent->name], $this->_items[$child->name])) { + if (!isset($this->items[$parent->name], $this->items[$child->name])) { throw new InvalidParamException("Either '{$parent->name}' or '{$child->name}' does not exist."); } @@ -144,11 +164,11 @@ class PhpManager extends BaseManager if ($this->detectLoop($parent, $child)) { throw new InvalidCallException("Cannot add '{$child->name}' as a child of '{$parent->name}'. A loop has been detected."); } - if (isset($this->_children[$parent->name][$child->name])) { + if (isset($this->children[$parent->name][$child->name])) { throw new InvalidCallException("The item '{$parent->name}' already has a child '{$child->name}'."); } - $this->_children[$parent->name][$child->name] = $this->_items[$child->name]; - $this->save(); + $this->children[$parent->name][$child->name] = $this->items[$child->name]; + $this->saveItems(); return true; } @@ -165,10 +185,10 @@ class PhpManager extends BaseManager if ($child->name === $parent->name) { return true; } - if (!isset($this->_children[$child->name], $this->_items[$parent->name])) { + if (!isset($this->children[$child->name], $this->items[$parent->name])) { return false; } - foreach ($this->_children[$child->name] as $grandchild) { + foreach ($this->children[$child->name] as $grandchild) { /* @var $grandchild Item */ if ($this->detectLoop($parent, $grandchild)) { return true; @@ -183,9 +203,9 @@ class PhpManager extends BaseManager */ public function removeChild($parent, $child) { - if (isset($this->_children[$parent->name][$child->name])) { - unset($this->_children[$parent->name][$child->name]); - $this->save(); + if (isset($this->children[$parent->name][$child->name])) { + unset($this->children[$parent->name][$child->name]); + $this->saveItems(); return true; } else { return false; @@ -197,7 +217,7 @@ class PhpManager extends BaseManager */ public function hasChild($parent, $child) { - return isset($this->_children[$parent->name][$child->name]); + return isset($this->children[$parent->name][$child->name]); } /** @@ -205,18 +225,18 @@ class PhpManager extends BaseManager */ public function assign($role, $userId, $ruleName = null, $data = null) { - if (!isset($this->_items[$role->name])) { + if (!isset($this->items[$role->name])) { throw new InvalidParamException("Unknown role '{$role->name}'."); - } elseif (isset($this->_assignments[$userId][$role->name])) { + } elseif (isset($this->assignments[$userId][$role->name])) { throw new InvalidParamException("Authorization item '{$role->name}' has already been assigned to user '$userId'."); } else { - $this->_assignments[$userId][$role->name] = new Assignment([ + $this->assignments[$userId][$role->name] = new Assignment([ 'userId' => $userId, 'roleName' => $role->name, 'createdAt' => time(), ]); - $this->save(); - return $this->_assignments[$userId][$role->name]; + $this->saveAssignments(); + return $this->assignments[$userId][$role->name]; } } @@ -225,9 +245,9 @@ class PhpManager extends BaseManager */ public function revoke($role, $userId) { - if (isset($this->_assignments[$userId][$role->name])) { - unset($this->_assignments[$userId][$role->name]); - $this->save(); + if (isset($this->assignments[$userId][$role->name])) { + unset($this->assignments[$userId][$role->name]); + $this->saveAssignments(); return true; } else { return false; @@ -239,11 +259,11 @@ class PhpManager extends BaseManager */ public function revokeAll($userId) { - if (isset($this->_assignments[$userId]) && is_array($this->_assignments[$userId])) { - foreach ($this->_assignments[$userId] as $itemName => $value) { - unset($this->_assignments[$userId][$itemName]); + if (isset($this->assignments[$userId]) && is_array($this->assignments[$userId])) { + foreach ($this->assignments[$userId] as $itemName => $value) { + unset($this->assignments[$userId][$itemName]); } - $this->save(); + $this->saveAssignments(); return true; } else { return false; @@ -255,7 +275,7 @@ class PhpManager extends BaseManager */ public function getAssignment($roleName, $userId) { - return isset($this->_assignments[$userId][$roleName]) ? $this->_assignments[$userId][$roleName] : null; + return isset($this->assignments[$userId][$roleName]) ? $this->assignments[$userId][$roleName] : null; } /** @@ -265,7 +285,7 @@ class PhpManager extends BaseManager { $items = []; - foreach ($this->_items as $name => $item) { + foreach ($this->items as $name => $item) { /* @var $item Item */ if ($item->type == $type) { $items[$name] = $item; @@ -281,15 +301,15 @@ class PhpManager extends BaseManager */ public function removeItem($item) { - if (isset($this->_items[$item->name])) { - foreach ($this->_children as &$children) { + if (isset($this->items[$item->name])) { + foreach ($this->children as &$children) { unset($children[$item->name]); } - foreach ($this->_assignments as &$assignments) { + foreach ($this->assignments as &$assignments) { unset($assignments[$item->name]); } - unset($this->_items[$item->name]); - $this->save(); + unset($this->items[$item->name]); + $this->saveItems(); return true; } else { return false; @@ -301,7 +321,7 @@ class PhpManager extends BaseManager */ public function getItem($name) { - return isset($this->_items[$name]) ? $this->_items[$name] : null; + return isset($this->items[$name]) ? $this->items[$name] : null; } /** @@ -310,10 +330,10 @@ class PhpManager extends BaseManager public function updateRule($name, $rule) { if ($rule->name !== $name) { - unset($this->_rules[$name]); + unset($this->rules[$name]); } - $this->_rules[$rule->name] = $rule; - $this->save(); + $this->rules[$rule->name] = $rule; + $this->saveRules(); return true; } @@ -322,7 +342,7 @@ class PhpManager extends BaseManager */ public function getRule($name) { - return isset($this->_rules[$name]) ? $this->_rules[$name] : null; + return isset($this->rules[$name]) ? $this->rules[$name] : null; } /** @@ -330,7 +350,7 @@ class PhpManager extends BaseManager */ public function getRules() { - return $this->_rules; + return $this->rules; } /** @@ -340,7 +360,7 @@ class PhpManager extends BaseManager { $roles = []; foreach ($this->getAssignments($userId) as $name => $assignment) { - $roles[$name] = $this->_items[$assignment->roleName]; + $roles[$name] = $this->items[$assignment->roleName]; } return $roles; @@ -358,8 +378,8 @@ class PhpManager extends BaseManager } $permissions = []; foreach (array_keys($result) as $itemName) { - if (isset($this->_items[$itemName]) && $this->_items[$itemName] instanceof Permission) { - $permissions[$itemName] = $this->_items[$itemName]; + if (isset($this->items[$itemName]) && $this->items[$itemName] instanceof Permission) { + $permissions[$itemName] = $this->items[$itemName]; } } return $permissions; @@ -373,8 +393,8 @@ class PhpManager extends BaseManager */ protected function getChildrenRecursive($name, &$result) { - if (isset($this->_children[$name])) { - foreach ($this->_children[$name] as $child) { + if (isset($this->children[$name])) { + foreach ($this->children[$name] as $child) { $result[$child->name] = true; $this->getChildrenRecursive($child->name, $result); } @@ -398,8 +418,8 @@ class PhpManager extends BaseManager $permissions = []; foreach (array_keys($result) as $itemName) { - if (isset($this->_items[$itemName]) && $this->_items[$itemName] instanceof Permission) { - $permissions[$itemName] = $this->_items[$itemName]; + if (isset($this->items[$itemName]) && $this->items[$itemName] instanceof Permission) { + $permissions[$itemName] = $this->items[$itemName]; } } return $permissions; @@ -410,7 +430,7 @@ class PhpManager extends BaseManager */ public function getChildren($name) { - return isset($this->_children[$name]) ? $this->_children[$name] : []; + return isset($this->children[$name]) ? $this->children[$name] : []; } /** @@ -418,10 +438,10 @@ class PhpManager extends BaseManager */ public function removeAll() { - $this->_children = []; - $this->_items = []; - $this->_assignments = []; - $this->_rules = []; + $this->children = []; + $this->items = []; + $this->assignments = []; + $this->rules = []; $this->save(); } @@ -448,9 +468,9 @@ class PhpManager extends BaseManager protected function removeAllItems($type) { $names = []; - foreach ($this->_items as $name => $item) { + foreach ($this->items as $name => $item) { if ($item->type == $type) { - unset($this->_items[$name]); + unset($this->items[$name]); $names[$name] = true; } } @@ -458,25 +478,25 @@ class PhpManager extends BaseManager return; } - foreach ($this->_assignments as $i => $assignment) { + foreach ($this->assignments as $i => $assignment) { if (isset($names[$assignment->roleName])) { - unset($this->_assignments[$i]); + unset($this->assignments[$i]); } } - foreach ($this->_children as $name => $children) { + foreach ($this->children as $name => $children) { if (isset($names[$name])) { - unset($this->_children[$name]); + unset($this->children[$name]); } else { foreach ($children as $childName => $item) { if (isset($names[$childName])) { unset($children[$childName]); } } - $this->_children[$name] = $children; + $this->children[$name] = $children; } } - $this->save(); + $this->saveItems(); } /** @@ -484,11 +504,11 @@ class PhpManager extends BaseManager */ public function removeAllRules() { - foreach ($this->_items as $item) { + foreach ($this->items as $item) { $item->ruleName = null; } - $this->_rules = []; - $this->save(); + $this->rules = []; + $this->saveRules(); } /** @@ -496,8 +516,8 @@ class PhpManager extends BaseManager */ public function removeAllAssignments() { - $this->_assignments = []; - $this->save(); + $this->assignments = []; + $this->saveAssignments(); } /** @@ -505,14 +525,14 @@ class PhpManager extends BaseManager */ protected function removeRule($rule) { - if (isset($this->_rules[$rule->name])) { - unset($this->_rules[$rule->name]); - foreach ($this->_items as $item) { + if (isset($this->rules[$rule->name])) { + unset($this->rules[$rule->name]); + foreach ($this->items as $item) { if ($item->ruleName === $rule->name) { $item->ruleName = null; } } - $this->save(); + $this->saveRules(); return true; } else { return false; @@ -524,8 +544,8 @@ class PhpManager extends BaseManager */ protected function addRule($rule) { - $this->_rules[$rule->name] = $rule; - $this->save(); + $this->rules[$rule->name] = $rule; + $this->saveRules(); return true; } @@ -534,25 +554,25 @@ class PhpManager extends BaseManager */ protected function updateItem($name, $item) { - $this->_items[$item->name] = $item; + $this->items[$item->name] = $item; if ($name !== $item->name) { - if (isset($this->_items[$item->name])) { + if (isset($this->items[$item->name])) { throw new InvalidParamException("Unable to change the item name. The name '{$item->name}' is already used by another item."); } - if (isset($this->_items[$name])) { - unset ($this->_items[$name]); + if (isset($this->items[$name])) { + unset ($this->items[$name]); - if (isset($this->_children[$name])) { - $this->_children[$item->name] = $this->_children[$name]; - unset ($this->_children[$name]); + if (isset($this->children[$name])) { + $this->children[$item->name] = $this->children[$name]; + unset ($this->children[$name]); } - foreach ($this->_children as &$children) { + foreach ($this->children as &$children) { if (isset($children[$name])) { $children[$item->name] = $children[$name]; unset ($children[$name]); } } - foreach ($this->_assignments as &$assignments) { + foreach ($this->assignments as &$assignments) { if (isset($assignments[$name])) { $assignments[$item->name] = $assignments[$name]; unset($assignments[$name]); @@ -560,7 +580,7 @@ class PhpManager extends BaseManager } } } - $this->save(); + $this->saveItems(); return true; } @@ -577,9 +597,9 @@ class PhpManager extends BaseManager $item->updatedAt = $time; } - $this->_items[$item->name] = $item; + $this->items[$item->name] = $item; - $this->save(); + $this->saveItems(); return true; @@ -588,95 +608,63 @@ class PhpManager extends BaseManager /** * Loads authorization data from persistent storage. */ - public function load() + protected function load() { - $this->_children = []; - $this->_rules = []; - $this->_assignments = []; - $this->_items = []; + $this->children = []; + $this->rules = []; + $this->assignments = []; + $this->items = []; - $data = $this->loadFromFile($this->authFile); + $items = $this->loadFromFile($this->itemsFile); + $itemsMtime = @filemtime($this->itemsFile); + $assignments = $this->loadFromFile($this->assignmentsFile); + $assignmentsMtime = @filemtime($this->assignmentsFile); + $rules = $this->loadFromFile($this->rulesFile); - if (isset($data['items'])) { - foreach ($data['items'] as $name => $item) { - $class = $item['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); + foreach ($items as $name => $item) { + $class = $item['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); - $this->_items[$name] = new $class([ - 'name' => $name, - 'description' => isset($item['description']) ? $item['description'] : null, - 'ruleName' => isset($item['ruleName']) ? $item['ruleName'] : null, - 'data' => isset($item['data']) ? $item['data'] : null, - 'createdAt' => isset($item['createdAt']) ? $item['createdAt'] : null, - 'updatedAt' => isset($item['updatedAt']) ? $item['updatedAt'] : null, - ]); - } + $this->items[$name] = new $class([ + 'name' => $name, + 'description' => isset($item['description']) ? $item['description'] : null, + 'ruleName' => isset($item['ruleName']) ? $item['ruleName'] : null, + 'data' => isset($item['data']) ? $item['data'] : null, + 'createdAt' => $itemsMtime, + 'updatedAt' => $itemsMtime, + ]); + } - foreach ($data['items'] as $name => $item) { - if (isset($item['children'])) { - foreach ($item['children'] as $childName) { - if (isset($this->_items[$childName])) { - $this->_children[$name][$childName] = $this->_items[$childName]; - } - } - } - if (isset($item['assignments'])) { - foreach ($item['assignments'] as $userId => $assignment) { - $this->_assignments[$userId][$name] = new Assignment([ - 'userId' => $userId, - 'roleName' => $assignment['roleName'], - 'createdAt' => isset($assignment['createdAt']) ? $assignment['createdAt'] : null, - ]); + foreach ($items as $name => $item) { + if (isset($item['children'])) { + foreach ($item['children'] as $childName) { + if (isset($this->items[$childName])) { + $this->children[$name][$childName] = $this->items[$childName]; } } } } - if (isset($data['rules'])) { - foreach ($data['rules'] as $name => $ruleData) { - $this->_rules[$name] = unserialize($ruleData); - } + foreach ($assignments as $userId => $role) { + $this->assignments[$userId][$role] = new Assignment([ + 'userId' => $userId, + 'roleName' => $role, + 'createdAt' => $assignmentsMtime, + ]); + } + + foreach ($rules as $name => $ruleData) { + $this->rules[$name] = unserialize($ruleData); } } /** * Saves authorization data into persistent storage. */ - public function save() + protected function save() { - $items = []; - foreach ($this->_items as $name => $item) { - /* @var $item Item */ - $items[$name] = array_filter([ - 'type' => $item->type, - 'description' => $item->description, - 'ruleName' => $item->ruleName, - 'data' => $item->data, - ]); - if (isset($this->_children[$name])) { - foreach ($this->_children[$name] as $child) { - /* @var $child Item */ - $items[$name]['children'][] = $child->name; - } - } - } - - foreach ($this->_assignments as $userId => $assignments) { - foreach ($assignments as $name => $assignment) { - /* @var $assignment Assignment */ - if (isset($items[$name])) { - $items[$name]['assignments'][$userId] = [ - 'roleName' => $assignment->roleName, - ]; - } - } - } - - $rules = []; - foreach ($this->_rules as $name => $rule) { - $rules[$name] = serialize($rule); - } - - $this->saveToFile(['items' => $items, 'rules' => $rules], $this->authFile); + $this->saveItems(); + $this->saveAssignments(); + $this->saveRules(); } /** @@ -706,4 +694,57 @@ class PhpManager extends BaseManager { file_put_contents($file, "items as $name => $item) { + /* @var $item Item */ + $items[$name] = array_filter( + [ + 'type' => $item->type, + 'description' => $item->description, + 'ruleName' => $item->ruleName, + 'data' => $item->data, + ] + ); + if (isset($this->children[$name])) { + foreach ($this->children[$name] as $child) { + /* @var $child Item */ + $items[$name]['children'][] = $child->name; + } + } + } + $this->saveToFile($items, $this->itemsFile); + } + + /** + * Saves assignments data into persistent storage. + */ + protected function saveAssignments() + { + $assignmentData = []; + foreach ($this->assignments as $userId => $assignments) { + foreach ($assignments as $name => $assignment) { + /* @var $assignment Assignment */ + $assignmentData[$userId] = $assignment->roleName; + } + } + $this->saveToFile($assignmentData, $this->assignmentsFile); + } + + /** + * Saves rules data into persistent storage. + */ + protected function saveRules() + { + $rules = []; + foreach ($this->rules as $name => $rule) { + $rules[$name] = serialize($rule); + } + $this->saveToFile($rules, $this->rulesFile); + } } diff --git a/tests/unit/framework/rbac/ExposedPhpManager.php b/tests/unit/framework/rbac/ExposedPhpManager.php new file mode 100644 index 0000000000..bf7c111ff2 --- /dev/null +++ b/tests/unit/framework/rbac/ExposedPhpManager.php @@ -0,0 +1,37 @@ + item + /** + * @var array + */ + public $children = []; // itemName, childName => child + /** + * @var \yii\rbac\Assignment[] + */ + public $assignments = []; // userId, itemName => assignment + /** + * @var \yii\rbac\Rule[] + */ + public $rules = []; // ruleName => rule + + public function load() + { + parent::load(); + } + + public function save() + { + parent::save(); + } +} \ No newline at end of file diff --git a/tests/unit/framework/rbac/ManagerTestCase.php b/tests/unit/framework/rbac/ManagerTestCase.php index 335c05abed..ec12f78646 100644 --- a/tests/unit/framework/rbac/ManagerTestCase.php +++ b/tests/unit/framework/rbac/ManagerTestCase.php @@ -7,6 +7,9 @@ use yii\rbac\Permission; use yii\rbac\Role; use yiiunit\TestCase; +/** + * ManagerTestCase + */ abstract class ManagerTestCase extends TestCase { /** @@ -14,7 +17,7 @@ abstract class ManagerTestCase extends TestCase */ protected $auth; - public function testCreateRoleAndPermission() + public function testCreateRole() { $role = $this->auth->createRole('admin'); $this->assertTrue($role instanceof Role); @@ -57,174 +60,6 @@ abstract class ManagerTestCase extends TestCase $this->auth->addChild($user, $changeName); $this->assertCount(1, $this->auth->getChildren($user->name)); } -/* - public function testRemove() - { - - } - - public function testUpdate() - { - - } - - public function testCreateItem() - { - $type = Item::TYPE_TASK; - $name = 'editUser'; - $description = 'edit a user'; - $ruleName = 'isAuthor'; - $data = [1, 2, 3]; - $item = $this->auth->createItem($name, $type, $description, $ruleName, $data); - $this->assertTrue($item instanceof Item); - $this->assertEquals($item->type, $type); - $this->assertEquals($item->name, $name); - $this->assertEquals($item->description, $description); - $this->assertEquals($item->ruleName, $ruleName); - $this->assertEquals($item->data, $data); - - // test shortcut - $name2 = 'createUser'; - $item2 = $this->auth->createRole($name2, $description, $ruleName, $data); - $this->assertEquals($item2->type, Item::TYPE_ROLE); - - // test adding an item with the same name - $this->setExpectedException('\yii\base\Exception'); - $this->auth->createItem($name, $type, $description, $ruleName, $data); - } - - public function testGetItem() - { - $this->assertTrue($this->auth->getItem('readPost') instanceof Item); - $this->assertTrue($this->auth->getItem('reader') instanceof Item); - $this->assertNull($this->auth->getItem('unknown')); - } - - public function testRemoveItem() - { - $this->assertTrue($this->auth->getItem('updatePost') instanceof Item); - $this->assertTrue($this->auth->removeItem('updatePost')); - $this->assertNull($this->auth->getItem('updatePost')); - $this->assertFalse($this->auth->removeItem('updatePost')); - } - - public function testChangeItemName() - { - $item = $this->auth->getItem('readPost'); - $this->assertTrue($item instanceof Item); - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost')); - $item->name = 'readPost2'; - $item->save(); - $this->assertNull($this->auth->getItem('readPost')); - $this->assertEquals($this->auth->getItem('readPost2'), $item); - $this->assertFalse($this->auth->hasItemChild('reader', 'readPost')); - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost2')); - } - - public function testAddItemChild() - { - $this->auth->addItemChild('createPost', 'updatePost'); - - // test adding upper level item to lower one - $this->setExpectedException('\yii\base\Exception'); - $this->auth->addItemChild('readPost', 'reader'); - } - - public function testAddItemChild2() - { - // test adding inexistent items - $this->setExpectedException('\yii\base\Exception'); - $this->assertFalse($this->auth->addItemChild('createPost2', 'updatePost')); - } - - public function testRemoveItemChild() - { - $this->assertTrue($this->auth->hasItemChild('reader', 'readPost')); - $this->assertTrue($this->auth->removeItemChild('reader', 'readPost')); - $this->assertFalse($this->auth->hasItemChild('reader', 'readPost')); - $this->assertFalse($this->auth->removeItemChild('reader', 'readPost')); - } - - public function testGetItemChildren() - { - $this->assertEquals([], $this->auth->getItemChildren('readPost')); - $children = $this->auth->getItemChildren('author'); - $this->assertEquals(3, count($children)); - $this->assertTrue(reset($children) instanceof Item); - } - - public function testAssign() - { - $auth = $this->auth->assign('new user', 'createPost', 'isAuthor', 'data'); - $this->assertTrue($auth instanceof Assignment); - $this->assertEquals($auth->userId, 'new user'); - $this->assertEquals($auth->itemName, 'createPost'); - $this->assertEquals($auth->ruleName, 'isAuthor'); - $this->assertEquals($auth->data, 'data'); - - $this->setExpectedException('\yii\base\Exception'); - $this->auth->assign('new user', 'createPost2', 'rule', 'data'); - } - - public function testRevoke() - { - $this->assertTrue($this->auth->isAssigned('author B', 'author')); - $auth = $this->auth->getAssignment('author B', 'author'); - $this->assertTrue($auth instanceof Assignment); - $this->assertTrue($this->auth->revoke('author B', 'author')); - $this->assertFalse($this->auth->isAssigned('author B', 'author')); - $this->assertFalse($this->auth->revoke('author B', 'author')); - } - - public function testRevokeAll() - { - $this->assertTrue($this->auth->revokeAll('reader E')); - $this->assertFalse($this->auth->isAssigned('reader E', 'reader')); - } - - public function testGetAssignments() - { - $this->auth->assign('author B', 'deletePost'); - $auths = $this->auth->getAssignments('author B'); - $this->assertEquals(2, count($auths)); - $this->assertTrue(reset($auths) instanceof Assignment); - } - - public function testGetItems() - { - $this->assertEquals(count($this->auth->getRoles()), 4); - $this->assertEquals(count($this->auth->getOperations()), 4); - $this->assertEquals(count($this->auth->getTasks()), 1); - $this->assertEquals(count($this->auth->getItems()), 9); - - $this->assertEquals(count($this->auth->getItems('author B', null)), 1); - $this->assertEquals(count($this->auth->getItems('author C', null)), 0); - $this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_ROLE)), 1); - $this->assertEquals(count($this->auth->getItems('author B', Item::TYPE_OPERATION)), 0); - } - - public function testClearAll() - { - $this->auth->clearAll(); - $this->assertEquals(count($this->auth->getRoles()), 0); - $this->assertEquals(count($this->auth->getOperations()), 0); - $this->assertEquals(count($this->auth->getTasks()), 0); - $this->assertEquals(count($this->auth->getItems()), 0); - $this->assertEquals(count($this->auth->getAssignments('author B')), 0); - } - - public function testClearAssignments() - { - $this->auth->clearAssignments(); - $this->assertEquals(count($this->auth->getAssignments('author B')), 0); - } - - public function testDetectLoop() - { - $this->setExpectedException('\yii\base\Exception'); - $this->auth->addItemChild('readPost', 'readPost'); - } - */ public function testGetRule() { diff --git a/tests/unit/framework/rbac/PhpManagerTest.php b/tests/unit/framework/rbac/PhpManagerTest.php index 561905f54d..4f2e41209e 100644 --- a/tests/unit/framework/rbac/PhpManagerTest.php +++ b/tests/unit/framework/rbac/PhpManagerTest.php @@ -3,38 +3,74 @@ namespace yiiunit\framework\rbac; use Yii; -use yii\rbac\PhpManager; /** * @group rbac - * @property \yii\rbac\PhpManager $auth + * @property ExposedPhpManager $auth */ class PhpManagerTest extends ManagerTestCase { + protected function getItemsFile() + { + return Yii::$app->getRuntimePath() . '/rbac-items.php'; + } + + protected function getAssignmentsFile() + { + return Yii::$app->getRuntimePath() . '/rbac-assignments.php'; + } + + protected function getRulesFile() + { + return Yii::$app->getRuntimePath() . '/rbac-rules.php'; + } + + protected function removeDataFiles() + { + @unlink($this->getItemsFile()); + @unlink($this->getAssignmentsFile()); + @unlink($this->getRulesFile()); + } + + protected function createManager() + { + return new ExposedPhpManager([ + 'itemsFile' => $this->getItemsFile(), + 'assignmentsFile' => $this->getAssignmentsFile(), + 'rulesFile' => $this->getRulesFile(), + ]); + } + protected function setUp() { parent::setUp(); $this->mockApplication(); - $authFile = Yii::$app->getRuntimePath() . '/rbac.php'; - @unlink($authFile); - $this->auth = new PhpManager(); - $this->auth->authFile = $authFile; - $this->auth->init(); + $this->removeDataFiles(); + $this->auth = $this->createManager(); } protected function tearDown() { + $this->removeDataFiles(); parent::tearDown(); - @unlink($this->auth->authFile); } public function testSaveLoad() { $this->prepareData(); - $this->auth->save(); - $this->auth->removeAll(); - $this->auth->load(); - // TODO : Check if loaded and saved data are the same. - } + $items = $this->auth->items; + $children = $this->auth->children; + $assignments = $this->auth->assignments; + $rules = $this->auth->rules; + $this->auth->save(); + + $this->auth = $this->createManager(); + $this->auth->load(); + + $this->assertEquals($items, $this->auth->items); + $this->assertEquals($children, $this->auth->children); + $this->assertEquals($assignments, $this->auth->assignments); + $this->assertEquals($rules, $this->auth->rules); + } } \ No newline at end of file From c68e5f1fdbf33fd5e8bbeefe854b0381a156299c Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sun, 29 Jun 2014 16:18:19 +0400 Subject: [PATCH 2/2] Adjusted naming --- framework/CHANGELOG.md | 2 +- framework/UPGRADE.md | 8 +++--- framework/rbac/PhpManager.php | 28 ++++++++++---------- tests/unit/framework/rbac/PhpManagerTest.php | 18 ++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 1ed4d3bec4..b775258f7a 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -123,7 +123,7 @@ Yii Framework 2 Change Log - Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq) - Enh #4072: `\yii\rbac\PhpManager` adjustments (samdark) - Data is now stored in three separate files for items, assignments and rules. File format is simpler. - - Removed `authFile`. Added `itemsFile`, `assignmentsFile` and `rulesFile`. + - Removed `authFile`. Added `itemFile`, `assignmentFile` and `ruleFile`. - `createdAt` and `updatedAt` are now properly filled with corresponding file modification time. - `save()` and `load()` are now protected instead of public. - Added unit test for saving and loading data. diff --git a/framework/UPGRADE.md b/framework/UPGRADE.md index 5011128589..8df600bbf8 100644 --- a/framework/UPGRADE.md +++ b/framework/UPGRADE.md @@ -79,9 +79,9 @@ new ones save the following code as `convert.php` that should be placed in the s ```php getSecurity()->hashData()`. diff --git a/framework/rbac/PhpManager.php b/framework/rbac/PhpManager.php index d22d3bac80..e7089b145d 100644 --- a/framework/rbac/PhpManager.php +++ b/framework/rbac/PhpManager.php @@ -38,7 +38,7 @@ class PhpManager extends BaseManager * @see loadFromFile() * @see saveToFile() */ - public $itemsFile = '@app/data/rbac-items.php'; + public $itemFile = '@app/rbac/items.php'; /** * @var string the path of the PHP script that contains the authorization assignments. * This can be either a file path or a path alias to the file. @@ -46,7 +46,7 @@ class PhpManager extends BaseManager * @see loadFromFile() * @see saveToFile() */ - public $assignmentsFile = '@app/data/rbac-assignments.php'; + public $assignmentFile = '@app/rbac/assignments.php'; /** * @var string the path of the PHP script that contains the authorization rules. @@ -55,7 +55,7 @@ class PhpManager extends BaseManager * @see loadFromFile() * @see saveToFile() */ - public $rulesFile = '@app/data/rbac-rules.php'; + public $ruleFile = '@app/rbac/rules.php'; /** * @var Item[] */ @@ -82,9 +82,9 @@ class PhpManager extends BaseManager public function init() { parent::init(); - $this->itemsFile = Yii::getAlias($this->itemsFile); - $this->assignmentsFile = Yii::getAlias($this->assignmentsFile); - $this->rulesFile = Yii::getAlias($this->rulesFile); + $this->itemFile = Yii::getAlias($this->itemFile); + $this->assignmentFile = Yii::getAlias($this->assignmentFile); + $this->ruleFile = Yii::getAlias($this->ruleFile); $this->load(); } @@ -615,11 +615,11 @@ class PhpManager extends BaseManager $this->assignments = []; $this->items = []; - $items = $this->loadFromFile($this->itemsFile); - $itemsMtime = @filemtime($this->itemsFile); - $assignments = $this->loadFromFile($this->assignmentsFile); - $assignmentsMtime = @filemtime($this->assignmentsFile); - $rules = $this->loadFromFile($this->rulesFile); + $items = $this->loadFromFile($this->itemFile); + $itemsMtime = @filemtime($this->itemFile); + $assignments = $this->loadFromFile($this->assignmentFile); + $assignmentsMtime = @filemtime($this->assignmentFile); + $rules = $this->loadFromFile($this->ruleFile); foreach ($items as $name => $item) { $class = $item['type'] == Item::TYPE_PERMISSION ? Permission::className() : Role::className(); @@ -718,7 +718,7 @@ class PhpManager extends BaseManager } } } - $this->saveToFile($items, $this->itemsFile); + $this->saveToFile($items, $this->itemFile); } /** @@ -733,7 +733,7 @@ class PhpManager extends BaseManager $assignmentData[$userId] = $assignment->roleName; } } - $this->saveToFile($assignmentData, $this->assignmentsFile); + $this->saveToFile($assignmentData, $this->assignmentFile); } /** @@ -745,6 +745,6 @@ class PhpManager extends BaseManager foreach ($this->rules as $name => $rule) { $rules[$name] = serialize($rule); } - $this->saveToFile($rules, $this->rulesFile); + $this->saveToFile($rules, $this->ruleFile); } } diff --git a/tests/unit/framework/rbac/PhpManagerTest.php b/tests/unit/framework/rbac/PhpManagerTest.php index 4f2e41209e..d420b7a51d 100644 --- a/tests/unit/framework/rbac/PhpManagerTest.php +++ b/tests/unit/framework/rbac/PhpManagerTest.php @@ -10,34 +10,34 @@ use Yii; */ class PhpManagerTest extends ManagerTestCase { - protected function getItemsFile() + protected function getItemFile() { return Yii::$app->getRuntimePath() . '/rbac-items.php'; } - protected function getAssignmentsFile() + protected function getAssignmentFile() { return Yii::$app->getRuntimePath() . '/rbac-assignments.php'; } - protected function getRulesFile() + protected function getRuleFile() { return Yii::$app->getRuntimePath() . '/rbac-rules.php'; } protected function removeDataFiles() { - @unlink($this->getItemsFile()); - @unlink($this->getAssignmentsFile()); - @unlink($this->getRulesFile()); + @unlink($this->getItemFile()); + @unlink($this->getAssignmentFile()); + @unlink($this->getRuleFile()); } protected function createManager() { return new ExposedPhpManager([ - 'itemsFile' => $this->getItemsFile(), - 'assignmentsFile' => $this->getAssignmentsFile(), - 'rulesFile' => $this->getRulesFile(), + 'itemFile' => $this->getItemFile(), + 'assignmentFile' => $this->getAssignmentFile(), + 'ruleFile' => $this->getRuleFile(), ]); }