Commit 2c28198c by Alexander Makarov

Fixes #499: Decoupled `Rule` from RBAC `Item`

parent 0e6cbda4
...@@ -79,6 +79,7 @@ Yii Framework 2 Change Log ...@@ -79,6 +79,7 @@ Yii Framework 2 Change Log
- Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard) - Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard)
- Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard) - Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard)
- Enh #497: Removed `\yii\log\Target::logUser` and added `\yii\log\Target::prefix` to support customizing message prefix (qiangxue) - Enh #497: Removed `\yii\log\Target::logUser` and added `\yii\log\Target::prefix` to support customizing message prefix (qiangxue)
- Enh #499: Decoupled `Rule` from RBAC `Item` (samdark, qiangxue)
- Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue) - Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue)
- Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe) - Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe)
- Enh #938: Added `yii\web\View::renderAjax()` and `yii\web\Controller::renderAjax()` (qiangxue) - Enh #938: Added `yii\web\View::renderAjax()` and `yii\web\Controller::renderAjax()` (qiangxue)
......
...@@ -77,7 +77,7 @@ class DbManager extends Manager ...@@ -77,7 +77,7 @@ class DbManager extends Manager
* @param mixed $userId the user ID. This should can be either an integer or a string representing * @param mixed $userId the user ID. This should can be either an integer or a string representing
* the unique identifier of a user. See [[\yii\web\User::id]]. * the unique identifier of a user. See [[\yii\web\User::id]].
* @param string $itemName the name of the operation that need access check * @param string $itemName the name of the operation that need access check
* @param array $params name-value pairs that would be passed to biz rules associated * @param array $params name-value pairs that would be passed to rules associated
* with the tasks and roles assigned to the user. A param with name 'userId' is added to this array, * with the tasks and roles assigned to the user. A param with name 'userId' is added to this array,
* which holds the value of `$userId`. * which holds the value of `$userId`.
* @return boolean whether the operations can be performed by the user. * @return boolean whether the operations can be performed by the user.
...@@ -95,7 +95,7 @@ class DbManager extends Manager ...@@ -95,7 +95,7 @@ class DbManager extends Manager
* @param mixed $userId the user ID. This should can be either an integer or a string representing * @param mixed $userId the user ID. This should can be either an integer or a string representing
* the unique identifier of a user. See [[\yii\web\User::id]]. * the unique identifier of a user. See [[\yii\web\User::id]].
* @param string $itemName the name of the operation that need access check * @param string $itemName the name of the operation that need access check
* @param array $params name-value pairs that would be passed to biz rules associated * @param array $params name-value pairs that would be passed to rules associated
* with the tasks and roles assigned to the user. A param with name 'userId' is added to this array, * with the tasks and roles assigned to the user. A param with name 'userId' is added to this array,
* which holds the value of `$userId`. * which holds the value of `$userId`.
* @param Assignment[] $assignments the assignments to the specified user * @param Assignment[] $assignments the assignments to the specified user
...@@ -116,7 +116,7 @@ class DbManager extends Manager ...@@ -116,7 +116,7 @@ class DbManager extends Manager
} }
if (isset($assignments[$itemName])) { if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName]; $assignment = $assignments[$itemName];
if ($this->executeRule($assignment->bizRule, $params, $assignment->data)) { if ($this->executeRule($assignment->ruleName, $params, $assignment->data)) {
return true; return true;
} }
} }
...@@ -216,7 +216,7 @@ class DbManager extends Manager ...@@ -216,7 +216,7 @@ class DbManager extends Manager
public function getItemChildren($names) public function getItemChildren($names)
{ {
$query = new Query; $query = new Query;
$rows = $query->select(['name', 'type', 'description', 'biz_rule', 'data']) $rows = $query->select(['name', 'type', 'description', 'rule_name', 'data'])
->from([$this->itemTable, $this->itemChildTable]) ->from([$this->itemTable, $this->itemChildTable])
->where(['parent' => $names, 'name' => new Expression('child')]) ->where(['parent' => $names, 'name' => new Expression('child')])
->createCommand($this->db) ->createCommand($this->db)
...@@ -231,7 +231,7 @@ class DbManager extends Manager ...@@ -231,7 +231,7 @@ class DbManager extends Manager
'name' => $row['name'], 'name' => $row['name'],
'type' => $row['type'], 'type' => $row['type'],
'description' => $row['description'], 'description' => $row['description'],
'bizRule' => $row['biz_rule'], 'ruleName' => $row['rule_name'],
'data' => $data, 'data' => $data,
]); ]);
} }
...@@ -259,7 +259,7 @@ class DbManager extends Manager ...@@ -259,7 +259,7 @@ class DbManager extends Manager
->insert($this->assignmentTable, [ ->insert($this->assignmentTable, [
'user_id' => $userId, 'user_id' => $userId,
'item_name' => $itemName, 'item_name' => $itemName,
'biz_rule' => $ruleName, 'rule_name' => $ruleName,
'data' => $data === null ? null : serialize($data), 'data' => $data === null ? null : serialize($data),
]) ])
->execute(); ->execute();
...@@ -268,7 +268,7 @@ class DbManager extends Manager ...@@ -268,7 +268,7 @@ class DbManager extends Manager
'manager' => $this, 'manager' => $this,
'userId' => $userId, 'userId' => $userId,
'itemName' => $itemName, 'itemName' => $itemName,
'bizRule' => $ruleName, 'ruleName' => $ruleName,
'data' => $data, 'data' => $data,
]); ]);
} }
...@@ -338,7 +338,7 @@ class DbManager extends Manager ...@@ -338,7 +338,7 @@ class DbManager extends Manager
'manager' => $this, 'manager' => $this,
'userId' => $row['user_id'], 'userId' => $row['user_id'],
'itemName' => $row['item_name'], 'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'], 'ruleName' => $row['rule_name'],
'data' => $data, 'data' => $data,
]); ]);
} else { } else {
...@@ -368,7 +368,7 @@ class DbManager extends Manager ...@@ -368,7 +368,7 @@ class DbManager extends Manager
'manager' => $this, 'manager' => $this,
'userId' => $row['user_id'], 'userId' => $row['user_id'],
'itemName' => $row['item_name'], 'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'], 'ruleName' => $row['rule_name'],
'data' => $data, 'data' => $data,
]); ]);
} }
...@@ -384,7 +384,7 @@ class DbManager extends Manager ...@@ -384,7 +384,7 @@ class DbManager extends Manager
{ {
$this->db->createCommand() $this->db->createCommand()
->update($this->assignmentTable, [ ->update($this->assignmentTable, [
'biz_rule' => $assignment->bizRule, 'rule_name' => $assignment->ruleName,
'data' => $assignment->data === null ? null : serialize($assignment->data), 'data' => $assignment->data === null ? null : serialize($assignment->data),
], [ ], [
'user_id' => $assignment->userId, 'user_id' => $assignment->userId,
...@@ -412,12 +412,12 @@ class DbManager extends Manager ...@@ -412,12 +412,12 @@ class DbManager extends Manager
->where(['type' => $type]) ->where(['type' => $type])
->createCommand($this->db); ->createCommand($this->db);
} elseif ($type === null) { } elseif ($type === null) {
$command = $query->select(['name', 'type', 'description', 't1.biz_rule', 't1.data']) $command = $query->select(['name', 'type', 'description', 't1.rule_name', 't1.data'])
->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2']) ->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2'])
->where(['user_id' => $userId, 'name' => new Expression('item_name')]) ->where(['user_id' => $userId, 'name' => new Expression('item_name')])
->createCommand($this->db); ->createCommand($this->db);
} else { } else {
$command = $query->select(['name', 'type', 'description', 't1.biz_rule', 't1.data']) $command = $query->select(['name', 'type', 'description', 't1.rule_name', 't1.data'])
->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2']) ->from([$this->itemTable . ' t1', $this->assignmentTable . ' t2'])
->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')]) ->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')])
->createCommand($this->db); ->createCommand($this->db);
...@@ -432,7 +432,7 @@ class DbManager extends Manager ...@@ -432,7 +432,7 @@ class DbManager extends Manager
'name' => $row['name'], 'name' => $row['name'],
'type' => $row['type'], 'type' => $row['type'],
'description' => $row['description'], 'description' => $row['description'],
'bizRule' => $row['biz_rule'], 'ruleName' => $row['rule_name'],
'data' => $data, 'data' => $data,
]); ]);
} }
...@@ -463,7 +463,7 @@ class DbManager extends Manager ...@@ -463,7 +463,7 @@ class DbManager extends Manager
'name' => $name, 'name' => $name,
'type' => $type, 'type' => $type,
'description' => $description, 'description' => $description,
'biz_rule' => $rule, 'rule_name' => $rule,
'data' => $data === null ? null : serialize($data), 'data' => $data === null ? null : serialize($data),
]) ])
->execute(); ->execute();
...@@ -473,7 +473,7 @@ class DbManager extends Manager ...@@ -473,7 +473,7 @@ class DbManager extends Manager
'name' => $name, 'name' => $name,
'type' => $type, 'type' => $type,
'description' => $description, 'description' => $description,
'bizRule' => $rule, 'ruleName' => $rule,
'data' => $data, 'data' => $data,
]); ]);
} }
...@@ -522,7 +522,7 @@ class DbManager extends Manager ...@@ -522,7 +522,7 @@ class DbManager extends Manager
'name' => $row['name'], 'name' => $row['name'],
'type' => $row['type'], 'type' => $row['type'],
'description' => $row['description'], 'description' => $row['description'],
'bizRule' => $row['biz_rule'], 'ruleName' => $row['rule_name'],
'data' => $data, 'data' => $data,
]); ]);
} else { } else {
...@@ -623,7 +623,7 @@ class DbManager extends Manager ...@@ -623,7 +623,7 @@ class DbManager extends Manager
*/ */
public function removeRule($name) public function removeRule($name)
{ {
// TODO: Implement removeRule() method. return $this->db->createCommand()->delete($this->ruleTable, ['name' => $name])->execute();
} }
/** /**
...@@ -633,7 +633,12 @@ class DbManager extends Manager ...@@ -633,7 +633,12 @@ class DbManager extends Manager
*/ */
public function saveRule(Rule $rule) public function saveRule(Rule $rule)
{ {
// TODO: Implement saveRule() method. $data = serialize($rule);
try {
$this->db->createCommand()->insert($this->ruleTable, ['name' => $rule->name, 'data' => $data])->execute();
} catch (\yii\db\Exception $e) {
$this->db->createCommand()->update($this->ruleTable, ['data' => $data], ['name' => $rule->name])->execute();
}
} }
/** /**
...@@ -644,7 +649,10 @@ class DbManager extends Manager ...@@ -644,7 +649,10 @@ class DbManager extends Manager
*/ */
public function getRule($name) public function getRule($name)
{ {
// TODO: Implement getRule() method. $query = new Query;
$query->select(['data'])->from($this->ruleTable)->where(['name' => $name]);
$row = $query->createCommand($this->db)->queryOne();
return $row === false ? null : unserialize($row['data']);
} }
/** /**
...@@ -654,5 +662,13 @@ class DbManager extends Manager ...@@ -654,5 +662,13 @@ class DbManager extends Manager
*/ */
public function getRules() public function getRules()
{ {
// TODO: Implement getRules() method. $query = new Query();
}} $rows = $query->from($this->ruleTable)->createCommand($this->db)->queryAll();
$rules = [];
foreach ($rows as $row) {
$rules[$row['name']] = unserialize($row['data']);
}
return $rules;
}
}
...@@ -10,11 +10,17 @@ namespace yii\rbac; ...@@ -10,11 +10,17 @@ namespace yii\rbac;
use yii\base\Object; use yii\base\Object;
/** /**
* Rule * Rule represents a business constraint that may be assigned and the applied to
* @property string $name * an authorization item or assignment.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/ */
abstract class Rule extends Object abstract class Rule extends Object
{ {
/**
* @var string name of the rule
*/
public $name; public $name;
/** /**
......
...@@ -29,10 +29,11 @@ create table "auth_item" ...@@ -29,10 +29,11 @@ create table "auth_item"
"rule_name" varchar(64), "rule_name" varchar(64),
"data" text, "data" text,
primary key ("name"), primary key ("name"),
foreign key ("rule_name") references "auth_rule" ("name") on delete set null on update cascade, foreign key ("rule_name") references "auth_rule" ("name") on delete set null on update cascade
key "type" ("type")
); );
create index "auth_item_type_idx" on "auth_item" ("type");
create table "auth_item_child" create table "auth_item_child"
( (
"parent" varchar(64) not null, "parent" varchar(64) not null,
......
<?php
namespace yiiunit\framework\rbac;
use yii\db\Connection;
use yii\rbac\DbManager;
/**
* DbManagerTestCase
*/
abstract class DbManagerTestCase extends ManagerTestCase
{
protected $database;
protected $driverName = 'mysql';
/**
* @var Connection
*/
protected $db;
protected function setUp()
{
parent::setUp();
$databases = $this->getParam('databases');
$this->database = $databases[$this->driverName];
$pdo_database = 'pdo_'.$this->driverName;
if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) {
$this->markTestSkipped('pdo and '.$pdo_database.' extension are required.');
}
$this->auth = new DbManager(['db' => $this->getConnection()]);
$this->auth->init();
$this->prepareData();
}
protected function tearDown()
{
parent::tearDown();
if ($this->db) {
$this->db->close();
}
$this->destroyApplication();
}
/**
* @param boolean $reset whether to clean up the test database
* @param boolean $open whether to open and populate test database
* @throws \yii\base\InvalidParamException
* @throws \yii\db\Exception
* @throws \yii\base\InvalidConfigException
* @return \yii\db\Connection
*/
public function getConnection($reset = true, $open = true)
{
if (!$reset && $this->db) {
return $this->db;
}
$db = new Connection;
$db->dsn = $this->database['dsn'];
if (isset($this->database['username'])) {
$db->username = $this->database['username'];
$db->password = $this->database['password'];
}
if (isset($this->database['attributes'])) {
$db->attributes = $this->database['attributes'];
}
if ($open) {
$db->open();
$lines = explode(';', file_get_contents(\Yii::getAlias('@yii/rbac/schema-'.$this->driverName.'.sql')));
foreach ($lines as $line) {
if (trim($line) !== '') {
$db->pdo->exec($line);
}
}
}
$this->db = $db;
return $db;
}
}
<?php
namespace yiiunit\framework\rbac;
/**
* MSSQLManagerTest
*/
class MSSQLManagerTest extends DbManagerTestCase
{
protected $driverName = 'mssql';
}
...@@ -98,11 +98,11 @@ abstract class ManagerTestCase extends TestCase ...@@ -98,11 +98,11 @@ abstract class ManagerTestCase extends TestCase
public function testAssign() public function testAssign()
{ {
$auth = $this->auth->assign('new user', 'createPost', 'rule', 'data'); $auth = $this->auth->assign('new user', 'createPost', 'isAuthor', 'data');
$this->assertTrue($auth instanceof Assignment); $this->assertTrue($auth instanceof Assignment);
$this->assertEquals($auth->userId, 'new user'); $this->assertEquals($auth->userId, 'new user');
$this->assertEquals($auth->itemName, 'createPost'); $this->assertEquals($auth->itemName, 'createPost');
$this->assertEquals($auth->ruleName, 'rule'); $this->assertEquals($auth->ruleName, 'isAuthor');
$this->assertEquals($auth->data, 'data'); $this->assertEquals($auth->data, 'data');
$this->setExpectedException('\yii\base\Exception'); $this->setExpectedException('\yii\base\Exception');
......
<?php
namespace yiiunit\framework\rbac;
/**
* MySQLManagerTest
*/
class MySQLManagerTest extends DbManagerTestCase
{
}
<?php
namespace yiiunit\framework\rbac;
/**
* OciManagerTest
*/
class OciManagerTest extends DbManagerTestCase
{
protected $driverName = 'oci';
}
<?php
namespace yiiunit\framework\rbac;
/**
* PgSQLManagerTest
*/
class PgSQLManagerTest extends DbManagerTestCase
{
protected $driverName = 'pgsql';
}
<?php
namespace yiiunit\framework\rbac;
/**
* SqliteManagerTest
*/
class SqliteManagerTest extends DbManagerTestCase
{
protected $driverName = 'sqlite';
}
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