diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 576f015..64d2f5e 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -25,4 +25,8 @@ jobs: - name: Run PHPCodeSniffer if: always() - run: phpcs -q --report=checkstyle cli src | cs2pr \ No newline at end of file + run: phpcs -q --report=checkstyle cli src | cs2pr + + - name: Run PHPArkitect + if: always() + run: vendor/bin/phparkitect check --format=json \ No newline at end of file diff --git a/composer.json b/composer.json index e7f5d9c..6de01c2 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,8 @@ "pdepend/pdepend": "3.x-dev", "phpbench/phpbench": "^1.4", "vincentlanglet/twig-cs-fixer": "^3.8", - "bmitch/churn-php": "^1.7" + "bmitch/churn-php": "^1.7", + "phparkitect/phparkitect": "^0.7.0" }, "extra": { "hooks": { @@ -69,12 +70,13 @@ } }, "scripts": { - "check-code": ["@phpcs", "@phpstan"], + "check-code": ["@phpcs", "@phpstan", "@phparkitect"], "phpmd": "vendor/bin/phpmd --ignore-violations-on-exit --ignore-errors-on-exit src text phpmd.xml" , "phpstan": "vendor/bin/phpstan --memory-limit=1G", "phpcs": "vendor/bin/phpcs", "phpcbf": "vendor/bin/phpcbf", "churn": "vendor/bin/churn", + "phparkitect": "vendor/bin/phparkitect check", "twig-lint": "vendor/bin/twig-cs-fixer lint templates", "twig-lint-fix": "vendor/bin/twig-cs-fixer lint --fix templates" } diff --git a/composer.lock b/composer.lock index 7fa6ba7..566beac 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": "21433aee69f8d237547fe291686190d2", + "content-hash": "e54a3ca0273d9c2622b32f13b2f95a94", "packages": [ { "name": "cuyz/valinor", @@ -3241,6 +3241,84 @@ ], "time": "2024-02-05T11:56:58+00:00" }, + { + "name": "ondram/ci-detector", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/OndraM/ci-detector.git", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OndraM/ci-detector/zipball/8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.13.2", + "lmc/coding-standard": "^3.0.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^9.6.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "OndraM\\CiDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Machulda", + "email": "ondrej.machulda@gmail.com" + } + ], + "description": "Detect continuous integration environment and provide unified access to properties of current build", + "keywords": [ + "CircleCI", + "Codeship", + "Wercker", + "adapter", + "appveyor", + "aws", + "aws codebuild", + "azure", + "azure devops", + "azure pipelines", + "bamboo", + "bitbucket", + "buddy", + "ci-info", + "codebuild", + "continuous integration", + "continuousphp", + "devops", + "drone", + "github", + "gitlab", + "interface", + "jenkins", + "pipelines", + "sourcehut", + "teamcity", + "travis" + ], + "support": { + "issues": "https://github.com/OndraM/ci-detector/issues", + "source": "https://github.com/OndraM/ci-detector/tree/4.2.0" + }, + "time": "2024-03-12T13:22:30+00:00" + }, { "name": "pdepend/pdepend", "version": "3.x-dev", @@ -3310,6 +3388,89 @@ ], "time": "2025-12-06T17:47:53+00:00" }, + { + "name": "phparkitect/phparkitect", + "version": "0.7.0", + "source": { + "type": "git", + "url": "https://github.com/phparkitect/arkitect.git", + "reference": "f6e11f5581f0772c2c4532cda263409965f441af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phparkitect/arkitect/zipball/f6e11f5581f0772c2c4532cda263409965f441af", + "reference": "f6e11f5581f0772c2c4532cda263409965f441af", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/php-parser": "~5", + "ondram/ci-detector": "^4.2", + "php": "^7.4|^8", + "phpstan/phpdoc-parser": "^1.2|^2.0", + "symfony/console": "^3.0|^4.0|^5.0|^6.0|^7.0|^8.0", + "symfony/event-dispatcher": "^3.0|^4.0|^5.0|^6.0|^7.0|^8.0", + "symfony/finder": "^3.0|^4.0|^5.0|^6.0|^7.0|^8.0", + "symfony/polyfill-php80": "^1.33", + "webmozart/assert": "^1.9" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.90", + "mikey179/vfsstream": "^1.6", + "phpspec/prophecy": "^1.10", + "phpspec/prophecy-phpunit": "^2.4", + "phpunit/phpunit": "^7.5|^9.0|^10.0", + "roave/security-advisories": "dev-master", + "symfony/var-dumper": "^3.0|^4.0|^5.0|^6.0|^7.0|^8.0" + }, + "bin": [ + "bin-stub/phparkitect" + ], + "type": "library", + "autoload": { + "psr-4": { + "Arkitect\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pietro Campagnano", + "email": "hello@pietro.camp" + }, + { + "name": "Patrick Luca Fazzi", + "email": "patrick91@live.it" + }, + { + "name": "Alessandro Minoccheri", + "email": "alessandro.minoccheri@gmail.com" + }, + { + "name": "Michele Orselli", + "email": "michele.orselli@gmail.com" + } + ], + "description": "Enforce architectural constraints in your PHP applications", + "support": { + "issues": "https://github.com/phparkitect/arkitect/issues", + "source": "https://github.com/phparkitect/arkitect/tree/0.7.0" + }, + "funding": [ + { + "url": "https://github.com/AlessandroMinoccheri", + "type": "github" + }, + { + "url": "https://github.com/micheleorselli", + "type": "github" + } + ], + "time": "2025-12-02T09:53:25+00:00" + }, { "name": "phpbench/container", "version": "2.2.3", @@ -3546,6 +3707,53 @@ ], "time": "2025-12-07T10:56:53+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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/2.3.0" + }, + "time": "2025-08-30T15:50:23+00:00" + }, { "name": "phpstan/phpstan", "version": "2.1.33", @@ -3599,6 +3807,56 @@ ], "time": "2025-12-05T10:24:31+00:00" }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, { "name": "seld/jsonlint", "version": "1.11.0", @@ -3823,16 +4081,16 @@ }, { "name": "symfony/console", - "version": "v7.4.1", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e" + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", - "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e", + "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6", + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6", "shasum": "" }, "require": { @@ -3897,7 +4155,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.1" + "source": "https://github.com/symfony/console/tree/v7.4.3" }, "funding": [ { @@ -3917,7 +4175,7 @@ "type": "tidelift" } ], - "time": "2025-12-05T15:23:39+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/dependency-injection", @@ -4003,6 +4261,167 @@ ], "time": "2025-12-08T06:57:04+00:00" }, + { + "name": "symfony/event-dispatcher", + "version": "v8.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "573f95783a2ec6e38752979db139f09fec033f03" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03", + "reference": "573f95783a2ec6e38752979db139f09fec033f03", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/security-http": "<7.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-10-30T14:17:19+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, { "name": "symfony/filesystem", "version": "v7.4.0", @@ -4075,23 +4494,23 @@ }, { "name": "symfony/finder", - "version": "v7.4.0", + "version": "v8.0.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" + "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", + "url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12", + "reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=8.4" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0|^8.0" + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4119,7 +4538,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.0" + "source": "https://github.com/symfony/finder/tree/v8.0.3" }, "funding": [ { @@ -4139,7 +4558,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T05:42:40+00:00" + "time": "2025-12-23T14:52:06+00:00" }, { "name": "symfony/options-resolver", @@ -4446,35 +4865,34 @@ }, { "name": "symfony/string", - "version": "v7.4.0", + "version": "v8.0.1", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003" + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003", - "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003", + "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc", + "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.33", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0" + "symfony/var-exporter": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -4513,7 +4931,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.0" + "source": "https://github.com/symfony/string/tree/v8.0.1" }, "funding": [ { @@ -4533,7 +4951,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2025-12-01T09:13:36+00:00" }, { "name": "symfony/yaml", @@ -4799,9 +5217,9 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "pdepend/pdepend": 20, + "roave/better-reflection": 20, "phpmd/phpmd": 20, - "roave/better-reflection": 20 + "pdepend/pdepend": 20 }, "prefer-stable": false, "prefer-lowest": false, @@ -4811,6 +5229,6 @@ "ext-curl": "*", "ext-apcu": "*" }, - "platform-dev": {}, - "plugin-api-version": "2.9.0" + "platform-dev": [], + "plugin-api-version": "2.3.0" } diff --git a/phparkitect.php b/phparkitect.php new file mode 100644 index 0000000..34ff82c --- /dev/null +++ b/phparkitect.php @@ -0,0 +1,58 @@ +that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Controller')) + ->should(new HaveNameMatching('*Controller')) + ->because('we want uniform naming for controllers'); + + /* API Client Rules */ + $rules[] = Rule::allClasses() + ->that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Client')) + ->should(new IsA('Phparch\SpaceTraders\Client')) + ->because('we want to ensure clients behave consistently.'); + + /* Interface Rules */ + $rules[] = Rule::allClasses() + ->that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Interface')) + ->should(new IsInterface()) + ->because('we want only intefaces in this namespace.'); + + /* Middleware Rules */ + $rules[] = Rule::allClasses() + ->that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Middleware')) + ->should(new IsA('Psr\Http\Server\MiddlewareInterface')) + ->because('we want middleware classes to implement the PSR interface.'); + + + /* Traits Rules */ + $rules[] = Rule::allClasses() + ->that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Trait')) + ->should(new IsTrait()) + ->because('we want to be sure that there are only traits in a specific namespace'); + + /* Value Object Rules */ + $rules[] = Rule::allClasses() + ->that(new ResideInOneOfTheseNamespaces('Phparch\SpaceTraders\Value')) + ->should(new DependsOnlyOnTheseNamespaces(['Phparch\SpaceTraders\Value'], [])) + ->because('we want to protect our domain from external dependencies except for Ramsey\Uuid'); + + + $config->add($classSet, ...$rules); +}; \ No newline at end of file diff --git a/src/Middleware/Auth.php b/src/Middleware/Auth.php index 7646acf..fbf0b12 100644 --- a/src/Middleware/Auth.php +++ b/src/Middleware/Auth.php @@ -3,7 +3,6 @@ namespace Phparch\SpaceTraders\Middleware; use Lcobucci\JWT\Token\InvalidTokenStructure; -use Phparch\SpaceTraders\APIException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface;