From 41a984950fdf706c82ef9b9688061098d5cbdd5a Mon Sep 17 00:00:00 2001 From: myrmidex Date: Mon, 15 Jun 2026 01:11:08 +0200 Subject: [PATCH] 29 - Add PHPStan --- .gitignore | 4 + composer.json | 5 + composer.lock | 269 +++++++++++++++++++++++++++++++++++++++++++- phpstan.dist.neon | 21 ++++ shell.nix | 7 ++ symfony.lock | 12 ++ tests/SmokeTest.php | 13 --- 7 files changed, 315 insertions(+), 16 deletions(-) create mode 100644 phpstan.dist.neon delete mode 100644 tests/SmokeTest.php diff --git a/.gitignore b/.gitignore index cbf1875..e4f0cf3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ /phpunit.xml /.phpunit.cache/ ###< phpunit/phpunit ### + +###> phpstan/phpstan ### +phpstan.neon +###< phpstan/phpstan ### diff --git a/composer.json b/composer.json index db98f69..2f1969c 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "config": { "allow-plugins": { "php-http/discovery": true, + "phpstan/extension-installer": true, "symfony/flex": true, "symfony/runtime": true }, @@ -84,6 +85,10 @@ } }, "require-dev": { + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.2", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^13.2", "symfony/browser-kit": "8.1.*", "symfony/css-selector": "8.1.*" diff --git a/composer.lock b/composer.lock index e16a392..833dce0 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": "3e0ffab72ea120c62b0ba58b8ce99057", + "content-hash": "dd13115e337fffb1a13b9512d8bc2821", "packages": [ { "name": "api-platform/doctrine-common", @@ -7624,6 +7624,269 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.2.2", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-06-05T09:00:01+00:00" + }, + { + "name": "phpstan/phpstan-doctrine", + "version": "2.0.27", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-doctrine.git", + "reference": "39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f", + "reference": "39b4ca45a07cdd6366eeefa2f7a993cddf3b9f9f", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.2.2" + }, + "conflict": { + "doctrine/collections": "<1.0", + "doctrine/common": "<2.7", + "doctrine/mongodb-odm": "<1.2", + "doctrine/orm": "<2.5", + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "cache/array-adapter": "^1.1", + "composer/semver": "^3.3.2", + "cweagans/composer-patches": "^1.7.3", + "doctrine/annotations": "^2.0", + "doctrine/collections": "^1.6 || ^2.1", + "doctrine/common": "^2.7 || ^3.0", + "doctrine/dbal": "^3.3.8", + "doctrine/lexer": "^2.0 || ^3.0", + "doctrine/mongodb-odm": "^2.4.3", + "doctrine/orm": "^2.16.0", + "doctrine/persistence": "^2.2.1 || ^3.4.3", + "gedmo/doctrine-extensions": "^3.8", + "nesbot/carbon": "^2.49", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0.2", + "phpstan/phpstan-phpunit": "^2.0.8", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6.20", + "ramsey/uuid": "^4.2", + "shipmonk/name-collision-detector": "^2.1", + "symfony/cache": "^5.4", + "symfony/uid": "^5.4 || ^6.4 || ^7.3" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Doctrine extensions for PHPStan", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan-doctrine/issues", + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.27" + }, + "time": "2026-06-10T10:39:35+00:00" + }, + { + "name": "phpstan/phpstan-symfony", + "version": "2.0.19", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-symfony.git", + "reference": "546071ed7f80a89ec30909346eb7cc741800740a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/546071ed7f80a89ec30909346eb7cc741800740a", + "reference": "546071ed7f80a89ec30909346eb7cc741800740a", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.13" + }, + "conflict": { + "symfony/framework-bundle": "<3.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-phpunit": "^2.0.8", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "psr/container": "1.1.2", + "symfony/config": "^5.4 || ^6.1", + "symfony/console": "^5.4 || ^6.1", + "symfony/dependency-injection": "^5.4 || ^6.1", + "symfony/form": "^5.4 || ^6.1", + "symfony/framework-bundle": "^5.4 || ^6.1", + "symfony/http-foundation": "^5.4 || ^6.1", + "symfony/messenger": "^5.4", + "symfony/polyfill-php80": "^1.24", + "symfony/serializer": "^5.4", + "symfony/service-contracts": "^2.2.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lukáš Unger", + "email": "looky.msc@gmail.com", + "homepage": "https://lookyman.net" + } + ], + "description": "Symfony Framework extensions and rules for PHPStan", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan-symfony/issues", + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.19" + }, + "time": "2026-05-29T12:52:44+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "14.2.2", @@ -9522,7 +9785,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { @@ -9530,6 +9793,6 @@ "ext-ctype": "*", "ext-iconv": "*" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.9.0" } diff --git a/phpstan.dist.neon b/phpstan.dist.neon new file mode 100644 index 0000000..7e7d31c --- /dev/null +++ b/phpstan.dist.neon @@ -0,0 +1,21 @@ +parameters: + level: 6 + paths: + - bin/ + - config/ + - public/ + - src/ + - tests/ + # phpstan-symfony: point at the compiled dev container so it understands service wiring. + # Requires the dev cache to be warm (php bin/console cache:warmup). + symfony: + containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml + ignoreErrors: + # Framework-generated Kernel: getAllowedEnvs() is called via reflection by Symfony, + # so PHPStan can't see the usage. Scoped to this one file/message (not a global pattern). + - + message: '#Method App\\Kernel::getAllowedEnvs\(\) is unused\.#' + path: src/Kernel.php + # Recipe-generated test bootstrap — not our code to lint. + excludePaths: + - tests/bootstrap.php diff --git a/shell.nix b/shell.nix index 4d34722..5bae4b8 100644 --- a/shell.nix +++ b/shell.nix @@ -103,6 +103,12 @@ pkgs.mkShell { $COMPOSE exec php php bin/phpunit "$@" } + dev-stan() { + # Warm the dev cache so phpstan-symfony can read the compiled container, then analyse. + $COMPOSE exec php php bin/console cache:warmup --quiet + $COMPOSE exec php vendor/bin/phpstan analyse --memory-limit=512M "$@" + } + # =================== # BUILD COMMANDS # =================== @@ -155,6 +161,7 @@ pkgs.mkShell { echo " dev-console Run Symfony console command" echo " dev-composer Run composer in the container" echo " dev-test [args] Run PHPUnit (bin/phpunit)" + echo " dev-stan [args] Run PHPStan static analysis" echo " base-build Build and push image" echo "" echo "Services:" diff --git a/symfony.lock b/symfony.lock index b8e29e0..ccf5cb7 100644 --- a/symfony.lock +++ b/symfony.lock @@ -61,6 +61,18 @@ "config/packages/nelmio_cors.yaml" ] }, + "phpstan/phpstan": { + "version": "2.2", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + }, + "files": [ + "phpstan.dist.neon" + ] + }, "phpunit/phpunit": { "version": "13.2", "recipe": { diff --git a/tests/SmokeTest.php b/tests/SmokeTest.php deleted file mode 100644 index 5d9a88d..0000000 --- a/tests/SmokeTest.php +++ /dev/null @@ -1,13 +0,0 @@ -