Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync with base package #57

Merged
merged 14 commits into from
Jan 16, 2024
2 changes: 1 addition & 1 deletion .github/workflows/composer-require-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.0', '8.1']
['8.1']
extensions: uopz
5 changes: 2 additions & 3 deletions .github/workflows/mssql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-mssql-${{ matrix.mssql }}

env:
extensions: pdo, pdo_sqlsrv-5.10.1, uopz
extensions: pdo, pdo_sqlsrv-5.11.1, uopz

runs-on: ${{ matrix.os }}

Expand All @@ -36,7 +36,6 @@ jobs:
- ubuntu-latest

php:
- 8.0
- 8.1

mssql:
Expand Down Expand Up @@ -95,7 +94,7 @@ jobs:
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Install db-mssql
run: composer require --dev yiisoft/db-mssql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
run: composer require --dev "yiisoft/db-mssql:^1.1" --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Run tests with phpunit
run: vendor/bin/phpunit --testsuite Mssql --coverage-clover=coverage.xml --colors=always
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ jobs:
- ubuntu-latest

php:
- 8.0
- 8.1

mysql:
Expand Down Expand Up @@ -85,7 +84,7 @@ jobs:
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Install db-mysql
run: composer require --dev yiisoft/db-mysql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
run: composer require --dev "yiisoft/db-mysql:^1.1" --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Run tests with phpunit
run: vendor/bin/phpunit --testsuite Mysql --coverage-clover=coverage.xml --colors=always
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/oracle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ jobs:
- ubuntu-latest

php:
- 8.0
- 8.1
- 8.2

Expand Down Expand Up @@ -91,7 +90,7 @@ jobs:
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Install db-oracle
run: composer require --dev yiisoft/db-oracle --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
run: composer require --dev "yiisoft/db-oracle:^1.2" --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Run tests with phpunit
run: vendor/bin/phpunit --testsuite Oracle --coverage-clover=coverage.xml --colors=always
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/pgsql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ jobs:
- ubuntu-latest

php:
- 8.0
- 8.1

pgsql:
Expand Down Expand Up @@ -90,7 +89,7 @@ jobs:
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Install db-pgsql
run: composer require --dev yiisoft/db-pgsql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
run: composer require --dev "yiisoft/db-pgsql:^1.2" --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi

- name: Run tests with phpunit
run: vendor/bin/phpunit --testsuite Pgsql --coverage-clover=coverage.xml --colors=always
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/sqlite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jobs:
- windows-latest

php:
- 8.0
- 8.1
- 8.2

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ jobs:
os: >-
['ubuntu-latest']
php: >-
['8.0', '8.1']
['8.1']
extensions: uopz
2 changes: 1 addition & 1 deletion .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ build:

environment:
php:
version: 8.0.11
version: 8.1
ini:
"xdebug.mode": coverage

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- `userHasItem()`.
(@arogachev)
- Bug #54: Fix ignoring of using `Assignment::$createdAt` in `AssignmentsStorage::add()` (@arogachev)
- Chg #?: Raise PHP version to 8.1 (@arogachev)

## 1.0.0 April 20, 2023

Expand Down
11 changes: 6 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
"minimum-stability": "dev",
"require": {
"ext-pdo": "*",
"php": "^8.0",
"yiisoft/db": "^1.0",
"yiisoft/rbac": "dev-master"
"php": "^8.1",
"yiisoft/db": "^1.2",
"yiisoft/rbac": "dev-master#cba39d8471677970282fdad302271c858f5c7912"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"ext-uopz": "*",
"maglnet/composer-require-checker": "^4.3",
"phpunit/phpunit": "^9.5",
"phpunit/phpunit": "^10.5.5",
"rector/rector": "^0.19.0",
"roave/infection-static-analysis-plugin": "^1.25",
"slope-it/clock-mock": "0.4.0",
Expand All @@ -55,7 +55,8 @@
"psr-4": {
"Yiisoft\\Rbac\\Db\\Tests\\": "tests",
"Yiisoft\\Rbac\\Tests\\": "vendor/yiisoft/rbac/tests"
}
},
"files": ["tests/bootstrap.php"]
},
"config": {
"sort-packages": true,
Expand Down
39 changes: 21 additions & 18 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
backupGlobals="false"
colors="true"
verbose="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
defaultTestSuite="Sqlite"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory>./</directory>
</include>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</coverage>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
defaultTestSuite="Sqlite"
executionOrder="random"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
cacheDirectory=".phpunit.cache"
>
<php>
<ini name="error_reporting" value="-1"/>
</php>
Expand All @@ -37,4 +31,13 @@
<directory>./tests/Oracle</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>./</directory>
</include>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</source>
</phpunit>
3 changes: 3 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<MixedAssignment errorLevel="suppress" />
</issueHandlers>
</psalm>
12 changes: 12 additions & 0 deletions src/AssignmentsStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ public function userHasItem(string $userId, array $itemNames): bool
->exists();
}

public function filterUserItemNames(string $userId, array $itemNames): array
{
/** @var array{itemName: string} $rows */
$rows = (new Query($this->database))
->select('itemName')
->from($this->tableName)
->where(['userId' => $userId, 'itemName' => $itemNames])
->all();

return array_column($rows, 'itemName');
}

