Commit c3f4e005 by Qiang Xue

Refactored `yii\rbac\PhpManager`

Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()`
parent 12c3b59b
......@@ -7,7 +7,7 @@ Yii Framework 2 Change Log
- Bug #3091: Fixed inconsistent treatment of `Widget::run()` when a widget is used as a container and as a self-contained object (qiangxue)
- Enh #3103: debugger panel is now not displayed when printing a page (githubjeka)
- Enh #3108: Added `yii\debug\Module::enableDebugLogs` to disable logging debug logs by default (qiangxue)
- no changes in this release.
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
2.0.0-beta April 13, 2014
......
......@@ -7,3 +7,10 @@ The following upgrading instructions are cumulative. That is,
if you want to upgrade from version A to version C and there is
version B between A and C, you need to following the instructions
for both A and B.
Upgrade from Yii 2.0 Beta
-------------------------
* If you used `clearAll()` or `clearAllAssignments()` of `yii\rbac\DbManager`, you should replace
them with `removeAll()` and `removeAllAssignments()` respectively.
......@@ -551,6 +551,17 @@ class DbManager extends BaseManager
/**
* @inheritdoc
*/
public function hasChild($parent, $child)
{
return (new Query)
->from($this->itemChildTable)
->where(['parent' => $parent->name, 'child' => $child->$name])
->one($this->db) !== false;
}
/**
* @inheritdoc
*/
public function getChildren($name)
{
$query = (new Query)
......@@ -627,20 +638,78 @@ class DbManager extends BaseManager
}
/**
* Removes all authorization data.
* @inheritdoc
*/
public function clearAll()
public function removeAll()
{
$this->clearAssignments();
$this->removeAllAssignments();
$this->db->createCommand()->delete($this->itemChildTable)->execute();
$this->db->createCommand()->delete($this->itemTable)->execute();
$this->db->createCommand()->delete($this->ruleTable)->execute();
}
/**
* Removes all authorization assignments.
* @inheritdoc
*/
public function removeAllPermissions()
{
$this->removeAllItems(Item::TYPE_PERMISSION);
}
/**
* @inheritdoc
*/
public function removeAllRoles()
{
$this->removeAllItems(Item::TYPE_ROLE);
}
/**
* Removes all auth items of the specified type.
* @param integer $type the auth item type (either Item::TYPE_PERMISSION or Item::TYPE_ROLE)
*/
protected function removeAllItems($type)
{
if (!$this->supportsCascadeUpdate()) {
$names = (new Query)
->select(['name'])
->from($this->itemTable)
->where(['type' => $type])
->column($this->db);
if (empty($names)) {
return;
}
$key = $type == Item::TYPE_PERMISSION ? 'child' : 'parent';
$this->db->createCommand()
->delete($this->itemChildTable, [$key => $names])
->execute();
$this->db->createCommand()
->delete($this->assignmentTable, ['item_name' => $names])
->execute();
}
$this->db->createCommand()
->delete($this->itemTable, ['type' => $type])
->execute();
}
/**
* @inheritdoc
*/
public function removeAllRules()
{
if (!$this->supportsCascadeUpdate()) {
$this->db->createCommand()
->update($this->itemTable, ['ruleName' => null])
->execute();
}
$this->db->createCommand()->delete($this->ruleTable)->execute();
}
/**
* @inheritdoc
*/
public function clearAssignments()
public function removeAllAssignments()
{
$this->db->createCommand()->delete($this->assignmentTable)->execute();
}
......
......@@ -146,6 +146,14 @@ interface ManagerInterface
public function removeChild($parent, $child);
/**
* Returns a value indicating whether the child already exists for the parent.
* @param Item $parent
* @param Item $child
* @return boolean whether `$child` is already a child of `$parent`
*/
public function hasChild($parent, $child);
/**
* Returns the child permissions and/or roles.
* @param string $name the parent name
* @return Item[] the child permissions and/or roles
......@@ -198,12 +206,30 @@ interface ManagerInterface
public function getAssignments($userId);
/**
* Removes all authorization data.
* Removes all authorization data, including roles, permissions, rules, and assignments.
*/
public function removeAll();
/**
* Removes all permissions.
* All parent child relations will be adjusted accordingly.
*/
public function removeAllPermissions();
/**
* Removes all roles.
* All parent child relations will be adjusted accordingly.
*/
public function removeAllRoles();
/**
* Removes all rules.
* All roles and permissions which have rules will be adjusted accordingly.
*/
public function clearAll();
public function removeAllRules();
/**
* Removes all authorization assignments.
* Removes all role assignments.
*/
public function clearAssignments();
public function removeAllAssignments();
}
......@@ -40,10 +40,21 @@ class PhpManager extends BaseManager
* @see saveToFile()
*/
public $authFile = '@app/data/rbac.php';
/**
* @var Item[]
*/
private $_items = []; // itemName => item
/**
* @var array
*/
private $_children = []; // itemName, childName => child
/**
* @var Assignment[]
*/
private $_assignments = []; // userId, itemName => assignment
/**
* @var Rule[]
*/
private $_rules = []; // ruleName => rule
......@@ -60,90 +71,6 @@ class PhpManager extends BaseManager
}
/**
* Loads authorization data.
*/
public function load()
{
$this->clearAll();
$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' => $item['description'],
'ruleName' => $item['ruleName'],
'data' => $item['data'],
'createdAt' => isset($item['createdAt']) ? $item['createdAt'] : time(),
'updatedAt' => isset($item['updatedAt']) ? $item['updatedAt'] : time(),
]);
}
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'] : time(),
]);
}
}
}
}
if (isset($data['rules'])) {
foreach ($data['rules'] as $name => $ruleData) {
$this->_rules[$name] = unserialize($ruleData);
}
}
}
/**
* Removes all authorization data.
*/
public function clearAll()
{
$this->clearAssignments();
$this->_children = [];
$this->_items = [];
}
/**
* Removes all authorization assignments.
*/
public function clearAssignments()
{
$this->_assignments = [];
}
/**
* Loads the authorization data from a PHP script file.
*
* @param string $file the file path.
* @return array the authorization data
* @see saveToFile()
*/
protected function loadFromFile($file)
{
if (is_file($file)) {
return require($file);
} else {
return [];
}
}
/**
* @inheritdoc
*/
public function checkAccess($userId, $permissionName, $params = [])
......@@ -176,7 +103,7 @@ class PhpManager extends BaseManager
* @param Assignment[] $assignments the assignments to the specified user
* @return boolean whether the operations can be performed by the user.
*/
public function checkAccessRecursive($user, $itemName, $params, $assignments)
protected function checkAccessRecursive($user, $itemName, $params, $assignments)
{
if (!isset($this->_items[$itemName])) {
return false;
......@@ -226,6 +153,7 @@ class PhpManager extends BaseManager
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();
return true;
}
......@@ -262,7 +190,7 @@ class PhpManager extends BaseManager
{
if (isset($this->_children[$parent->name][$child->name])) {
unset($this->_children[$parent->name][$child->name]);
$this->save();
return true;
} else {
return false;
......@@ -270,13 +198,9 @@ class PhpManager extends BaseManager
}
/**
* Returns a value indicating whether a child exists within a parent.
*
* @param Item $parent the parent item name
* @param Item $child the child item name
* @return boolean whether the child exists
* @inheritdoc
*/
public function hasItemChild($parent, $child)
public function hasChild($parent, $child)
{
return isset($this->_children[$parent->name][$child->name]);
}
......@@ -291,11 +215,13 @@ class PhpManager extends BaseManager
} elseif (isset($this->_assignments[$userId][$role->name])) {
throw new InvalidParamException("Authorization item '{$role->name}' has already been assigned to user '$userId'.");
} else {
return $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];
}
}
......@@ -306,7 +232,7 @@ class PhpManager extends BaseManager
{
if (isset($this->_assignments[$userId][$role->name])) {
unset($this->_assignments[$userId][$role->name]);
$this->save();
return true;
} else {
return false;
......@@ -322,7 +248,7 @@ class PhpManager extends BaseManager
foreach ($this->_assignments[$userId] as $itemName => $value) {
unset($this->_assignments[$userId][$itemName]);
}
$this->save();
return true;
} else {
return false;
......@@ -368,7 +294,7 @@ class PhpManager extends BaseManager
unset($assignments[$item->name]);
}
unset($this->_items[$item->name]);
$this->save();
return true;
} else {
return false;
......@@ -384,70 +310,6 @@ class PhpManager extends BaseManager
}
/**
* Saves the changes to an authorization assignment.
*
* @param Assignment $assignment the assignment that has been changed.
*/
public function saveAssignment(Assignment $assignment)
{
}
/**
* Saves authorization data into persistent storage.
* If any change is made to the authorization data, please make
* sure you call this method to save the changed data into persistent storage.
*/
public function save()
{
$items = [];
foreach ($this->_items as $name => $item) {
/** @var Item $item */
$items[$name] = [
'type' => $item->type,
'description' => $item->description,
'ruleName' => $item->ruleName,
'data' => $item->data,
];
if (isset($this->_children[$name])) {
foreach ($this->_children[$name] as $child) {
/** @var Item $child */
$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);
}
/**
* Saves the authorization data to a PHP script file.
*
* @param array $data the authorization data
* @param string $file the file path.
* @see loadFromFile()
*/
protected function saveToFile($data, $file)
{
file_put_contents($file, "<?php\nreturn " . var_export($data, true) . ";\n", LOCK_EX);
}
/**
* @inheritdoc
*/
public function updateRule($name, $rule)
......@@ -456,6 +318,7 @@ class PhpManager extends BaseManager
unset($this->_rules[$name]);
}
$this->_rules[$rule->name] = $rule;
$this->save();
return true;
}
......@@ -558,10 +421,103 @@ class PhpManager extends BaseManager
/**
* @inheritdoc
*/
public function removeAll()
{
$this->_children = [];
$this->_items = [];
$this->_assignments = [];
$this->_rules = [];
$this->save();
}
/**
* @inheritdoc
*/
public function removeAllPermissions()
{
$this->removeAllItems(Item::TYPE_PERMISSION);
}
/**
* @inheritdoc
*/
public function removeAllRoles()
{
$this->removeAllItems(Item::TYPE_ROLE);
}
/**
* Removes all auth items of the specified type.
* @param integer $type the auth item type (either Item::TYPE_PERMISSION or Item::TYPE_ROLE)
*/
protected function removeAllItems($type)
{
$names = [];
foreach ($this->_items as $name => $item) {
if ($item->type == $type) {
unset($this->_items[$name]);
$names[$name] = true;
}
}
if (empty($names)) {
return;
}
foreach ($this->_assignments as $i => $assignment) {
if (isset($names[$assignment->roleName])) {
unset($this->_assignments[$i]);
}
}
foreach ($this->_children as $name => $children) {
if (isset($names[$name])) {
unset($this->_children[$name]);
} else {
foreach ($children as $childName => $item) {
if (isset($names[$childName])) {
unset($children[$childName]);
}
}
$this->_children[$name] = $children;
}
}
$this->save();
}
/**
* @inheritdoc
*/
public function removeAllRules()
{
foreach ($this->_items as $item) {
$item->ruleName = null;
}
$this->_rules = [];
$this->save();
}
/**
* @inheritdoc
*/
public function removeAllAssignments()
{
$this->_assignments = [];
$this->save();
}
/**
* @inheritdoc
*/
protected function removeRule($rule)
{
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();
return true;
} else {
return false;
......@@ -574,6 +530,7 @@ class PhpManager extends BaseManager
protected function addRule($rule)
{
$this->_rules[$rule->name] = $rule;
$this->save();
return true;
}
......@@ -608,6 +565,7 @@ class PhpManager extends BaseManager
}
}
}
$this->save();
return true;
}
......@@ -626,7 +584,131 @@ class PhpManager extends BaseManager
$this->_items[$item->name] = $item;
$this->save();
return true;
}
/**
* 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' => $item['description'],
'ruleName' => $item['ruleName'],
'data' => $item['data'],
'createdAt' => isset($item['createdAt']) ? $item['createdAt'] : time(),
'updatedAt' => isset($item['updatedAt']) ? $item['updatedAt'] : time(),
]);
}
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'] : time(),
]);
}
}
}
}
if (isset($data['rules'])) {
foreach ($data['rules'] as $name => $ruleData) {
$this->_rules[$name] = unserialize($ruleData);
}
}
}
/**
* Saves authorization data into persistent storage.
*/
public function save()
{
$items = [];
foreach ($this->_items as $name => $item) {
/** @var Item $item */
$items[$name] = [
'type' => $item->type,
'description' => $item->description,
'ruleName' => $item->ruleName,
'data' => $item->data,
];
if (isset($this->_children[$name])) {
foreach ($this->_children[$name] as $child) {
/** @var Item $child */
$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);
}
/**
* Loads the authorization data from a PHP script file.
*
* @param string $file the file path.
* @return array the authorization data
* @see saveToFile()
*/
protected function loadFromFile($file)
{
if (is_file($file)) {
return require($file);
} else {
return [];
}
}
/**
* Saves the authorization data to a PHP script file.
*
* @param array $data the authorization data
* @param string $file the file path.
* @see loadFromFile()
*/
protected function saveToFile($data, $file)
{
file_put_contents($file, "<?php\nreturn " . var_export($data, true) . ";\n", LOCK_EX);
}
}
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