Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ composer.lock
*.iml

# coverage report
/build
/build

.phpunit.*
64 changes: 64 additions & 0 deletions src/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,68 @@ public function updatePolicies(string $sec, string $ptype, array $oldRules, arra
throw $e;
}
}

/**
* UpdateFilteredPolicies deletes old rules and adds new rules.
*
* @param string $sec
* @param string $ptype
* @param array $newPolicies
* @param integer $fieldIndex
* @param string ...$fieldValues
* @return array
*/
public function updateFilteredPolicies(string $sec, string $ptype, array $newPolicies, int $fieldIndex, string ...$fieldValues): array
{
$deleteWhere['ptype'] = $ptype;
$deleteCondition[] = 'ptype = :ptype';
foreach ($fieldValues as $value) {
if (!is_null($value) && $value !== '') {
$key = $fieldIndex++;
$placeholder = "v" . strval($key);
$deleteWhere['v' . strval($key)] = $value;
$deleteCondition[] = 'v' . strval($key) . ' = :' . $placeholder;
}
}
$deleteSql = "DELETE FROM {$this->casbinRuleTableName} WHERE " . implode(' AND ', $deleteCondition);

$selectSql = "SELECT * FROM {$this->casbinRuleTableName} WHERE " . implode(' AND ', $deleteCondition);
$oldP = $this->connection->query($selectSql, $deleteWhere);
foreach ($oldP as &$item) {
$item = array_filter($item, function ($value) {
return !is_null($value) && $value !== '';
});
unset($item['ptype']);
unset($item['id']);
}

$columns = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
$values = [];
$sets = [];
$columnsCount = count($columns);
foreach ($newPolicies as $newPolicy) {
array_unshift($newPolicy, $ptype);
$values = array_merge($values, array_pad($newPolicy, $columnsCount, null));
$sets[] = array_pad([], $columnsCount, '?');
}
$valuesStr = implode(', ', array_map(function ($set) {
return '(' . implode(', ', $set) . ')';
}, $sets));
$insertSql = 'INSERT INTO ' . $this->casbinRuleTableName . ' (' . implode(', ', $columns) . ')' . ' VALUES ' . $valuesStr;

// start transaction
$this->connection->getPdo()->beginTransaction();
try {
// delete old data
$this->connection->execute($deleteSql, $deleteWhere);
// insert new data
$this->connection->execute($insertSql, $values);
$this->connection->getPdo()->commit();
} catch (Throwable $e) {
$this->connection->getPdo()->rollback();
throw $e;
}

return $oldP;
}
}
125 changes: 125 additions & 0 deletions tests/AdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,131 @@ public function testUpdatePolicies()
], $e->getPolicy());
}

public function arrayEqualsWithoutOrder(array $expected, array $actual)
{
if (method_exists($this, 'assertEqualsCanonicalizing')) {
$this->assertEqualsCanonicalizing($expected, $actual);
} else {
array_multisort($expected);
array_multisort($actual);
$this->assertEquals($expected, $actual);
}
}

public function testUpdateFilteredPolicies()
{
$e = $this->getEnforcer();
$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
], $e->getPolicy());

$e->updateFilteredPolicies([["alice", "data1", "write"]], 0, "alice", "data1", "read");
$e->updateFilteredPolicies([["bob", "data2", "read"]], 0, "bob", "data2", "write");

$policies = [
['alice', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test use updateFilteredPolicies to update all policies of a user
$e = $this->getEnforcer();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->arrayEqualsWithoutOrder([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'write'], ['alice', 'data2', 'read']], 0, 'alice');
$e->updateFilteredPolicies([['bob', 'data1', 'write'], ["bob", "data2", "read"]], 0, 'bob');

$policies = [
['alice', 'data1', 'write'],
['alice', 'data2', 'read'],
['bob', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test if $fieldValues contains empty string
$e = $this->getEnforcer();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'write'], ['alice', 'data2', 'read']], 0, 'alice', '', '');
$e->updateFilteredPolicies([['bob', 'data1', 'write'], ["bob", "data2", "read"]], 0, 'bob', '', '');

$policies = [
['alice', 'data1', 'write'],
['alice', 'data2', 'read'],
['bob', 'data1', 'write'],
['bob', 'data2', 'read'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write']
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());

// test if $fieldIndex is not zero
$e = $this->getEnforcer();
$policies = [
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
];
$e->addPolicies($policies);

$this->assertEquals([
['alice', 'data1', 'read'],
['bob', 'data2', 'write'],
['data2_admin', 'data2', 'read'],
['data2_admin', 'data2', 'write'],
['alice', 'data2', 'write'],
['bob', 'data1', 'read']
], $e->getPolicy());

$e->updateFilteredPolicies([['alice', 'data1', 'edit'], ['bob', 'data1', 'edit']], 2, 'read');
$e->updateFilteredPolicies([['alice', 'data2', 'read'], ["bob", "data2", "read"]], 2, 'write');

$policies = [
['alice', 'data1', 'edit'],
['alice', 'data2', 'read'],
['bob', 'data1', 'edit'],
['bob', 'data2', 'read'],
];

$this->arrayEqualsWithoutOrder($policies, $e->getPolicy());
}

protected function env($key, $default = null)
{
$value = getenv($key);
Expand Down