Skip to content

Commit ccf4e46

Browse files
committed
feat: support Casbin FilteredAdapter interface
1 parent 8da7014 commit ccf4e46

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

src/Adapter.php

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,31 @@
44

55
use Casbin\Persist\Adapter as AdapterContract;
66
use Casbin\Persist\BatchAdapter as BatchAdapterContract;
7+
use Casbin\Persist\FilteredAdapter as FilteredAdapterContract;
78
use Casbin\Persist\AdapterHelper;
89
use Laminas\Db\Adapter\AdapterInterface as LaminasDbAdapterInterface;
910
use Laminas\Db\Adapter\Adapter as LaminasDbAdapter;
1011
use Laminas\Db\TableGateway\TableGateway;
1112
use Laminas\Db\TableGateway\TableGatewayInterface;
1213
use Laminas\Db\Sql\Select;
1314
use Casbin\Model\Model;
15+
use Casbin\Persist\Adapters\Filter;
16+
use Casbin\Exceptions\InvalidFilterTypeException;
1417

1518
/**
1619
* Laminas DB Adapter for Casbin.
1720
*
1821
1922
*/
20-
class Adapter implements AdapterContract, BatchAdapterContract
23+
class Adapter implements AdapterContract, BatchAdapterContract, FilteredAdapterContract
2124
{
2225
use AdapterHelper;
2326

27+
/**
28+
* @var bool
29+
*/
30+
private $filtered = false;
31+
2432
/**
2533
* @var TableGatewayInterface
2634
*/
@@ -235,4 +243,57 @@ public function removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues)
235243

236244
$this->tableGateway->delete($where);
237245
}
246+
247+
/**
248+
* Loads only policy rules that match the filter.
249+
*
250+
* @param Model $model
251+
* @param mixed $filter
252+
*/
253+
public function loadFilteredPolicy(Model $model, $filter): void
254+
{
255+
if (is_string($filter)) {
256+
$where = $filter;
257+
} elseif ($filter instanceof Filter) {
258+
foreach ($filter->p as $k => $v) {
259+
$where[$v] = $filter->g[$k];
260+
}
261+
} elseif ($filter instanceof \Closure) {
262+
$where = $filter;
263+
} else {
264+
throw new InvalidFilterTypeException('invalid filter type');
265+
}
266+
$rows = $this->tableGateway->select($where)->toArray();
267+
268+
foreach ($rows as $row) {
269+
$row = array_filter($row, function ($value) {
270+
return !is_null($value) && $value !== '';
271+
});
272+
$line = implode(', ', array_filter($row, function ($val) {
273+
return '' != $val && !is_null($val);
274+
}));
275+
$this->loadPolicyLine(trim($line), $model);
276+
}
277+
$this->setFiltered(true);
278+
}
279+
280+
/**
281+
* Returns true if the loaded policy has been filtered.
282+
*
283+
* @return bool
284+
*/
285+
public function isFiltered(): bool
286+
{
287+
return $this->filtered;
288+
}
289+
290+
/**
291+
* Sets filtered parameter.
292+
*
293+
* @param bool $filtered
294+
*/
295+
public function setFiltered(bool $filtered): void
296+
{
297+
$this->filtered = $filtered;
298+
}
238299
}

tests/AdapterTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
use Laminas\Db\Sql\Ddl\CreateTable;
1212
use Laminas\Db\Sql\Ddl\Column\Varchar;
1313
use Laminas\Db\Sql\Sql;
14+
use Casbin\Persist\Adapters\Filter;
15+
use Casbin\Exceptions\InvalidFilterTypeException;
16+
use Laminas\Db\Sql\Select;
1417

1518
class AdapterTest extends TestCase
1619
{
@@ -217,6 +220,49 @@ public function testRemoveFilteredPolicy()
217220
$this->assertFalse($e->enforce('alice', 'data2', 'write'));
218221
}
219222

223+
public function testLoadFilteredPolicy()
224+
{
225+
$e = $this->getEnforcer();
226+
$e->clearPolicy();
227+
$adapter = $e->getAdapter();
228+
$adapter->setFiltered(true);
229+
$this->assertEquals([], $e->getPolicy());
230+
231+
// invalid filter type
232+
try {
233+
$filter = ['alice', 'data1', 'read'];
234+
$e->loadFilteredPolicy($filter);
235+
$exception = InvalidFilterTypeException::class;
236+
$this->fail("Expected exception $exception not thrown");
237+
} catch (InvalidFilterTypeException $exception) {
238+
$this->assertEquals("invalid filter type", $exception->getMessage());
239+
}
240+
241+
// string
242+
$filter = "v0 = 'bob'";
243+
$e->loadFilteredPolicy($filter);
244+
$this->assertEquals([
245+
['bob', 'data2', 'write']
246+
], $e->getPolicy());
247+
248+
// Filter
249+
$filter = new Filter(['v2'], ['read']);
250+
$e->loadFilteredPolicy($filter);
251+
$this->assertEquals([
252+
['alice', 'data1', 'read'],
253+
['data2_admin', 'data2', 'read'],
254+
], $e->getPolicy());
255+
256+
// Closure
257+
$e->loadFilteredPolicy(function (Select $select) {
258+
return $select->where(['v1' => 'data1']);
259+
});
260+
261+
$this->assertEquals([
262+
['alice', 'data1', 'read'],
263+
], $e->getPolicy());
264+
}
265+
220266
protected function env($key, $default = null)
221267
{
222268
$value = getenv($key);

0 commit comments

Comments
 (0)