Skip to content

Commit 3bee8c4

Browse files
authored
Merge pull request #5 from basakest/filtered-adapter
feat: support Casbin FilteredAdapter interface
2 parents c40bdba + f6ad78a commit 3bee8c4

File tree

2 files changed

+126
-1
lines changed

2 files changed

+126
-1
lines changed

src/Adapter.php

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@
55
use Casbin\Persist\Adapter as AdapterContract;
66
use Casbin\Persist\BatchAdapter as BatchAdapterContract;
77
use Casbin\Persist\UpdatableAdapter as UpdatableAdapterContract;
8+
use Casbin\Persist\FilteredAdapter as FilteredAdapterContract;
89
use Casbin\Persist\AdapterHelper;
910
use Casbin\Model\Model;
1011
use Medoo\Medoo;
12+
use Casbin\Exceptions\CasbinException;
13+
use Casbin\Persist\Adapters\Filter;
14+
use Casbin\Exceptions\InvalidFilterTypeException;
1115

1216
/**
1317
* Medoo Adapter.
1418
*
1519
1620
*/
17-
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract
21+
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract, FilteredAdapterContract
1822
{
1923
use AdapterHelper;
2024

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

39+
/**
40+
* @var bool
41+
*/
42+
private $filtered = false;
43+
3544
/**
3645
* Adapter constructor.
3746
*
@@ -57,6 +66,26 @@ public static function newAdapter(array $config)
5766
return new static($config);
5867
}
5968

69+
/**
70+
* Returns true if the loaded policy has been filtered.
71+
*
72+
* @return bool
73+
*/
74+
public function isFiltered(): bool
75+
{
76+
return $this->filtered;
77+
}
78+
79+
/**
80+
* Sets filtered parameter.
81+
*
82+
* @param bool $filtered
83+
*/
84+
public function setFiltered(bool $filtered): void
85+
{
86+
$this->filtered = $filtered;
87+
}
88+
6089
/**
6190
* Initialize the policy rules table, create if it does not exist.
6291
*
@@ -259,6 +288,56 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $
259288
$this->database->replace($this->casbinRuleTableName, $columns, $where);
260289
}
261290

291+
/**
292+
* UpdatePolicies updates some policy rules to storage, like db, redis.
293+
*
294+
* @param string $sec
295+
* @param string $ptype
296+
* @param string[][] $oldRules
297+
* @param string[][] $newRules
298+
* @return void
299+
*/
300+
public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void
301+
{
302+
throw new CasbinException('not implemented');
303+
}
304+
305+
/**
306+
* Loads only policy rules that match the filter.
307+
*
308+
* @param Model $model
309+
* @param mixed $filter
310+
*/
311+
public function loadFilteredPolicy(Model $model, $filter): void
312+
{
313+
$columns = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
314+
if (is_string($filter)) {
315+
$where = Medoo::raw('WHERE ' . $filter);
316+
$rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
317+
} elseif ($filter instanceof Filter) {
318+
foreach ($filter->p as $k => $v) {
319+
$where[$v] = $filter->g[$k];
320+
}
321+
$rows = $this->database->select($this->casbinRuleTableName, $columns, $where);
322+
} elseif ($filter instanceof \Closure) {
323+
$rows = [];
324+
$filter($this->database, $this->casbinRuleTableName, $columns, $rows);
325+
} else {
326+
throw new InvalidFilterTypeException('invalid filter type');
327+
}
328+
329+
foreach ($rows as $row) {
330+
$row = array_filter($row, function ($value) {
331+
return !is_null($value) && $value !== '';
332+
});
333+
$line = implode(', ', array_filter($row, function ($val) {
334+
return '' != $val && !is_null($val);
335+
}));
336+
$this->loadPolicyLine(trim($line), $model);
337+
}
338+
$this->setFiltered(true);
339+
}
340+
262341
/**
263342
* Gets database.
264343
*

tests/AdapterTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
use Casbin\Model\Model;
77
use CasbinAdapter\Medoo\Adapter as DatabaseAdapter;
88
use PHPUnit\Framework\TestCase;
9+
use Casbin\Persist\Adapters\Filter;
10+
use Casbin\Exceptions\InvalidFilterTypeException;
911

1012
class AdapterTest extends TestCase
1113
{
@@ -198,6 +200,50 @@ public function testUpdatePolicy()
198200
], $e->getPolicy());
199201
}
200202

203+
public function testLoadFilteredPolicy()
204+
{
205+
$e = $this->getEnforcer();
206+
$e->clearPolicy();
207+
$adapter = $e->getAdapter();
208+
$adapter->setFiltered(true);
209+
$this->assertEquals([], $e->getPolicy());
210+
211+
// invalid filter type
212+
try {
213+
$filter = ['alice', 'data1', 'read'];
214+
$e->loadFilteredPolicy($filter);
215+
$exception = InvalidFilterTypeException::class;
216+
$this->fail("Expected exception $exception not thrown");
217+
} catch (InvalidFilterTypeException $exception) {
218+
$this->assertEquals("invalid filter type", $exception->getMessage());
219+
}
220+
221+
// string
222+
$filter = "v0 = 'bob'";
223+
$e->loadFilteredPolicy($filter);
224+
$this->assertEquals([
225+
['bob', 'data2', 'write']
226+
], $e->getPolicy());
227+
228+
// Filter
229+
$filter = new Filter(['v2'], ['read']);
230+
$e->loadFilteredPolicy($filter);
231+
$this->assertEquals([
232+
['alice', 'data1', 'read'],
233+
['data2_admin', 'data2', 'read'],
234+
], $e->getPolicy());
235+
236+
// Closure
237+
$e->loadFilteredPolicy(function (\Medoo\Medoo $database, string $casbinRuleTableName, array $columns, array &$rows) {
238+
$where = \Medoo\Medoo::raw('WHERE ' . "v1 = 'data1'");
239+
$rows = $database->select($casbinRuleTableName, $columns, $where);
240+
});
241+
242+
$this->assertEquals([
243+
['alice', 'data1', 'read'],
244+
], $e->getPolicy());
245+
}
246+
201247
protected function env($key, $default = null)
202248
{
203249
$value = getenv($key);

0 commit comments

Comments
 (0)