Skip to content

Commit

Permalink
feat: support Casbin FilteredAdapter interface
Browse files Browse the repository at this point in the history
  • Loading branch information
basakest committed Jul 27, 2021
1 parent c40bdba commit f6ad78a
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 1 deletion.
81 changes: 80 additions & 1 deletion src/Adapter.php
Expand Up @@ -5,16 +5,20 @@
use Casbin\Persist\Adapter as AdapterContract;
use Casbin\Persist\BatchAdapter as BatchAdapterContract;
use Casbin\Persist\UpdatableAdapter as UpdatableAdapterContract;
use Casbin\Persist\FilteredAdapter as FilteredAdapterContract;
use Casbin\Persist\AdapterHelper;
use Casbin\Model\Model;
use Medoo\Medoo;
use Casbin\Exceptions\CasbinException;
use Casbin\Persist\Adapters\Filter;
use Casbin\Exceptions\InvalidFilterTypeException;

/**
* Medoo Adapter.
*
* @author techlee@qq.com
*/
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract, FilteredAdapterContract
{
use AdapterHelper;

Expand All @@ -32,6 +36,11 @@ class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapter
*/
public $casbinRuleTableName = 'casbin_rule';

/**
* @var bool
*/
private $filtered = false;

/**
* Adapter constructor.
*
Expand All @@ -57,6 +66,26 @@ public static function newAdapter(array $config)
return new static($config);
}

/**
* Returns true if the loaded policy has been filtered.
*
* @return bool
*/
public function isFiltered(): bool
{
return $this->filtered;
}

/**
* Sets filtered parameter.
*
* @param bool $filtered
*/
public function setFiltered(bool $filtered): void
{
$this->filtered = $filtered;
}

/**
* Initialize the policy rules table, create if it does not exist.
*
Expand Down Expand Up @@ -259,6 +288,56 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $
$this->database->replace($this->casbinRuleTableName, $columns, $where);
}

/**
* UpdatePolicies updates some policy rules to storage, like db, redis.
*
* @param string $sec
* @param string $ptype
* @param string[][] $oldRules
* @param string[][] $newRules
* @return void
*/
public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void
{
throw new CasbinException('not implemented');
}

/**
* Loads only policy rules that match the filter.
*
* @param Model $model
* @param mixed $filter
*/
public function loadFilteredPolicy(Model $model, $filter): void
{
$columns = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
if (is_string($filter)) {
$where = Medoo::raw('WHERE ' . $filter);
$rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
} elseif ($filter instanceof Filter) {
foreach ($filter->p as $k => $v) {
$where[$v] = $filter->g[$k];
}
$rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
} elseif ($filter instanceof \Closure) {
$rows = [];
$filter($this->database, $this->casbinRuleTableName, $columns, $rows);
} else {
throw new InvalidFilterTypeException('invalid filter type');
}

foreach ($rows as $row) {
$row = array_filter($row, function ($value) {
return !is_null($value) && $value !== '';
});
$line = implode(', ', array_filter($row, function ($val) {
return '' != $val && !is_null($val);
}));
$this->loadPolicyLine(trim($line), $model);
}
$this->setFiltered(true);
}

/**
* Gets database.
*
Expand Down
46 changes: 46 additions & 0 deletions tests/AdapterTest.php
Expand Up @@ -6,6 +6,8 @@
use Casbin\Model\Model;
use CasbinAdapter\Medoo\Adapter as DatabaseAdapter;
use PHPUnit\Framework\TestCase;
use Casbin\Persist\Adapters\Filter;
use Casbin\Exceptions\InvalidFilterTypeException;

class AdapterTest extends TestCase
{
Expand Down Expand Up @@ -198,6 +200,50 @@ public function testUpdatePolicy()
], $e->getPolicy());
}

public function testLoadFilteredPolicy()
{
$e = $this->getEnforcer();
$e->clearPolicy();
$adapter = $e->getAdapter();
$adapter->setFiltered(true);
$this->assertEquals([], $e->getPolicy());

// invalid filter type
try {
$filter = ['alice', 'data1', 'read'];
$e->loadFilteredPolicy($filter);
$exception = InvalidFilterTypeException::class;
$this->fail("Expected exception $exception not thrown");
} catch (InvalidFilterTypeException $exception) {
$this->assertEquals("invalid filter type", $exception->getMessage());
}

// string
$filter = "v0 = 'bob'";
$e->loadFilteredPolicy($filter);
$this->assertEquals([
['bob', 'data2', 'write']
], $e->getPolicy());

// Filter
$filter = new Filter(['v2'], ['read']);
$e->loadFilteredPolicy($filter);
$this->assertEquals([
['alice', 'data1', 'read'],
['data2_admin', 'data2', 'read'],
], $e->getPolicy());

// Closure
$e->loadFilteredPolicy(function (\Medoo\Medoo $database, string $casbinRuleTableName, array $columns, array &$rows) {
$where = \Medoo\Medoo::raw('WHERE ' . "v1 = 'data1'");
$rows = $database->select($casbinRuleTableName, $columns, $where);
});

$this->assertEquals([
['alice', 'data1', 'read'],
], $e->getPolicy());
}

protected function env($key, $default = null)
{
$value = getenv($key);
Expand Down

0 comments on commit f6ad78a

Please sign in to comment.