Skip to content

Commit cd5eefc

Browse files
authored
Merge pull request #17 from basakest/FilteredDatabaseAdapter
feat: support Casbin FilteredAdapter interface
2 parents bb56632 + d929f75 commit cd5eefc

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

src/Adapters/DatabaseAdapter.php

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,27 @@
77
use Lauthz\Models\Rule;
88
use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract;
99
use Lauthz\Contracts\BatchDatabaseAdapter as BatchDatabaseAdapterContract;
10-
use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract;
10+
use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract;
11+
use Lauthz\Contracts\FilteredDatabaseAdapter as FilteredDatabaseAdapterContract;
12+
use Casbin\Persist\Adapters\Filter;
1113
use Casbin\Model\Model;
1214
use Casbin\Persist\AdapterHelper;
1315
use DateTime;
16+
use Casbin\Exceptions\InvalidFilterTypeException;
1417
/**
1518
* DatabaseAdapter.
1619
*
1720
1821
*/
19-
class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract
22+
class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract, FilteredDatabaseAdapterContract
2023
{
2124
use AdapterHelper;
2225

26+
/**
27+
* @var bool
28+
*/
29+
private $filtered = false;
30+
2331
/**
2432
* Rules eloquent model.
2533
*
@@ -232,4 +240,57 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $
232240
}
233241
$instance->update($update);
234242
}
243+
244+
/**
245+
* Loads only policy rules that match the filter.
246+
*
247+
* @param Model $model
248+
* @param mixed $filter
249+
*/
250+
public function loadFilteredPolicy(Model $model, $filter): void
251+
{
252+
$instance = $this->eloquent;
253+
254+
if (is_string($filter)) {
255+
$instance = $instance->whereRaw($filter);
256+
} else if ($filter instanceof Filter) {
257+
foreach($filter->p as $k => $v) {
258+
$where[$v] = $filter->g[$k];
259+
$instance = $instance->where($v, $filter->g[$k]);
260+
}
261+
} else if ($filter instanceof \Closure) {
262+
$instance = $instance->where($filter);
263+
} else {
264+
throw new InvalidFilterTypeException('invalid filter type');
265+
}
266+
$rows = $instance->get()->makeHidden(['created_at','updated_at', 'id'])->toArray();
267+
foreach ($rows as $row) {
268+
$row = array_filter($row, function($value) { return !is_null($value) && $value !== ''; });
269+
$line = implode(', ', array_filter($row, function ($val) {
270+
return '' != $val && !is_null($val);
271+
}));
272+
$this->loadPolicyLine(trim($line), $model);
273+
}
274+
$this->setFiltered(true);
275+
}
276+
277+
/**
278+
* Returns true if the loaded policy has been filtered.
279+
*
280+
* @return bool
281+
*/
282+
public function isFiltered(): bool
283+
{
284+
return $this->filtered;
285+
}
286+
287+
/**
288+
* Sets filtered parameter.
289+
*
290+
* @param bool $filtered
291+
*/
292+
public function setFiltered(bool $filtered): void
293+
{
294+
$this->filtered = $filtered;
295+
}
235296
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Lauthz\Contracts;
4+
5+
use Casbin\Persist\FilteredAdapter;
6+
7+
interface FilteredDatabaseAdapter extends FilteredAdapter
8+
{
9+
}

tests/DatabaseAdapterTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use Enforcer;
66
use Illuminate\Foundation\Testing\DatabaseMigrations;
7+
use Casbin\Persist\Adapters\Filter;
8+
use Casbin\Exceptions\InvalidFilterTypeException;
79

810
class DatabaseAdapterTest extends TestCase
911
{
@@ -128,4 +130,48 @@ public function testUpdatePolicy()
128130
['data2_admin', 'data2', 'write'],
129131
], Enforcer::getPolicy());
130132
}
133+
134+
public function testLoadFilteredPolicy()
135+
{
136+
$this->initTable();
137+
Enforcer::clearPolicy();
138+
$this->initConfig();
139+
$adapter = Enforcer::getAdapter();
140+
$adapter->setFiltered(true);
141+
$this->assertEquals([], Enforcer::getPolicy());
142+
143+
// invalid filter type
144+
try {
145+
$filter = ['alice', 'data1', 'read'];
146+
Enforcer::loadFilteredPolicy($filter);
147+
$e = InvalidFilterTypeException::class;
148+
$this->fail("Expected exception $e not thrown");
149+
} catch (InvalidFilterTypeException $e) {
150+
$this->assertEquals("invalid filter type", $e->getMessage());
151+
}
152+
153+
// string
154+
$filter = "v0 = 'bob'";
155+
Enforcer::loadFilteredPolicy($filter);
156+
$this->assertEquals([
157+
['bob', 'data2', 'write']
158+
], Enforcer::getPolicy());
159+
160+
// Filter
161+
$filter = new Filter(['v2'], ['read']);
162+
Enforcer::loadFilteredPolicy($filter);
163+
$this->assertEquals([
164+
['alice', 'data1', 'read'],
165+
['data2_admin', 'data2', 'read'],
166+
], Enforcer::getPolicy());
167+
168+
// Closure
169+
Enforcer::loadFilteredPolicy(function ($query) {
170+
$query->where('v1', 'data1');
171+
});
172+
173+
$this->assertEquals([
174+
['alice', 'data1', 'read'],
175+
], Enforcer::getPolicy());
176+
}
131177
}

0 commit comments

Comments
 (0)