Skip to content

Commit c178a5d

Browse files
authored
Merge pull request #6 from basakest/filtered-adapter
feat: support Casbin FilteredAdapter interface
2 parents 5b02e5c + b86cad9 commit c178a5d

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

src/Adapter.php

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
use Casbin\Persist\Adapter as AdapterContract;
77
use Casbin\Persist\BatchAdapter as BatchAdapterContract;
88
use Casbin\Persist\UpdatableAdapter as UpdatableAdapterContract;
9+
use Casbin\Persist\FilteredAdapter as FilteredAdapterContract;
10+
use Casbin\Model\Model;
11+
use Casbin\Persist\Adapters\Filter;
12+
use Casbin\Exceptions\InvalidFilterTypeException;
913
use Casbin\Persist\AdapterHelper;
1014
use Cake\ORM\TableRegistry;
1115
use CasbinAdapter\Cake\Model\Table\CasbinRuleTable;
@@ -15,12 +19,17 @@
1519
*
1620
1721
*/
18-
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract
22+
class Adapter implements AdapterContract, BatchAdapterContract, UpdatableAdapterContract, FilteredAdapterContract
1923
{
2024
use AdapterHelper;
2125

2226
protected $table;
2327

28+
/**
29+
* @var bool
30+
*/
31+
private $filtered = false;
32+
2433
public function __construct()
2534
{
2635
$this->table = $this->getTable();
@@ -159,6 +168,64 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $
159168
$this->table->save($first);
160169
}
161170

171+
/**
172+
* Loads only policy rules that match the filter.
173+
*
174+
* @param Model $model
175+
* @param mixed $filter
176+
*/
177+
public function loadFilteredPolicy(Model $model, $filter): void
178+
{
179+
$entity = $this->table->find();
180+
181+
if (is_string($filter)) {
182+
$entity = $entity->epilog('WHERE ' . $filter);
183+
} elseif ($filter instanceof Filter) {
184+
foreach ($filter->p as $k => $v) {
185+
$where[$v] = $filter->g[$k];
186+
$entity = $entity->where([$v => $filter->g[$k]]);
187+
}
188+
} elseif ($filter instanceof \Closure) {
189+
$entity = $entity->where($filter);
190+
} else {
191+
throw new InvalidFilterTypeException('invalid filter type');
192+
}
193+
$rows = $entity->all();
194+
195+
foreach ($rows as $row) {
196+
unset($row->id);
197+
$row = $row->toArray();
198+
$row = array_filter($row, function ($value) {
199+
return !is_null($value) && $value !== '';
200+
});
201+
$line = implode(', ', array_filter($row, function ($val) {
202+
return '' != $val && !is_null($val);
203+
}));
204+
$this->loadPolicyLine(trim($line), $model);
205+
}
206+
$this->setFiltered(true);
207+
}
208+
209+
/**
210+
* Returns true if the loaded policy has been filtered.
211+
*
212+
* @return bool
213+
*/
214+
public function isFiltered(): bool
215+
{
216+
return $this->filtered;
217+
}
218+
219+
/**
220+
* Sets filtered parameter.
221+
*
222+
* @param bool $filtered
223+
*/
224+
public function setFiltered(bool $filtered): void
225+
{
226+
$this->filtered = $filtered;
227+
}
228+
162229
protected function getTable()
163230
{
164231
return TableRegistry::getTableLocator()->get('CasbinRule', [

tests/DatabaseAdapterTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use CasbinAdapter\Cake\Casbin;
1010
use Cake\Filesystem\File;
1111
use Cake\Filesystem\Folder;
12+
use Casbin\Persist\Adapters\Filter;
13+
use Casbin\Exceptions\InvalidFilterTypeException;
1214

1315
class DatabaseAdapterTest extends TestCase
1416
{
@@ -161,4 +163,47 @@ public function testUpdatePolicy()
161163
['data2_admin', 'data2', 'write'],
162164
], $e->getPolicy());
163165
}
166+
167+
public function testLoadFilteredPolicy()
168+
{
169+
$e = $this->getEnforcer();
170+
$e->clearPolicy();
171+
$adapter = $e->getAdapter();
172+
$adapter->setFiltered(true);
173+
$this->assertEquals([], $e->getPolicy());
174+
175+
// invalid filter type
176+
try {
177+
$filter = ['alice', 'data1', 'read'];
178+
$e->loadFilteredPolicy($filter);
179+
$exception = InvalidFilterTypeException::class;
180+
$this->fail("Expected exception $exception not thrown");
181+
} catch (InvalidFilterTypeException $exception) {
182+
$this->assertEquals("invalid filter type", $exception->getMessage());
183+
}
184+
185+
// string
186+
$filter = "v0 = 'bob'";
187+
$e->loadFilteredPolicy($filter);
188+
$this->assertEquals([
189+
['bob', 'data2', 'write']
190+
], $e->getPolicy());
191+
192+
// Filter
193+
$filter = new Filter(['v2'], ['read']);
194+
$e->loadFilteredPolicy($filter);
195+
$this->assertEquals([
196+
['alice', 'data1', 'read'],
197+
['data2_admin', 'data2', 'read'],
198+
], $e->getPolicy());
199+
200+
// Closure
201+
$e->loadFilteredPolicy(function ($query) {
202+
return $query->and(['v1' => 'data1']);
203+
});
204+
205+
$this->assertEquals([
206+
['alice', 'data1', 'read'],
207+
], $e->getPolicy());
208+
}
164209
}

0 commit comments

Comments
 (0)