From fdadd55ecd4c1da24d94ff4f66d403da777bf1ab Mon Sep 17 00:00:00 2001 From: Jon Lee Date: Thu, 9 Sep 2021 09:56:48 +0800 Subject: [PATCH 1/4] fix: ignore .phpunit.* --- .gitignore | 4 +++- .phpunit.result.cache | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 .phpunit.result.cache diff --git a/.gitignore b/.gitignore index 1093993..54fd7d0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ composer.lock *.iml # coverage report -/build \ No newline at end of file +/build + +.phpunit.* \ No newline at end of file diff --git a/.phpunit.result.cache b/.phpunit.result.cache deleted file mode 100644 index 849c158..0000000 --- a/.phpunit.result.cache +++ /dev/null @@ -1 +0,0 @@ -C:37:"PHPUnit\Runner\DefaultTestResultCache":1324:{a:2:{s:7:"defects";a:10:{s:52:"CasbinAdapter\DBAL\Tests\AdapterTest::testLoadPolicy";i:4;s:51:"CasbinAdapter\DBAL\Tests\AdapterTest::testAddPolicy";i:4;s:52:"CasbinAdapter\DBAL\Tests\AdapterTest::testSavePolicy";i:4;s:54:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemovePolicy";i:4;s:62:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemoveFilteredPolicy";i:4;s:53:"CasbinAdapter\DBAL\Tests\AdapterTest::testAddPolicies";i:4;s:7:"Warning";i:6;s:56:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemovePolicies";i:4;s:54:"CasbinAdapter\DBAL\Tests\AdapterTest::testUpdatePolicy";i:4;s:60:"CasbinAdapter\DBAL\Tests\AdapterTest::testLoadFilteredPolicy";i:4;}s:5:"times";a:10:{s:52:"CasbinAdapter\DBAL\Tests\AdapterTest::testLoadPolicy";d:1.072;s:51:"CasbinAdapter\DBAL\Tests\AdapterTest::testAddPolicy";d:0.211;s:52:"CasbinAdapter\DBAL\Tests\AdapterTest::testSavePolicy";d:0.215;s:54:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemovePolicy";d:0.219;s:62:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemoveFilteredPolicy";d:0.3;s:53:"CasbinAdapter\DBAL\Tests\AdapterTest::testAddPolicies";d:0.391;s:7:"Warning";d:0.007;s:56:"CasbinAdapter\DBAL\Tests\AdapterTest::testRemovePolicies";d:0.205;s:54:"CasbinAdapter\DBAL\Tests\AdapterTest::testUpdatePolicy";d:0.241;s:60:"CasbinAdapter\DBAL\Tests\AdapterTest::testLoadFilteredPolicy";d:0.236;}}} \ No newline at end of file From 253a76665442515430c0cd6636785e862a1dbc12 Mon Sep 17 00:00:00 2001 From: Jon Lee Date: Thu, 9 Sep 2021 15:11:56 +0800 Subject: [PATCH 2/4] feat: implements updateFilteredPolicies --- src/Adapter.php | 115 +++++++++++++++--- tests/AdapterFeatureTest.php | 214 +++++++++++++++++++++++++++++++++ tests/AdapterTest.php | 224 +++++------------------------------ tests/DebugStackLogger.php | 52 ++++++++ 4 files changed, 391 insertions(+), 214 deletions(-) create mode 100644 tests/AdapterFeatureTest.php create mode 100644 tests/DebugStackLogger.php diff --git a/src/Adapter.php b/src/Adapter.php index 92f728a..0ec1094 100644 --- a/src/Adapter.php +++ b/src/Adapter.php @@ -11,12 +11,14 @@ use Casbin\Persist\UpdatableAdapter; use Closure; use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ResultStatement; -use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Query\Expression\CompositeExpression; +use Doctrine\DBAL\Result; +use Doctrine\DBAL\Schema\Schema; use Throwable; /** @@ -47,6 +49,11 @@ class Adapter implements FilteredAdapter, BatchAdapter, UpdatableAdapter */ private $filtered = false; + /** + * @var string[] + */ + protected $columns = ['p_type', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5']; + /** * Adapter constructor. * @@ -93,7 +100,7 @@ public function initTable() { $sm = $this->connection->getSchemaManager(); if (!$sm->tablesExist([$this->policyTableName])) { - $schema = new \Doctrine\DBAL\Schema\Schema(); + $schema = new Schema(); $table = $schema->createTable($this->policyTableName); $table->addColumn('id', 'integer', array('autoincrement' => true)); $table->addColumn('p_type', 'string', ['notnull' => false]); @@ -228,8 +235,7 @@ public function addPolicy(string $sec, string $ptype, array $rule): void * @param string $ptype * @param string[][] $rules * - * @throws Exception - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ public function addPolicies(string $sec, string $ptype, array $rules): void { @@ -306,6 +312,41 @@ public function removePolicies(string $sec, string $ptype, array $rules): void }); } + /** + * @param string $sec + * @param string $ptype + * @param int $fieldIndex + * @param string|null ...$fieldValues + * @return array + * @throws Throwable + */ + public function _removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, ?string ...$fieldValues): array + { + $removedRules = []; + $this->connection->transactional(function (Connection $conn) use ($ptype, $fieldIndex, $fieldValues, &$removedRules) { + $queryBuilder = $conn->createQueryBuilder(); + $queryBuilder->where('p_type = :ptype')->setParameter('ptype', $ptype); + + foreach ($fieldValues as $value) { + if (!is_null($value) && $value !== '') { + $key = 'v' . strval($fieldIndex); + $queryBuilder->andWhere($key . ' = :' . $key)->setParameter($key, $value); + } + $fieldIndex++; + } + + $stmt = $queryBuilder->select(...$this->columns)->from($this->policyTableName)->execute(); + + while ($row = $this->fetch($stmt)) { + $removedRules[] = $this->filterRule($row); + } + + $queryBuilder->delete($this->policyTableName)->execute(); + }); + + return $removedRules; + } + /** * RemoveFilteredPolicy removes policy rules that match the filter from the storage. * This is part of the Auto-Save feature. @@ -314,23 +355,11 @@ public function removePolicies(string $sec, string $ptype, array $rules): void * @param string $ptype * @param int $fieldIndex * @param string ...$fieldValues - * @throws Exception + * @throws Exception|Throwable */ public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, string ...$fieldValues): void { - $queryBuilder = $this->connection->createQueryBuilder(); - $queryBuilder->where('p_type = :ptype')->setParameter('ptype', $ptype); - - foreach (range(0, 5) as $value) { - if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) { - if ('' != $val = $fieldValues[$value - $fieldIndex]) { - $key = 'v' . strval($value); - $queryBuilder->andWhere($key . ' = :' . $key)->setParameter($key, $val); - } - } - } - - $queryBuilder->delete($this->policyTableName)->execute(); + $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues); } /** @@ -369,6 +398,7 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $ * @param string[][] $oldRules * @param string[][] $newRules * @return void + * @throws Throwable */ public function updatePolicies(string $sec, string $ptype, array $oldRules, array $newRules): void { @@ -379,6 +409,41 @@ public function updatePolicies(string $sec, string $ptype, array $oldRules, arra }); } + /** + * @param string $sec + * @param string $ptype + * @param array $newRules + * @param int $fieldIndex + * @param string ...$fieldValues + * @return array + * @throws Throwable + */ + public function updateFilteredPolicies(string $sec, string $ptype, array $newRules, int $fieldIndex, ?string ...$fieldValues): array + { + $oldRules = []; + $this->getConnection()->transactional(function ($conn) use ($sec, $ptype, $newRules, $fieldIndex, $fieldValues, &$oldRules) { + $oldRules = $this->_removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues); + $this->addPolicies($sec, $ptype, $newRules); + }); + + return $oldRules; + } + + /** + * Filter the rule. + * + * @param array $rule + * @return array + */ + public function filterRule(array $rule): array + { + $rule = array_filter($rule, function ($val) { + return '' != $val && !is_null($val); + }); + + return array_values($rule); + } + /** * Returns true if the loaded policy has been filtered. * @@ -409,12 +474,23 @@ public function getConnection(): Connection return $this->connection; } + /** + * Gets columns. + * + * @return string[] + */ + public function getColumns(): array + { + return $this->columns; + } + /** * @param mixed $stmt * * @return mixed + * @throws Exception */ - private function fetch($stmt) + private function fetch(Result $stmt) { if (method_exists($stmt, 'fetchAssociative')) { return $stmt->fetchAssociative(); @@ -422,4 +498,5 @@ private function fetch($stmt) return $stmt->fetch(); } + } diff --git a/tests/AdapterFeatureTest.php b/tests/AdapterFeatureTest.php new file mode 100644 index 0000000..8268f4a --- /dev/null +++ b/tests/AdapterFeatureTest.php @@ -0,0 +1,214 @@ +getEnforcer(); + $this->assertTrue($e->enforce('alice', 'data1', 'read')); + $this->assertFalse($e->enforce('bob', 'data1', 'read')); + $this->assertTrue($e->enforce('bob', 'data2', 'write')); + $this->assertTrue($e->enforce('alice', 'data2', 'read')); + $this->assertTrue($e->enforce('alice', 'data2', 'write')); + } + + public function testLoadFilteredPolicy() + { + $this->initConfig(); + $adapter = DatabaseAdapter::newAdapter($this->config); + $adapter->setFiltered(true); + $e = $this->getEnforcerWithAdapter($adapter); + $this->assertEquals([], $e->getPolicy()); + + // string + $filter = "v0 = 'bob'"; + $e->loadFilteredPolicy($filter); + $this->assertEquals([ + ['bob', 'data2', 'write'] + ], $e->getPolicy()); + + // CompositeExpression + $queryBuilder = new QueryBuilder($adapter->getConnection()); + $e->loadFilteredPolicy( + $queryBuilder->expr()->in("v0", ['"alice", "bob"']) + ); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'], + ], $e->getPolicy()); + + // Filter + $filter = new Filter('v2 = ?', ['read']); + $e->loadFilteredPolicy($filter); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['data2_admin', 'data2', 'read'], + ], $e->getPolicy()); + + // Closure + $e->loadFilteredPolicy(function (QueryBuilder &$queryBuilder) { + $queryBuilder->where('v1 = :v1')->setParameter('v1', 'data1'); + }); + + $this->assertEquals([ + ['alice', 'data1', 'read'], + ], $e->getPolicy()); + } + + public function testAddPolicy() + { + $e = $this->getEnforcer(); + $this->assertFalse($e->enforce('eve', 'data3', 'read')); + + $e->addPermissionForUser('eve', 'data3', 'read'); + $this->assertTrue($e->enforce('eve', 'data3', 'read')); + } + + public function testAddPolicies() + { + $policies = [ + ['u1', 'd1', 'read'], + ['u2', 'd2', 'read'], + ['u3', 'd3', 'read'], + ]; + $e = $this->getEnforcer(); + $e->clearPolicy(); + $this->initDb($this->adapter); + $this->assertEquals([], $e->getPolicy()); + $e->addPolicies($policies); + $this->assertEquals($policies, $e->getPolicy()); + } + + public function testSavePolicy() + { + $e = $this->getEnforcer(); + $this->assertFalse($e->enforce('alice', 'data4', 'read')); + + $model = $e->getModel(); + $model->clearPolicy(); + $model->addPolicy('p', 'p', ['alice', 'data4', 'read']); + + $adapter = $e->getAdapter(); + $adapter->savePolicy($model); + $this->assertTrue($e->enforce('alice', 'data4', 'read')); + } + + public function testRemovePolicy() + { + $e = $this->getEnforcer(); + $this->assertFalse($e->enforce('alice', 'data5', 'read')); + $e->addPermissionForUser('alice', 'data5', 'read'); + $this->assertTrue($e->enforce('alice', 'data5', 'read')); + $e->deletePermissionForUser('alice', 'data5', 'read'); + $this->assertFalse($e->enforce('alice', 'data5', 'read')); + } + + public function testRemovePolicies() + { + $e = $this->getEnforcer(); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'], + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ], $e->getPolicy()); + + $e->removePolicies([ + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ]); + + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'] + ], $e->getPolicy()); + } + + public function testRemoveFilteredPolicy() + { + $e = $this->getEnforcer(); + $this->assertTrue($e->enforce('alice', 'data1', 'read')); + $e->removeFilteredPolicy(1, 'data1'); + $this->assertFalse($e->enforce('alice', 'data1', 'read')); + + $this->assertTrue($e->enforce('bob', 'data2', 'write')); + $this->assertTrue($e->enforce('alice', 'data2', 'read')); + $this->assertTrue($e->enforce('alice', 'data2', 'write')); + + $e->removeFilteredPolicy(1, 'data2', 'read'); + + $this->assertTrue($e->enforce('bob', 'data2', 'write')); + $this->assertFalse($e->enforce('alice', 'data2', 'read')); + $this->assertTrue($e->enforce('alice', 'data2', 'write')); + + $e->removeFilteredPolicy(2, 'write'); + + $this->assertFalse($e->enforce('bob', 'data2', 'write')); + $this->assertFalse($e->enforce('alice', 'data2', 'write')); + } + + public function testUpdatePolicy() + { + $e = $this->getEnforcer(); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'], + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ], $e->getPolicy()); + + $e->updatePolicy( + ['alice', 'data1', 'read'], + ['alice', 'data1', 'write'] + ); + + $e->updatePolicy( + ['bob', 'data2', 'write'], + ['bob', 'data2', 'read'] + ); + + $this->assertEquals([ + ['alice', 'data1', 'write'], + ['bob', 'data2', 'read'], + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ], $e->getPolicy()); + } + + public function testUpdatePolicies() + { + $e = $this->getEnforcer(); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'], + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ], $e->getPolicy()); + + $oldPolicies = [ + ['alice', 'data1', 'read'], + ['bob', 'data2', 'write'] + ]; + + $newPolicies = [ + ['alice', 'data1', 'write'], + ['bob', 'data2', 'read'] + ]; + + $e->updatePolicies($oldPolicies, $newPolicies); + + $this->assertEquals([ + ['alice', 'data1', 'write'], + ['bob', 'data2', 'read'], + ['data2_admin', 'data2', 'read'], + ['data2_admin', 'data2', 'write'], + ], $e->getPolicy()); + } +} diff --git a/tests/AdapterTest.php b/tests/AdapterTest.php index eaa9c87..789f39e 100644 --- a/tests/AdapterTest.php +++ b/tests/AdapterTest.php @@ -3,212 +3,46 @@ namespace CasbinAdapter\DBAL\Tests; use CasbinAdapter\DBAL\Adapter as DatabaseAdapter; -use CasbinAdapter\DBAL\Filter; -use Doctrine\DBAL\Query\Expression\CompositeExpression; -use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Exception; class AdapterTest extends TestCase { - public function testLoadPolicy() - { - $e = $this->getEnforcer(); - $this->assertTrue($e->enforce('alice', 'data1', 'read')); - $this->assertFalse($e->enforce('bob', 'data1', 'read')); - $this->assertTrue($e->enforce('bob', 'data2', 'write')); - $this->assertTrue($e->enforce('alice', 'data2', 'read')); - $this->assertTrue($e->enforce('alice', 'data2', 'write')); - } - public function testLoadFilteredPolicy() + /** + * @throws Exception + */ + public function testUpdateFilteredPolicies() { $this->initConfig(); - $adapter = DatabaseAdapter::newAdapter($this->config); - $adapter->setFiltered(true); - $e = $this->getEnforcerWithAdapter($adapter); - $this->assertEquals([], $e->getPolicy()); - - // string - $filter = "v0 = 'bob'"; - $e->loadFilteredPolicy($filter); - $this->assertEquals([ - ['bob', 'data2', 'write'] - ], $e->getPolicy()); - - // CompositeExpression - $queryBuilder = new QueryBuilder($adapter->getConnection()); - $e->loadFilteredPolicy( - $queryBuilder->expr()->in("v0", ['"alice", "bob"']) - ); - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'], - ], $e->getPolicy()); - - // Filter - $filter = new Filter('v2 = ?', ['read']); - $e->loadFilteredPolicy($filter); - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['data2_admin', 'data2', 'read'], - ], $e->getPolicy()); - - // Closure - $e->loadFilteredPolicy(function (QueryBuilder &$queryBuilder) { - $queryBuilder->where('v1 = :v1')->setParameter('v1', 'data1'); - }); - - $this->assertEquals([ - ['alice', 'data1', 'read'], - ], $e->getPolicy()); - } - - public function testAddPolicy() - { - $e = $this->getEnforcer(); - $this->assertFalse($e->enforce('eve', 'data3', 'read')); - - $e->addPermissionForUser('eve', 'data3', 'read'); - $this->assertTrue($e->enforce('eve', 'data3', 'read')); - } - - public function testAddPolicies() - { - $policies = [ - ['u1', 'd1', 'read'], - ['u2', 'd2', 'read'], - ['u3', 'd3', 'read'], - ]; - $e = $this->getEnforcer(); - $e->clearPolicy(); - $this->initDb($this->adapter); - $this->assertEquals([], $e->getPolicy()); - $e->addPolicies($policies); - $this->assertEquals($policies, $e->getPolicy()); - } - - public function testSavePolicy() - { - $e = $this->getEnforcer(); - $this->assertFalse($e->enforce('alice', 'data4', 'read')); - - $model = $e->getModel(); - $model->clearPolicy(); - $model->addPolicy('p', 'p', ['alice', 'data4', 'read']); - - $adapter = $e->getAdapter(); - $adapter->savePolicy($model); - $this->assertTrue($e->enforce('alice', 'data4', 'read')); - } - - public function testRemovePolicy() - { - $e = $this->getEnforcer(); - $this->assertFalse($e->enforce('alice', 'data5', 'read')); - $e->addPermissionForUser('alice', 'data5', 'read'); - $this->assertTrue($e->enforce('alice', 'data5', 'read')); - $e->deletePermissionForUser('alice', 'data5', 'read'); - $this->assertFalse($e->enforce('alice', 'data5', 'read')); - } - - public function testRemovePolicies() - { - $e = $this->getEnforcer(); - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'], - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ], $e->getPolicy()); - - $e->removePolicies([ - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ]); - - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'] - ], $e->getPolicy()); - } - - public function testRemoveFilteredPolicy() - { - $e = $this->getEnforcer(); - $this->assertTrue($e->enforce('alice', 'data1', 'read')); - $e->removeFilteredPolicy(1, 'data1'); - $this->assertFalse($e->enforce('alice', 'data1', 'read')); - - $this->assertTrue($e->enforce('bob', 'data2', 'write')); - $this->assertTrue($e->enforce('alice', 'data2', 'read')); - $this->assertTrue($e->enforce('alice', 'data2', 'write')); - - $e->removeFilteredPolicy(1, 'data2', 'read'); - - $this->assertTrue($e->enforce('bob', 'data2', 'write')); - $this->assertFalse($e->enforce('alice', 'data2', 'read')); - $this->assertTrue($e->enforce('alice', 'data2', 'write')); - - $e->removeFilteredPolicy(2, 'write'); - - $this->assertFalse($e->enforce('bob', 'data2', 'write')); - $this->assertFalse($e->enforce('alice', 'data2', 'write')); - } - - public function testUpdatePolicy() - { - $e = $this->getEnforcer(); - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'], - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ], $e->getPolicy()); - - $e->updatePolicy( - ['alice', 'data1', 'read'], - ['alice', 'data1', 'write'] - ); - - $e->updatePolicy( - ['bob', 'data2', 'write'], - ['bob', 'data2', 'read'] + $connConfig = new Configuration(); + $logger = new DebugStackLogger(); + $connConfig->setSQLLogger($logger); + $conn = DriverManager::getConnection( + $this->config, + $connConfig ); - - $this->assertEquals([ - ['alice', 'data1', 'write'], - ['bob', 'data2', 'read'], - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ], $e->getPolicy()); - } - - public function testUpdatePolicies() - { - $e = $this->getEnforcer(); - $this->assertEquals([ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'], - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ], $e->getPolicy()); - - $oldPolicies = [ - ['alice', 'data1', 'read'], - ['bob', 'data2', 'write'] - ]; + $adapter = DatabaseAdapter::newAdapter($conn); + $conn->delete($adapter->policyTableName, ["1" => "1"]); + $conn->insert($adapter->policyTableName, ["p_type" => "p", "v0" => "alice", "v1" => "data", "v2" => "read", "v3" => "allow"]); + $conn->insert($adapter->policyTableName, ["p_type" => "p", "v0" => "alice", "v1" => "data1", "v2" => "write", "v3" => "allow"]); + $conn->insert($adapter->policyTableName, ["p_type" => "p", "v0" => "bob", "v1" => "data", "v2" => "write", "v3" => "allow"]); + $conn->insert($adapter->policyTableName, ["p_type" => "p", "v0" => "bob", "v1" => "data1", "v2" => "read", "v3" => "allow"]); $newPolicies = [ - ['alice', 'data1', 'write'], - ['bob', 'data2', 'read'] + ["alice", "data", "read", "allow"], + ["bob", "data", "read", "allow"] ]; + $oldRules = $adapter->updateFilteredPolicies("p", "p", $newPolicies, 1, "data", null, "allow"); + $this->assertEquals([ + ["p", "alice", "data", "read", "allow"], + ["p", "bob", "data", "write", "allow"] + ], $oldRules); - $e->updatePolicies($oldPolicies, $newPolicies); + $result = $conn->createQueryBuilder()->from($adapter->policyTableName)->where('p_type = "p" and v1 = "data" and v3 = "allow"')->select("v0", "v1", "v2", "v3")->execute()->fetchAllAssociative(); + $result = array_map([$adapter, "filterRule"], $result); - $this->assertEquals([ - ['alice', 'data1', 'write'], - ['bob', 'data2', 'read'], - ['data2_admin', 'data2', 'read'], - ['data2_admin', 'data2', 'write'], - ], $e->getPolicy()); + $this->assertEquals($newPolicies, $result); } } diff --git a/tests/DebugStackLogger.php b/tests/DebugStackLogger.php new file mode 100644 index 0000000..3959c69 --- /dev/null +++ b/tests/DebugStackLogger.php @@ -0,0 +1,52 @@ +isNamedArray($params)) { + $sql = str_replace(array_map(function ($item) { + return ":" . $item; + }, array_keys($params)), array_values($params), $sql); + } else { + $sql = str_replace(array('%', '?'), array('%%', '%s'), $sql); + $sql = sprintf($sql, ...$params); + } + + printf(date('Y-m-d H:i:s') . '[SQL]: ' . $sql . PHP_EOL); + } + + /** + * + */ + public function stopQuery() + { + // TODO: Implement stopQuery() method. + } + + public function isNamedArray($array): bool + { + if (is_array($array)) { + $keys = array_keys($array); + return $keys != array_keys($keys); + } + return false; + } +} \ No newline at end of file From d32690dbc0b43b3ac85d9c6f2714a81fbd683988 Mon Sep 17 00:00:00 2001 From: Jon Lee Date: Thu, 9 Sep 2021 15:22:53 +0800 Subject: [PATCH 3/4] ci: update ci config --- .github/workflows/default.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index 225f1fb..e71d591 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -1,10 +1,6 @@ name: Default -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] +on: [push, pull_request] jobs: test: From 2563953f8618c4645e6b0e2c923748896cae4842 Mon Sep 17 00:00:00 2001 From: Jon Lee Date: Thu, 9 Sep 2021 15:48:48 +0800 Subject: [PATCH 4/4] fix: Use loadPolicyArray instead of loadPolicyLine to fix the problem of quotation marks --- src/Adapter.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Adapter.php b/src/Adapter.php index 0ec1094..4489e76 100644 --- a/src/Adapter.php +++ b/src/Adapter.php @@ -151,10 +151,7 @@ public function loadPolicy(Model $model): void $stmt = $queryBuilder->select('p_type', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5')->from($this->policyTableName)->execute(); while ($row = $this->fetch($stmt)) { - $line = implode(', ', array_filter($row, function ($val) { - return '' != $val && !is_null($val); - })); - $this->loadPolicyLine(trim($line), $model); + $this->loadPolicyArray($this->filterRule($row), $model); } } @@ -437,11 +434,16 @@ public function updateFilteredPolicies(string $sec, string $ptype, array $newRul */ public function filterRule(array $rule): array { - $rule = array_filter($rule, function ($val) { - return '' != $val && !is_null($val); - }); + $rule = array_values($rule); + + $i = count($rule) - 1; + for (; $i >= 0; $i--) { + if ($rule[$i] != "" && !is_null($rule[$i])) { + break; + } + } - return array_values($rule); + return array_slice($rule, 0, $i + 1); } /**