Commit 3eee7b8e by Alexander Makarov

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.
parent c8ee057e
......@@ -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)
......
......@@ -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
<?php
$oldFile = 'rbac.php';
$itemsFile = 'rbac-items.php';
$assignmentsFile = 'rbac-assignments.php';
$rulesFile = 'rbac-rules.php';
$oldData = include $oldFile;
function saveToFile($data, $fileName) {
$out = var_export($data, true);
$out = "<?php\nreturn " . $out . ";";
$out = str_replace(['array (', ')'], ['[', ']'], $out);
file_put_contents($fileName, $out);
}
$items = [];
$assignments = [];
if (isset($oldData['items'])) {
foreach ($oldData['items'] as $name => $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
......@@ -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 <qiang.xue@gmail.com>
* @author Alexander Kochetov <creocoder@gmail.com>
* @since 2.0
......
......@@ -26,34 +26,52 @@ use yii\helpers\VarDumper;
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Alexander Kochetov <creocoder@gmail.com>
* @author Christophe Boulain <christophe.boulain@gmail.com>
* @author Alexander Makarov <sam@rmcreative.ru>
* @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()
{
$this->_children = [];
$this->_rules = [];
$this->_assignments = [];
$this->_items = [];
$data = $this->loadFromFile($this->authFile);
if (isset($data['items'])) {
foreach ($data['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,
]);
}
protected function load()
{
$this->children = [];
$this->rules = [];
$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);
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' => $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, "<?php\nreturn " . VarDumper::export($data) . ";\n", LOCK_EX);
}
/**
* Saves items data into persistent storage.
*/
protected function saveItems()
{
$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;
}
}
}
$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);
}
}
<?php
namespace yiiunit\framework\rbac;
use yii\rbac\PhpManager;
/**
* Exposes protected properties and methods to inspect from outside
*/
class ExposedPhpManager extends PhpManager
{
/**
* @var \yii\rbac\Item[]
*/
public $items = []; // itemName => 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
......@@ -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()
{
......
......@@ -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();
$items = $this->auth->items;
$children = $this->auth->children;
$assignments = $this->auth->assignments;
$rules = $this->auth->rules;
$this->auth->save();
$this->auth->removeAll();
$this->auth = $this->createManager();
$this->auth->load();
// TODO : Check if loaded and saved data are the same.
}
$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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment