Commit 2c28198c by Alexander Makarov

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

parent 0e6cbda4
......@@ -79,6 +79,7 @@ Yii Framework 2 Change Log
- 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 #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 #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)
......
......@@ -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
* the unique identifier of a user. See [[\yii\web\User::id]].
* @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,
* which holds the value of `$userId`.
* @return boolean whether the operations can be performed by the user.
......@@ -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
* the unique identifier of a user. See [[\yii\web\User::id]].
* @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,
* which holds the value of `$userId`.
* @param Assignment[] $assignments the assignments to the specified user
......@@ -116,7 +116,7 @@ class DbManager extends Manager
}
if (isset($assignments[$itemName])) {
$assignment = $assignments[$itemName];
if ($this->executeRule($assignment->bizRule, $params, $assignment->data)) {
if ($this->executeRule($assignment->ruleName, $params, $assignment->data)) {
return true;
}
}
......@@ -216,7 +216,7 @@ class DbManager extends Manager
public function getItemChildren($names)
{
$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])
->where(['parent' => $names, 'name' => new Expression('child')])
->createCommand($this->db)
......@@ -231,7 +231,7 @@ class DbManager extends Manager
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'ruleName' => $row['rule_name'],
'data' => $data,
]);
}
......@@ -259,7 +259,7 @@ class DbManager extends Manager
->insert($this->assignmentTable, [
'user_id' => $userId,
'item_name' => $itemName,
'biz_rule' => $ruleName,
'rule_name' => $ruleName,
'data' => $data === null ? null : serialize($data),
])
->execute();
......@@ -268,7 +268,7 @@ class DbManager extends Manager
'manager' => $this,
'userId' => $userId,
'itemName' => $itemName,
'bizRule' => $ruleName,
'ruleName' => $ruleName,
'data' => $data,
]);
}
......@@ -338,7 +338,7 @@ class DbManager extends Manager
'manager' => $this,
'userId' => $row['user_id'],
'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'],
'ruleName' => $row['rule_name'],
'data' => $data,
]);
} else {
......@@ -368,7 +368,7 @@ class DbManager extends Manager
'manager' => $this,
'userId' => $row['user_id'],
'itemName' => $row['item_name'],
'bizRule' => $row['biz_rule'],
'ruleName' => $row['rule_name'],
'data' => $data,
]);
}
......@@ -384,7 +384,7 @@ class DbManager extends Manager
{
$this->db->createCommand()
->update($this->assignmentTable, [
'biz_rule' => $assignment->bizRule,
'rule_name' => $assignment->ruleName,
'data' => $assignment->data === null ? null : serialize($assignment->data),
], [
'user_id' => $assignment->userId,
......@@ -412,12 +412,12 @@ class DbManager extends Manager
->where(['type' => $type])
->createCommand($this->db);
} 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'])
->where(['user_id' => $userId, 'name' => new Expression('item_name')])
->createCommand($this->db);
} 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'])
->where(['user_id' => $userId, 'type' => $type, 'name' => new Expression('item_name')])
->createCommand($this->db);
......@@ -432,7 +432,7 @@ class DbManager extends Manager
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'ruleName' => $row['rule_name'],
'data' => $data,
]);
}
......@@ -463,7 +463,7 @@ class DbManager extends Manager
'name' => $name,
'type' => $type,
'description' => $description,
'biz_rule' => $rule,
'rule_name' => $rule,
'data' => $data === null ? null : serialize($data),
])
->execute();
......@@ -473,7 +473,7 @@ class DbManager extends Manager
'name' => $name,
'type' => $type,
'description' => $description,
'bizRule' => $rule,
'ruleName' => $rule,
'data' => $data,
]);
}
......@@ -522,7 +522,7 @@ class DbManager extends Manager
'name' => $row['name'],
'type' => $row['type'],
'description' => $row['description'],
'bizRule' => $row['biz_rule'],
'ruleName' => $row['rule_name'],
'data' => $data,
]);
} else {
......@@ -623,7 +623,7 @@ class DbManager extends Manager
*/
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
*/
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
*/
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
*/
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;
use yii\base\Object;
/**
* Rule
* @property string $name
* Rule represents a business constraint that may be assigned and the applied to
* an authorization item or assignment.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
abstract class Rule extends Object
{
/**
* @var string name of the rule
*/
public $name;
/**
......
......@@ -29,10 +29,11 @@ create table "auth_item"
"rule_name" varchar(64),
"data" text,
primary key ("name"),
foreign key ("rule_name") references "auth_rule" ("name") on delete set null on update cascade,
key "type" ("type")
foreign key ("rule_name") references "auth_rule" ("name") on delete set null on update cascade
);
create index "auth_item_type_idx" on "auth_item" ("type");
create table "auth_item_child"
(
"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
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->assertEquals($auth->userId, 'new user');
$this->assertEquals($auth->itemName, 'createPost');
$this->assertEquals($auth->ruleName, 'rule');
$this->assertEquals($auth->ruleName, 'isAuthor');
$this->assertEquals($auth->data, 'data');
$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