public function add(Assignment $assignment): void
{
$this
Expand Down
93 changes: 76 additions & 17 deletions src/ItemTreeTraversal/CteItemTreeTraversal.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @internal
*
* @psalm-import-type RawItem from ItemsStorage
* @psalm-import-type AccessTree from ItemTreeTraversalInterface
*/
abstract class CteItemTreeTraversal implements ItemTreeTraversalInterface
{
Expand Down Expand Up @@ -49,34 +50,60 @@ public function getParentRows(string $name): array
return $this->getRowsCommand($name, baseOuterQuery: $baseOuterQuery)->queryAll();
}

public function getChildrenRows(string $name): array
public function getAccessTree(string $name): array
{
$baseOuterQuery = (new Query($this->database))->select('item.*')->where(['!=', 'item.name', $name]);
$baseOuterQuery = (new Query($this->database))->select(['item.*', 'parent_of.children']);
$cteSelectRelationQuery = (new Query($this->database))
->select(['parent', new Expression($this->getTrimConcatChildrenExpression())])
->from("$this->childrenTableName AS item_child_recursive")
->innerJoin('parent_of', [
'item_child_recursive.child' => new Expression('{{parent_of}}.[[child_name]]'),
]);
$cteSelectItemQuery = (new Query($this->database))
->select(['name', new Expression($this->getEmptyChildrenExpression())])
->from($this->tableName)
->where(['name' => $name])
->union($cteSelectRelationQuery, all: true);
$quoter = $this->database->getQuoter();
$outerQuery = $baseOuterQuery
->withQuery(
$cteSelectItemQuery,
$quoter->quoteTableName('parent_of') . '(' . $quoter->quoteColumnName('child_name') . ',' .
$quoter->quoteColumnName('children') . ')',
recursive: $this->useRecursiveInWith,
)
->from('parent_of')
->leftJoin(
['item' => $this->tableName],
['item.name' => new Expression('{{parent_of}}.[[child_name]]')],
);

/** @psalm-var AccessTree */
return $outerQuery->all();
}

public function getChildrenRows(string|array $names): array
{
$baseOuterQuery = $this->getChildrenBaseOuterQuery($names);

/** @psalm-var RawItem[] */
return $this->getRowsCommand($name, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
return $this->getRowsCommand($names, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
}

public function getChildPermissionRows(string $name): array
public function getChildPermissionRows(string|array $names): array
{
$baseOuterQuery = (new Query($this->database))
->select('item.*')
->where(['!=', 'item.name', $name])
->andWhere(['item.type' => Item::TYPE_PERMISSION]);
$baseOuterQuery = $this->getChildrenBaseOuterQuery($names)->andWhere(['item.type' => Item::TYPE_PERMISSION]);

/** @psalm-var RawItem[] */
return $this->getRowsCommand($name, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
return $this->getRowsCommand($names, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
}

public function getChildRoleRows(string $name): array
public function getChildRoleRows(string|array $names): array
{
$baseOuterQuery = (new Query($this->database))
->select('item.*')
->where(['!=', 'item.name', $name])
->andWhere(['item.type' => Item::TYPE_ROLE]);
$baseOuterQuery = $this->getChildrenBaseOuterQuery($names)->andWhere(['item.type' => Item::TYPE_ROLE]);

/** @psalm-var RawItem[] */
return $this->getRowsCommand($name, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
return $this->getRowsCommand($names, baseOuterQuery: $baseOuterQuery, areParents: false)->queryAll();
}

public function hasChild(string $parentName, string $childName): bool
Expand All @@ -96,8 +123,27 @@ public function hasChild(string $parentName, string $childName): bool
return $result !== false;
}

/**
* @infection-ignore-all
* - ProtectedVisibility.
*
* @psalm-return non-empty-string
*/
protected function getEmptyChildrenExpression(): string
{
return "''";
}

/**
* @psalm-return non-empty-string
*/
protected function getTrimConcatChildrenExpression(): string
{
return "TRIM(',' FROM CONCAT(children, ',', item_child_recursive.child))";
}

private function getRowsCommand(
string $name,
string|array $names,
QueryInterface $baseOuterQuery,
bool $areParents = true,
): CommandInterface {
Expand All @@ -124,7 +170,7 @@ private function getRowsCommand(
$cteSelectItemQuery = (new Query($this->database))
->select('name')
->from($this->tableName)
->where(['name' => $name])
->where(['name' => $names])
->union($cteSelectRelationQuery, all: true);
$quoter = $this->database->getQuoter();
$outerQuery = $baseOuterQuery
Expand All @@ -141,4 +187,17 @@ private function getRowsCommand(

return $outerQuery->createCommand();
}

/**
* @psalm-param string|non-empty-array<array-key, string> $names
*/
private function getChildrenBaseOuterQuery(string|array $names): QueryInterface
{
$baseOuterQuery = (new Query($this->database))->select('item.*')->distinct();
if (is_string($names)) {
return $baseOuterQuery->where(['!=', 'item.name', $names]);
}

return $baseOuterQuery->where(['not in', 'item.name', $names]);
}
}
Loading
Loading