diff --git a/.gitattributes b/.gitattributes index 10d6160..705796b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,6 @@ /psalm.baseline.xml export-ignore /test/ export-ignore /autoload-dev/ export-ignore +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto +*.php text eol=lf diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml deleted file mode 100644 index 1281696..0000000 --- a/.github/workflows/build_test.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Continuous Integration - -on: - push: - # Avoid running tests on changes to documentation - paths-ignore: - - 'docs/**' - pull_request: - paths-ignore: - - 'docs/**' - -env: - COMPOSER_ARGS: '--no-progress' - -jobs: - build: - strategy: - matrix: - php_version: ['8.1', '8.2', '8.3'] - deps: ['--prefer-lowest --prefer-dist', ''] - include: - - code-coverage: 'yes' - php_version: '8.2' - deps: '' - runs-on: ubuntu-latest - - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{matrix.php_version}} - - - name: Show PHP version - run: php -v - - - uses: actions/checkout@v4 - name: Checkout branch - - - name: Validate composer.json and composer.lock - run: composer validate --strict - - - name: Cache Composer packages - id: composer-cache - uses: actions/cache@v4 - with: - path: vendor - key: ${{ runner.os }}-php-${{ matrix.php_version }}-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php--${{matrix.php_version}}- - - - name: Install/update dependencies - run: composer update ${{matrix.deps}} $COMPOSER_ARGS - - - name: Run PHPUnit test suite - if: ${{ matrix.code-coverage != 'yes' }} - run: composer run-script test - - - name: Run PHPUnit test suite with coverage - if: ${{ matrix.code-coverage == 'yes' }} - run: composer run-script test-coverage - - - name: Upload coverage results to Coverall - if: ${{ matrix.code-coverage == 'yes' }} - uses: coverallsapp/github-action@v2 - - diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..a506d0f --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,15 @@ +name: "Continuous Integration" + +on: + pull_request: + paths-ignore: + - 'docs/**' + push: + paths-ignore: + - 'docs/**' + branches: + tags: + +jobs: + ci: + uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x diff --git a/.laminas-ci.json b/.laminas-ci.json new file mode 100644 index 0000000..b33f394 --- /dev/null +++ b/.laminas-ci.json @@ -0,0 +1,8 @@ +{ + "extensions": [ + "sqlite3" + ], + "ignore_php_platform_requirements": { + "8.4": true + } +} diff --git a/README.md b/README.md index de64271..b931641 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ ![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.github.com%2Frepos%2Flm-commons%2Flmcrbac%2Fproperties%2Fvalues&query=%24%5B%3A1%5D.value&label=Maintenance%20Status) - Role-based access control module to provide additional features on top of Laminas\Permissions\Rbac ## Requirements diff --git a/composer.json b/composer.json index 3ed8a82..0c35caf 100644 --- a/composer.json +++ b/composer.json @@ -39,21 +39,21 @@ } ], "require": { - "php": "^8.1 || ^8.2 || ^8.3", - "laminas/laminas-permissions-rbac": "^3.0", - "laminas/laminas-servicemanager": "^3.3", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "laminas/laminas-permissions-rbac": "^3.1", + "laminas/laminas-servicemanager": "^3.15", "laminas/laminas-stdlib": "^3.1", "doctrine/persistence": "^2.0 || ^3.0" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5.0", + "laminas/laminas-coding-standard": "^3.0", "phpunit/phpunit": "^10.0 || ^11.0", "phpspec/prophecy": "^1.10", "phpspec/prophecy-phpunit": "^2.0", - "doctrine/orm": "^2.13 || ^3.0", - "symfony/cache": "^4.0 || ^5.0 || ^6.0", + "doctrine/orm": "^3.0", + "symfony/cache": "^6.3", "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.25" + "vimeo/psalm": "^5.26" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 13513ce..d98c534 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ae07828c3ee4aea827ffeb29488f3ee5", + "content-hash": "97193b457873506e51475d3d95d15b2e", "packages": [ { "name": "doctrine/event-manager", @@ -962,35 +962,38 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.2", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", - "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", + "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0" + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1006,7 +1009,7 @@ }, { "name": "Contributors", - "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -1030,10 +1033,10 @@ "tests" ], "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2022-02-04T12:51:07+00:00" + "time": "2023-01-05T11:28:13+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -1803,27 +1806,24 @@ }, { "name": "laminas/laminas-coding-standard", - "version": "2.5.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-coding-standard.git", - "reference": "c1aaa18a7c860c6932677a3e4ec13161f9fc7d61" + "reference": "ac809f5b27f0b22d0c1ec0cbc78cb67f92bfebcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-coding-standard/zipball/c1aaa18a7c860c6932677a3e4ec13161f9fc7d61", - "reference": "c1aaa18a7c860c6932677a3e4ec13161f9fc7d61", + "url": "https://api.github.com/repos/laminas/laminas-coding-standard/zipball/ac809f5b27f0b22d0c1ec0cbc78cb67f92bfebcb", + "reference": "ac809f5b27f0b22d0c1ec0cbc78cb67f92bfebcb", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", "php": "^7.4 || ^8.0", - "slevomat/coding-standard": "^7.0", - "squizlabs/php_codesniffer": "^3.6", - "webimpress/coding-standard": "^1.2" - }, - "conflict": { - "phpstan/phpdoc-parser": ">=1.6.0" + "slevomat/coding-standard": "^8.15.0", + "squizlabs/php_codesniffer": "^3.10", + "webimpress/coding-standard": "^1.3" }, "type": "phpcodesniffer-standard", "autoload": { @@ -1855,7 +1855,7 @@ "type": "community_bridge" } ], - "time": "2023-01-05T15:53:40+00:00" + "time": "2024-10-16T09:23:09+00:00" }, { "name": "myclabs/deep-copy", @@ -2197,28 +2197,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.6.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" }, "type": "library", "extra": { @@ -2242,36 +2249,39 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-12-07T09:39:29+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -2303,9 +2313,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2024-11-09T15:12:26+00:00" }, { "name": "phpspec/prophecy", @@ -2434,25 +2444,28 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.5.1", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "981cc368a216c988e862a75e526b6076987d1b50" + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/981cc368a216c988e862a75e526b6076987d1b50", - "reference": "981cc368a216c988e862a75e526b6076987d1b50", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" @@ -2472,9 +2485,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.5.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" }, - "time": "2022-05-05T11:32:40+00:00" + "time": "2024-10-13T11:25:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3926,42 +3939,42 @@ }, { "name": "slevomat/coding-standard", - "version": "7.2.1", + "version": "8.15.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90" + "reference": "7d1d957421618a3803b593ec31ace470177d7817" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/aff06ae7a84e4534bf6f821dc982a93a5d477c90", - "reference": "aff06ae7a84e4534bf6f821dc982a93a5d477c90", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.5.1", - "squizlabs/php_codesniffer": "^3.6.2" + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" }, "require-dev": { - "phing/phing": "2.17.3", + "phing/phing": "2.17.4", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.4.10|1.7.1", - "phpstan/phpstan-deprecation-rules": "1.0.0", - "phpstan/phpstan-phpunit": "1.0.0|1.1.1", - "phpstan/phpstan-strict-rules": "1.2.3", - "phpunit/phpunit": "7.5.20|8.5.21|9.5.20" + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" }, "type": "phpcodesniffer-standard", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard" + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3969,9 +3982,13 @@ "MIT" ], "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.2.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" }, "funding": [ { @@ -3983,7 +4000,7 @@ "type": "tidelift" } ], - "time": "2022-05-25T10:58:12+00:00" + "time": "2024-03-09T15:20:58+00:00" }, { "name": "spatie/array-to-xml", @@ -5376,7 +5393,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^8.1 || ^8.2 || ^8.3" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "platform-dev": {}, "platform-overrides": { diff --git a/psalm.baseline.xml b/psalm.baseline.xml index 31edb87..b6348c1 100644 --- a/psalm.baseline.xml +++ b/psalm.baseline.xml @@ -1,3 +1,312 @@ - + + + + + + + + + + + + + + + + + + + getAssertionManager()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getRoleProvider()[InMemoryRoleProvider::class] ?? []]]> + + + + + + + + + + + + + + + + + + + + roleCache[$key]]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + get(AssertionPluginManagerInterface::class)]]> + get(Rbac::class)]]> + get(RoleServiceInterface::class)]]> + getAssertionMap()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Driver::class, + 'path' => null, + 'memory' => true, + 'dbname' => 'test', + ]]]> + + + + + + + + + getChildren()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [ + function ($permission, ?IdentityInterface $identity = null, $context = null) use (&$called1) { + $called1 = true; + + return true; + }, + function ($permission, ?IdentityInterface $identity = null, $context = null) use (&$called2) { + $called2 = true; + + return false; + }, + ], + ]]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml index d3092be..c02dc19 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,13 +1,13 @@ diff --git a/src/Assertion/AssertionPluginManagerFactory.php b/src/Assertion/AssertionPluginManagerFactory.php index 40cd52b..a3e46dc 100644 --- a/src/Assertion/AssertionPluginManagerFactory.php +++ b/src/Assertion/AssertionPluginManagerFactory.php @@ -1,5 +1,7 @@ get(ModuleOptions::class); diff --git a/src/Assertion/AssertionPluginManagerInterface.php b/src/Assertion/AssertionPluginManagerInterface.php index b7db7d4..dace64d 100644 --- a/src/Assertion/AssertionPluginManagerInterface.php +++ b/src/Assertion/AssertionPluginManagerInterface.php @@ -25,5 +25,5 @@ interface AssertionPluginManagerInterface extends ContainerInterface { - public function get($name): AssertionInterface; + public function get(string $id): AssertionInterface; } diff --git a/src/Assertion/AssertionSet.php b/src/Assertion/AssertionSet.php index 174911a..ff82c34 100644 --- a/src/Assertion/AssertionSet.php +++ b/src/Assertion/AssertionSet.php @@ -40,15 +40,10 @@ class AssertionSet implements AssertionInterface public const CONDITION_OR = 'condition_or'; public const CONDITION_AND = 'condition_and'; - /** @var array */ private array $assertions; private string $condition = self::CONDITION_AND; - /** - * @param AssertionPluginManagerInterface $assertionPluginManager - * @param array $assertions - */ public function __construct( private readonly AssertionPluginManagerInterface $assertionPluginManager, array $assertions @@ -69,11 +64,8 @@ public function __construct( $this->assertions = $assertions; } - public function assert( - $permission, - ?IdentityInterface $identity = null, - mixed $context = null - ): bool { + public function assert(string $permission, ?IdentityInterface $identity = null, mixed $context = null): bool + { if (empty($this->assertions)) { return false; } @@ -94,12 +86,16 @@ public function assert( $asserted = $assertion->assert($permission, $identity, $context); break; case is_array($assertion): - $this->assertions[$index] = $assertion = new AssertionSet($this->assertionPluginManager, $assertion); + $this->assertions[$index] = $assertion = new AssertionSet( + $this->assertionPluginManager, + $assertion + ); $asserted = $assertion->assert($permission, $identity, $context); break; default: throw new Exception\InvalidArgumentException(sprintf( - 'Assertion must be callable, string, array or implement Lmc\Rbac\Assertion\AssertionInterface, "%s" given', + 'Assertion must be callable, string, + array or implement Lmc\Rbac\Assertion\AssertionInterface, "%s" given', is_object($assertion) ? $assertion::class : gettype($assertion) )); } diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php index 059f7c9..8e5c94f 100644 --- a/src/Exception/ExceptionInterface.php +++ b/src/Exception/ExceptionInterface.php @@ -23,7 +23,6 @@ /** * Base exception interface for LmcRbac - * */ interface ExceptionInterface { diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index 78a4b80..5e2acd9 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -25,7 +25,6 @@ /** * RuntimeException - * */ class RuntimeException extends BaseRuntimeException implements ExceptionInterface { diff --git a/src/Options/ModuleOptions.php b/src/Options/ModuleOptions.php index b494620..45cbfd0 100644 --- a/src/Options/ModuleOptions.php +++ b/src/Options/ModuleOptions.php @@ -26,7 +26,6 @@ /** * Options for LmcRbac module - * */ class ModuleOptions extends AbstractOptions { @@ -37,16 +36,12 @@ class ModuleOptions extends AbstractOptions /** * Assertion map - * - * @var array */ protected array $assertionMap = []; /** * A configuration for role provider * Defaults to InMemoryRoleProvider - * - * @var array */ protected array $roleProvider = [ InMemoryRoleProvider::class => [], @@ -54,8 +49,6 @@ class ModuleOptions extends AbstractOptions /** * Assertion plugin manager configuration - * - * @var array */ protected array $assertionManager = []; @@ -73,8 +66,6 @@ public function __construct($options = null) /** * Set the assertions options - * - * @param array $assertionMap */ public function setAssertionMap(array $assertionMap): void { @@ -83,8 +74,6 @@ public function setAssertionMap(array $assertionMap): void /** * Get the assertions options - * - * @return array */ public function getAssertionMap(): array { @@ -109,8 +98,6 @@ public function getGuestRole(): string /** * Set the configuration for the role provider - * - * @param array $roleProvider */ public function setRoleProvider(array $roleProvider): void { @@ -124,17 +111,12 @@ public function getRoleProvider(): array /** * Set the configuration for the assertion plugin manager - * - * @param array $assertionManager */ public function setAssertionManager(array $assertionManager): void { $this->assertionManager = $assertionManager; } - /** - * @return array - */ public function getAssertionManager(): array { return $this->assertionManager; diff --git a/src/Options/ModuleOptionsFactory.php b/src/Options/ModuleOptionsFactory.php index 86bdf3c..07ddf03 100644 --- a/src/Options/ModuleOptionsFactory.php +++ b/src/Options/ModuleOptionsFactory.php @@ -24,6 +24,8 @@ use Laminas\ServiceManager\Exception\ServiceNotCreatedException; use Psr\Container\ContainerInterface; +use function is_array; + /** * Factory for the module options */ @@ -33,7 +35,7 @@ public function __invoke(ContainerInterface $container): ModuleOptions { $config = $container->get('config'); - if (!isset($config['lmc_rbac']) || !is_array($config['lmc_rbac'])) { + if (! isset($config['lmc_rbac']) || ! is_array($config['lmc_rbac'])) { throw new ServiceNotCreatedException('No lmc_rbac config found.'); } diff --git a/src/Role/InMemoryRoleProvider.php b/src/Role/InMemoryRoleProvider.php index 41e02ef..6180c60 100644 --- a/src/Role/InMemoryRoleProvider.php +++ b/src/Role/InMemoryRoleProvider.php @@ -40,12 +40,8 @@ */ final class InMemoryRoleProvider implements RoleProviderInterface { - /** @var array */ private array $rolesConfig = []; - /** - * @param array $rolesConfig - */ public function __construct(array $rolesConfig) { $this->rolesConfig = $rolesConfig; diff --git a/src/Role/InMemoryRoleProviderFactory.php b/src/Role/InMemoryRoleProviderFactory.php index ea19bcd..5dc10d4 100644 --- a/src/Role/InMemoryRoleProviderFactory.php +++ b/src/Role/InMemoryRoleProviderFactory.php @@ -27,7 +27,6 @@ /** * Factory used to create an in memory role provider - * */ class InMemoryRoleProviderFactory { diff --git a/src/Service/AuthorizationService.php b/src/Service/AuthorizationService.php index 25e0ee8..25c196c 100644 --- a/src/Service/AuthorizationService.php +++ b/src/Service/AuthorizationService.php @@ -26,7 +26,6 @@ use Lmc\Rbac\Assertion\AssertionPluginManagerInterface; use Lmc\Rbac\Assertion\AssertionSet; use Lmc\Rbac\Identity\IdentityInterface; -use Lmc\Rbac\RbacInterface; use function array_merge; use function is_array; diff --git a/src/Service/AuthorizationServiceAwareInterface.php b/src/Service/AuthorizationServiceAwareInterface.php index b63afae..9bc8934 100644 --- a/src/Service/AuthorizationServiceAwareInterface.php +++ b/src/Service/AuthorizationServiceAwareInterface.php @@ -1,4 +1,7 @@ get(AuthorizationServiceInterface::class); diff --git a/src/Service/AuthorizationServiceFactory.php b/src/Service/AuthorizationServiceFactory.php index d1d2326..aa4f118 100644 --- a/src/Service/AuthorizationServiceFactory.php +++ b/src/Service/AuthorizationServiceFactory.php @@ -1,4 +1,5 @@ [], ] diff --git a/test/Assertion/AssertionSetTest.php b/test/Assertion/AssertionSetTest.php index 30b7de8..046c3f1 100644 --- a/test/Assertion/AssertionSetTest.php +++ b/test/Assertion/AssertionSetTest.php @@ -107,7 +107,10 @@ public function testAndConditionWillBreakEarlyWithFailure() $barAssertion = new SimpleAssertion(true); $assertionContainer = $this->getMockBuilder(AssertionPluginManagerInterface::class)->getMock(); - $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_AND]); + $assertionSet = new AssertionSet( + $assertionContainer, + ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_AND] + ); $assertionContainer->expects($this->once())->method('get')->with('fooFactory')->willReturn($fooAssertion); @@ -123,7 +126,10 @@ public function testOrConditionWillBreakEarlyWithSuccess() $barAssertion = new SimpleAssertion(false); $assertionContainer = $this->getMockBuilder(AssertionPluginManagerInterface::class)->getMock(); - $assertionSet = new AssertionSet($assertionContainer, ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_OR]); + $assertionSet = new AssertionSet( + $assertionContainer, + ['fooFactory', 'barFactory', 'condition' => AssertionSet::CONDITION_OR] + ); $assertionContainer->expects($this->once())->method('get')->with('fooFactory')->willReturn($fooAssertion); @@ -239,10 +245,10 @@ private function assertionsCalled(array $assertions, array $assertionCalledCount { unset($assertions['condition']); foreach ($assertions as $key => $assertion) { + /** @var array|SimpleAssertion $assertion */ if (is_array($assertion)) { $this->assertionsCalled($assertion, $assertionCalledCount[$key]); } else { - /** @var SimpleAssertion $assertion */ $this->assertSame($assertionCalledCount[$key], $assertion->calledTimes()); } } @@ -263,13 +269,39 @@ public static function dpMatrix(): array [['condition' => AssertionSet::CONDITION_OR, new SimpleAssertion(true)], true, [1]], // break early for AND condition with failure - [['condition' => AssertionSet::CONDITION_AND, new SimpleAssertion(false), new SimpleAssertion(false)], false, [1, 0]], + [ + [ + 'condition' => AssertionSet::CONDITION_AND, + new SimpleAssertion(false), + new SimpleAssertion(false), + ], + false, + [1, 0], + ], // break early for OR condition with success - [['condition' => AssertionSet::CONDITION_OR, new SimpleAssertion(true), new SimpleAssertion(false)], true, [1, 0]], + [ + [ + 'condition' => AssertionSet::CONDITION_OR, + new SimpleAssertion(true), + new SimpleAssertion(false), + ], + true, + [1, 0], + ], // nested assertions - [['condition' => AssertionSet::CONDITION_OR, new SimpleAssertion(false), [new SimpleAssertion(true)]], true, [1, [1]]], + [ + [ + 'condition' => AssertionSet::CONDITION_OR, + new SimpleAssertion(false), + [ + new SimpleAssertion(true), + ], + ], + true, + [1, [1]], + ], ]; } } diff --git a/test/Asset/DummyAuthorizationServiceClass.php b/test/Asset/DummyAuthorizationServiceClass.php index 88111fd..b7de24c 100644 --- a/test/Asset/DummyAuthorizationServiceClass.php +++ b/test/Asset/DummyAuthorizationServiceClass.php @@ -1,4 +1,5 @@ willAssert = $willAssert; } - public function assert(string $permission, ?IdentityInterface $identity = null, $context = null): bool + public function assert(string $permission, ?IdentityInterface $identity = null, mixed $context = null): bool { $this->called++; diff --git a/test/Options/ModuleOptionsFactoryTest.php b/test/Options/ModuleOptionsFactoryTest.php index 6b5fb51..1a12cb9 100644 --- a/test/Options/ModuleOptionsFactoryTest.php +++ b/test/Options/ModuleOptionsFactoryTest.php @@ -43,9 +43,10 @@ public function testFactory(): void $this->assertInstanceOf(ModuleOptions::class, $options); } + public function testNoConfig(): void { - $factory = new ModuleOptionsFactory(); + $factory = new ModuleOptionsFactory(); $serviceManager = new ServiceManager(); $config = []; diff --git a/test/Role/ObjectRepositoryRoleProviderFactoryTest.php b/test/Role/ObjectRepositoryRoleProviderFactoryTest.php index 0fb220a..c10e11f 100644 --- a/test/Role/ObjectRepositoryRoleProviderFactoryTest.php +++ b/test/Role/ObjectRepositoryRoleProviderFactoryTest.php @@ -93,14 +93,16 @@ public function testThrowExceptionIfNoRoleNamePropertyIsSet(): void } /** - * This is required due to the fact that the ServiceManager catches ALL exceptions and throws it's own... + * This is required due to the fact that the ServiceManager catches ALL exceptions and throws its own... */ public function testThrowExceptionIfNoObjectManagerNorObjectRepositoryIsSet(): void { $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('No object repository was found while creating the LmcRbac object repository role provider. Are - you sure you specified either the "object_repository" option or "object_manager"/"class_name" options?'); - + /* + $this->expectExceptionMessage('No object repository was found while creating the LmcRbac object repository + role provider. Are you sure you specified either the "object_repository" option or + "object_manager"/"class_name" options?'); + */ $container = new ServiceManager(); $container->setService(ModuleOptions::class, new ModuleOptions([ 'role_provider' => [ diff --git a/test/Service/AuthorizationServiceAwareTraitTest.php b/test/Service/AuthorizationServiceAwareTraitTest.php index b0b2312..32e9cdb 100644 --- a/test/Service/AuthorizationServiceAwareTraitTest.php +++ b/test/Service/AuthorizationServiceAwareTraitTest.php @@ -1,4 +1,5 @@ prophesize(ContainerInterface::class); $container->get(ModuleOptions::class)->willReturn(new ModuleOptions([])); $container->get(RoleServiceInterface::class)->willReturn($this->createMock(RoleServiceInterface::class)); - $container->get(AssertionPluginManagerInterface::class)->willReturn($this->createMock(AssertionPluginManager::class)); + $container->get(AssertionPluginManagerInterface::class) + ->willReturn($this->createMock(AssertionPluginManager::class)); $container->get(Rbac::class)->willReturn(new Rbac()); $factory = new AuthorizationServiceFactory(); diff --git a/test/Service/AuthorizationServiceTest.php b/test/Service/AuthorizationServiceTest.php index 3bb7014..696adc3 100644 --- a/test/Service/AuthorizationServiceTest.php +++ b/test/Service/AuthorizationServiceTest.php @@ -38,6 +38,7 @@ use LmcTest\Rbac\Asset\SimpleAssertion; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\TestCase; use stdClass; @@ -159,8 +160,13 @@ public static function grantedProvider(): array } #[DataProvider('grantedProvider')] - public function testGranted($role, $permission, $context, bool $isGranted, array $assertions = []): void - { + public function testGranted( + string|array $role, + string $permission, + bool|null $context, + bool $isGranted, + array $assertions = [] + ): void { $roleConfig = [ 'admin' => [ 'children' => ['member'], @@ -185,7 +191,12 @@ public function testGranted($role, $permission, $context, bool $isGranted, array $identity = new Identity((array) $role); $roleService = new RoleService(new InMemoryRoleProvider($roleConfig), 'guest'); $assertionPluginManager = new AssertionPluginManager(new ServiceManager(), $assertionPluginConfig); - $authorizationService = new AuthorizationService(new Rbac(), $roleService, $assertionPluginManager, $assertions); + $authorizationService = new AuthorizationService( + new Rbac(), + $roleService, + $assertionPluginManager, + $assertions + ); $this->assertEquals($isGranted, $authorizationService->isGranted($identity, $permission, $context)); } @@ -258,7 +269,12 @@ public function testUsesAssertionsAsInstances(): void $assertionPluginManager = $this->getMockBuilder(AssertionPluginManagerInterface::class)->getMock(); $assertionPluginManager->expects($this->never())->method('get'); - $authorizationService = new AuthorizationService($rbac, $roleService, $assertionPluginManager, ['foo' => $assertion]); + $authorizationService = new AuthorizationService( + $rbac, + $roleService, + $assertionPluginManager, + ['foo' => $assertion] + ); $authorizationService->isGranted($identity, 'foo', 'foo'); @@ -278,9 +294,15 @@ public function testUsesAssertionsAsStrings(): void $rbac->expects($this->once())->method('isGranted')->willReturn(true); $assertionPluginManager = $this->getMockBuilder(AssertionPluginManagerInterface::class)->getMock(); - $assertionPluginManager->expects($this->once())->method('get')->with('fooFactory')->willReturn($assertion); + $assertionPluginManager->expects($this->once()) + ->method('get')->with('fooFactory')->willReturn($assertion); - $authorizationService = new AuthorizationService($rbac, $roleService, $assertionPluginManager, ['foo' => 'fooFactory']); + $authorizationService = new AuthorizationService( + $rbac, + $roleService, + $assertionPluginManager, + ['foo' => 'fooFactory'] + ); $authorizationService->isGranted($identity, 'foo', 'foo'); @@ -369,14 +391,26 @@ public function testThrowExceptionForInvalidAssertion(): void $roleService = $this->getMockBuilder(RoleServiceInterface::class)->getMock(); $roleService->expects($this->once())->method('getIdentityRoles')->willreturn([$role]); - $assertionPluginManager = $this->getMockBuilder(AssertionPluginManagerInterface::class)->disableOriginalConstructor()->getMock(); - $authorizationService = new AuthorizationService($rbac, $roleService, $assertionPluginManager, ['foo' => new stdClass()]); + $assertionPluginManager = $this->getMockBuilder(AssertionPluginManagerInterface::class) + ->disableOriginalConstructor()->getMock(); + /** + * @psalm-suppress InvalidArgument + */ + $authorizationService = new AuthorizationService( + $rbac, + $roleService, + $assertionPluginManager, + ['foo' => new stdClass()] + ); $this->expectException(InvalidArgumentException::class); $authorizationService->isGranted(new Identity(), 'foo', 'foo'); } + /** + * @throws Exception + */ public function testContextIsPassedToRoleService(): void { $identity = new Identity([]); @@ -391,6 +425,9 @@ public function testContextIsPassedToRoleService(): void $authorizationService->isGranted($identity, 'foo', $context); } + /** + * @throws Exception + */ public function testGetAssertions(): void { $assertions = [ @@ -402,6 +439,9 @@ public function testGetAssertions(): void $this->assertNull($authorizationService->getAssertion('bar')); } + /** + * @throws Exception + */ public function testHasAssertion(): void { $assertions = [ @@ -412,6 +452,9 @@ public function testHasAssertion(): void $this->assertFalse($authorizationService->hasAssertion('bar')); } + /** + * @throws Exception + */ public function testSetAssertions(): void { $assertions = [ @@ -435,8 +478,14 @@ public function testSetAssertions(): void $this->assertEquals('foo', $authorizationService->getAssertion('bar')); } + /** + * @throws Exception + */ private function createAuthorizationService(array $assertions): AuthorizationService { + /** + * @psalm-suppress MixedArgumentTypeCoercion + */ return new AuthorizationService( $this->createMock(Rbac::class), $this->createMock(RoleServiceInterface::class), diff --git a/test/Service/RoleServiceFactoryTest.php b/test/Service/RoleServiceFactoryTest.php index 483237f..489b9e7 100644 --- a/test/Service/RoleServiceFactoryTest.php +++ b/test/Service/RoleServiceFactoryTest.php @@ -53,7 +53,7 @@ public function testCanCreateRoleService(): void ]); $factory = new RoleServiceFactory(); - $roleService = $factory($container, RoleService::class); + $roleService = $factory($container); $this->assertInstanceOf(RoleService::class, $roleService); }