Skip to content

Commit b95ae29

Browse files
authored
feat: support Casbin FilteredAdapter interface (#27)
1 parent b159ac4 commit b95ae29

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

src/adapter/DatabaseAdapter.php

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,25 @@
88
use Casbin\Persist\AdapterHelper;
99
use Casbin\Persist\UpdatableAdapter;
1010
use Casbin\Persist\BatchAdapter;
11+
use Casbin\Persist\FilteredAdapter;
12+
use Casbin\Persist\Adapters\Filter;
13+
use Casbin\Exceptions\InvalidFilterTypeException;
1114
use think\facade\Db;
1215

1316
/**
1417
* DatabaseAdapter.
1518
*
1619
1720
*/
18-
class DatabaseAdapter implements Adapter, UpdatableAdapter, BatchAdapter
21+
class DatabaseAdapter implements Adapter, UpdatableAdapter, BatchAdapter, FilteredAdapter
1922
{
2023
use AdapterHelper;
2124

25+
/**
26+
* @var bool
27+
*/
28+
private $filtered = false;
29+
2230
/**
2331
* Rules model.
2432
*
@@ -238,4 +246,59 @@ public function updatePolicies(string $sec, string $ptype, array $oldRules, arra
238246
}
239247
});
240248
}
249+
250+
/**
251+
* Returns true if the loaded policy has been filtered.
252+
*
253+
* @return bool
254+
*/
255+
public function isFiltered(): bool
256+
{
257+
return $this->filtered;
258+
}
259+
260+
/**
261+
* Sets filtered parameter.
262+
*
263+
* @param bool $filtered
264+
*/
265+
public function setFiltered(bool $filtered): void
266+
{
267+
$this->filtered = $filtered;
268+
}
269+
270+
/**
271+
* Loads only policy rules that match the filter.
272+
*
273+
* @param Model $model
274+
* @param mixed $filter
275+
*/
276+
public function loadFilteredPolicy(Model $model, $filter): void
277+
{
278+
$instance = $this->model;
279+
280+
if (is_string($filter)) {
281+
$instance = $instance->whereRaw($filter);
282+
} elseif ($filter instanceof Filter) {
283+
foreach ($filter->p as $k => $v) {
284+
$where[$v] = $filter->g[$k];
285+
$instance = $instance->where($v, $filter->g[$k]);
286+
}
287+
} elseif ($filter instanceof \Closure) {
288+
$instance = $instance->where($filter);
289+
} else {
290+
throw new InvalidFilterTypeException('invalid filter type');
291+
}
292+
$rows = $instance->select()->hidden(['id'])->toArray();
293+
foreach ($rows as $row) {
294+
$row = array_filter($row, function ($value) {
295+
return !is_null($value) && $value !== '';
296+
});
297+
$line = implode(', ', array_filter($row, function ($val) {
298+
return '' != $val && !is_null($val);
299+
}));
300+
$this->loadPolicyLine(trim($line), $model);
301+
}
302+
$this->setFiltered(true);
303+
}
241304
}

tests/DatabaseAdapterTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace tauthz\tests;
44

55
use tauthz\facade\Enforcer;
6+
use Casbin\Persist\Adapters\Filter;
7+
use Casbin\Exceptions\InvalidFilterTypeException;
68

79
class DatabaseAdapterTest extends TestCase
810
{
@@ -173,4 +175,49 @@ public function testUpdatePolicies()
173175
], Enforcer::getPolicy());
174176
});
175177
}
178+
179+
public function testLoadFilteredPolicy()
180+
{
181+
$this->testing(function () {
182+
$this->initTable();
183+
Enforcer::clearPolicy();
184+
$adapter = Enforcer::getAdapter();
185+
$adapter->setFiltered(true);
186+
$this->assertEquals([], Enforcer::getPolicy());
187+
188+
// invalid filter type
189+
try {
190+
$filter = ['alice', 'data1', 'read'];
191+
Enforcer::loadFilteredPolicy($filter);
192+
$e = InvalidFilterTypeException::class;
193+
$this->fail("Expected exception $e not thrown");
194+
} catch (InvalidFilterTypeException $e) {
195+
$this->assertEquals("invalid filter type", $e->getMessage());
196+
}
197+
198+
// string
199+
$filter = "v0 = 'bob'";
200+
Enforcer::loadFilteredPolicy($filter);
201+
$this->assertEquals([
202+
['bob', 'data2', 'write']
203+
], Enforcer::getPolicy());
204+
205+
// Filter
206+
$filter = new Filter(['v2'], ['read']);
207+
Enforcer::loadFilteredPolicy($filter);
208+
$this->assertEquals([
209+
['alice', 'data1', 'read'],
210+
['data2_admin', 'data2', 'read'],
211+
], Enforcer::getPolicy());
212+
213+
// Closure
214+
Enforcer::loadFilteredPolicy(function ($query) {
215+
$query->where('v1', 'data1');
216+
});
217+
218+
$this->assertEquals([
219+
['alice', 'data1', 'read'],
220+
], Enforcer::getPolicy());
221+
});
222+
}
176223
}

0 commit comments

Comments
 (0)