Skip to content

Commit

Permalink
feat: support Casbin FilteredAdapter interface (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
basakest authored Aug 13, 2021
1 parent b159ac4 commit b95ae29
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
65 changes: 64 additions & 1 deletion src/adapter/DatabaseAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@
use Casbin\Persist\AdapterHelper;
use Casbin\Persist\UpdatableAdapter;
use Casbin\Persist\BatchAdapter;
use Casbin\Persist\FilteredAdapter;
use Casbin\Persist\Adapters\Filter;
use Casbin\Exceptions\InvalidFilterTypeException;
use think\facade\Db;

/**
* DatabaseAdapter.
*
* @author techlee@qq.com
*/
class DatabaseAdapter implements Adapter, UpdatableAdapter, BatchAdapter
class DatabaseAdapter implements Adapter, UpdatableAdapter, BatchAdapter, FilteredAdapter
{
use AdapterHelper;

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

/**
* Rules model.
*
Expand Down Expand Up @@ -238,4 +246,59 @@ public function updatePolicies(string $sec, string $ptype, array $oldRules, arra
}
});
}

/**
* 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;
}

/**
* Loads only policy rules that match the filter.
*
* @param Model $model
* @param mixed $filter
*/
public function loadFilteredPolicy(Model $model, $filter): void
{
$instance = $this->model;

if (is_string($filter)) {
$instance = $instance->whereRaw($filter);
} elseif ($filter instanceof Filter) {
foreach ($filter->p as $k => $v) {
$where[$v] = $filter->g[$k];
$instance = $instance->where($v, $filter->g[$k]);
}
} elseif ($filter instanceof \Closure) {
$instance = $instance->where($filter);
} else {
throw new InvalidFilterTypeException('invalid filter type');
}
$rows = $instance->select()->hidden(['id'])->toArray();
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);
}
}
47 changes: 47 additions & 0 deletions tests/DatabaseAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace tauthz\tests;

use tauthz\facade\Enforcer;
use Casbin\Persist\Adapters\Filter;
use Casbin\Exceptions\InvalidFilterTypeException;

class DatabaseAdapterTest extends TestCase
{
Expand Down Expand Up @@ -173,4 +175,49 @@ public function testUpdatePolicies()
], Enforcer::getPolicy());
});
}

public function testLoadFilteredPolicy()
{
$this->testing(function () {
$this->initTable();
Enforcer::clearPolicy();
$adapter = Enforcer::getAdapter();
$adapter->setFiltered(true);
$this->assertEquals([], Enforcer::getPolicy());

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

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

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

// Closure
Enforcer::loadFilteredPolicy(function ($query) {
$query->where('v1', 'data1');
});

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

0 comments on commit b95ae29

Please sign in to comment.