From c5e7ad3e4129135ae0886f366e759a8610f67131 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 5 Nov 2025 13:04:23 +0100 Subject: [PATCH 01/26] Add Symfony 8 Support --- .github/workflows/build.yaml | 8 ++++++++ composer.json | 14 +++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 775c61c..783baed 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -162,6 +162,10 @@ jobs: exclude: - php-version: "8.1" symfony: "^7.0" + include: + - php-version: '8.4' + symfony: '^8.0.0-BETA-1' + composer-minimum-stability: beta steps: - name: "Checkout" @@ -175,6 +179,10 @@ jobs: coverage: "none" tools: "flex" + - name: "Configure Composer minimum stability" + if: matrix.composer-minimum-stability != '' + run: composer config minimum-stability ${{ matrix.composer-minimum-stability }} + - name: "Install composer dependencies" uses: "ramsey/composer-install@v3" env: diff --git a/composer.json b/composer.json index d0d6bec..e9f0681 100644 --- a/composer.json +++ b/composer.json @@ -14,15 +14,15 @@ "doctrine/dbal": "^3.4 || ^4.0", "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", - "symfony/config": "^5.4 || ^6.0 || ^7.0", - "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", - "symfony/form": "^5.4 || ^6.0 || ^7.0", - "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", + "symfony/config": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0 || 8.0", "symfony/polyfill-php83": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/property-info": "^5.4 || ^6.0 || ^7.0", - "symfony/validator": "^5.4 || ^6.0 || ^7.0" + "symfony/property-info": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0 || 8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.42", From 88c1f42c34994d65b98a6cf1f752dc0147a2a2c1 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 5 Nov 2025 13:32:32 +0100 Subject: [PATCH 02/26] ~ fix ^8.0 expr --- composer.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index e9f0681..3074ccc 100644 --- a/composer.json +++ b/composer.json @@ -12,17 +12,17 @@ "require": { "php": ">=8.1", "doctrine/dbal": "^3.4 || ^4.0", - "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0", + "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0 || ^4.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", - "symfony/config": "^5.4 || ^6.0 || ^7.0 || 8.0", - "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0 || 8.0", - "symfony/form": "^5.4 || ^6.0 || ^7.0 || 8.0", - "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || 8.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0 || 8.0", + "symfony/config": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0 || ^8.0", "symfony/polyfill-php83": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/property-info": "^5.4 || ^6.0 || ^7.0 || 8.0", - "symfony/validator": "^5.4 || ^6.0 || ^7.0 || 8.0" + "symfony/property-info": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.42", From c0642fede88f2efedd72d8ec29814dd6c21a07fb Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 5 Nov 2025 13:35:15 +0100 Subject: [PATCH 03/26] fix code-style --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3074ccc..ac17133 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ "dragonmantank/cron-expression": "^2.2 || ^3.0", "symfony/config": "^5.4 || ^6.0 || ^7.0 || ^8.0", "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/form": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || ^8.0", "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0 || ^8.0", "symfony/polyfill-php83": "^1.33", "symfony/polyfill-php84": "^1.33", From c29b03f091b91e3d410fb4ff145c5a531e3c9da9 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Thu, 27 Nov 2025 10:07:45 +0100 Subject: [PATCH 04/26] Update build.yaml 8.0 released --- .github/workflows/build.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 783baed..e8449f4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -164,8 +164,7 @@ jobs: symfony: "^7.0" include: - php-version: '8.4' - symfony: '^8.0.0-BETA-1' - composer-minimum-stability: beta + symfony: '^8.0.0' steps: - name: "Checkout" @@ -179,10 +178,6 @@ jobs: coverage: "none" tools: "flex" - - name: "Configure Composer minimum stability" - if: matrix.composer-minimum-stability != '' - run: composer config minimum-stability ${{ matrix.composer-minimum-stability }} - - name: "Install composer dependencies" uses: "ramsey/composer-install@v3" env: From 2eb12d7acea14c0f3baf11d41ff6f05236e63f09 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 09:55:29 +0100 Subject: [PATCH 05/26] remove psalm --- composer.json | 1 - psalm.xml | 51 ------------------- .../DBAL/Types/CronExpressionType.php | 6 --- .../CronExpressionToPartsTransformer.php | 5 -- ...CronExpressionToStringPartsTransformer.php | 5 -- .../CronExpressionToStringTransformer.php | 2 - .../TypeGuesser/CronExpressionTypeGuesser.php | 10 ---- 7 files changed, 80 deletions(-) delete mode 100644 psalm.xml diff --git a/composer.json b/composer.json index ac17133..8fe11b0 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,6 @@ "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0 || ^6.0", "phpdocumentor/reflection-docblock": "^5.3", "phpunit/phpunit": "^9.5 || ^12.0", - "psalm/plugin-phpunit": "^0.19", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index 883f428..0000000 --- a/psalm.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Doctrine/DBAL/Types/CronExpressionType.php b/src/Doctrine/DBAL/Types/CronExpressionType.php index c5b5f17..1aa0576 100644 --- a/src/Doctrine/DBAL/Types/CronExpressionType.php +++ b/src/Doctrine/DBAL/Types/CronExpressionType.php @@ -34,9 +34,6 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?CronExpr } if (!is_string($value)) { - /** - * @psalm-suppress UndefinedMethod - */ throw class_exists(InvalidType::class) ? InvalidType::new($value, CronExpression::class, ['string']) : ConversionException::conversionFailedInvalidType($value, CronExpression::class, ['string']); } @@ -47,9 +44,6 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?CronExpr try { return CronExpression::factory($value); } catch (\Throwable $e) { - /** - * @psalm-suppress UndefinedMethod - */ throw class_exists(ValueNotConvertible::class) ? ValueNotConvertible::new($value, CronExpression::class, null, $e) : ConversionException::conversionFailed($value, CronExpression::class, $e); } } diff --git a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php index 9a87d29..01c5326 100644 --- a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php @@ -10,8 +10,6 @@ /** * @template-implements DataTransformerInterface>> - * - * @psalm-suppress TooManyTemplateParams */ final class CronExpressionToPartsTransformer implements DataTransformerInterface { @@ -87,9 +85,6 @@ public function reverseTransform($value): CronExpression } } - /** - * @psalm-assert array> $value - */ private static function allArrayScalar(array $value): bool { return array_all($value, fn (mixed $s) => is_array($s) && array_all($s, fn (mixed $o) => is_scalar($o))); diff --git a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php index 20605fe..8ba158e 100644 --- a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php @@ -10,8 +10,6 @@ /** * @template-implements DataTransformerInterface> - * - * @psalm-suppress TooManyTemplateParams */ final class CronExpressionToStringPartsTransformer implements DataTransformerInterface { @@ -87,9 +85,6 @@ public function reverseTransform($value): CronExpression return $cronExpression; } - /** - * @psalm-assert iterable $value - */ private static function allString(array $value): bool { return array_all($value, fn (mixed $s) => is_string($s)); diff --git a/src/Form/DataTransformer/CronExpressionToStringTransformer.php b/src/Form/DataTransformer/CronExpressionToStringTransformer.php index fb0f954..4fdd10e 100644 --- a/src/Form/DataTransformer/CronExpressionToStringTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToStringTransformer.php @@ -10,8 +10,6 @@ /** * @template-implements DataTransformerInterface - * - * @psalm-suppress TooManyTemplateParams */ final class CronExpressionToStringTransformer implements DataTransformerInterface { diff --git a/src/Form/TypeGuesser/CronExpressionTypeGuesser.php b/src/Form/TypeGuesser/CronExpressionTypeGuesser.php index 1ef2ab5..7c6b653 100644 --- a/src/Form/TypeGuesser/CronExpressionTypeGuesser.php +++ b/src/Form/TypeGuesser/CronExpressionTypeGuesser.php @@ -93,9 +93,6 @@ private function createExtractor(): PropertyTypeExtractorInterface private function isCronExpression(string $class, string $property): bool { if (class_exists(Type::class) && method_exists($this->extractor, 'getType')) { - /** - * @psalm-suppress MixedAssignment - */ $type = $this->extractor->getType($class, $property); if (null === $type) { return false; @@ -104,18 +101,11 @@ private function isCronExpression(string $class, string $property): bool return true; } } else { - /** - * @psalm-suppress DeprecatedClass - * @psalm-suppress DeprecatedMethod - */ $types = $this->extractor->getTypes($class, $property); if (null === $types) { return false; } foreach ($types as $lType) { - /** - * @psalm-suppress DeprecatedClass - */ if (LegacyType::BUILTIN_TYPE_OBJECT === $lType->getBuiltinType() && CronExpression::class === $lType->getClassName()) { return true; From b01a198fc53657b153358334538f516efa3100ca Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 10:02:45 +0100 Subject: [PATCH 06/26] remove psalm --- .github/workflows/build.yaml | 46 ------------------------------------ composer.json | 3 +-- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e8449f4..2f20c23 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -91,52 +91,6 @@ jobs: - name: "Run shipmonk/composer-dependency-analyser" run: "vendor/bin/composer-dependency-analyser" - static-code-analysis: - name: "Static Code Analysis" - - runs-on: "ubuntu-latest" - - strategy: - matrix: - php-version: - - "8.1" - - "8.2" - - "8.3" - - "8.4" - - dependencies: - - "highest" - - symfony: - - "^5.4" - - "^6.0" - - "^7.0" - - exclude: - - php-version: "8.1" - symfony: "^7.0" - steps: - - name: "Checkout" - uses: "actions/checkout@v4" - - - name: "Setup PHP, with composer and extensions" - uses: "shivammathur/setup-php@v2" - with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.PHP_EXTENSIONS }}" - coverage: "none" - tools: "flex" - - - name: "Install composer dependencies" - uses: "ramsey/composer-install@v3" - env: - SYMFONY_REQUIRE: "${{ matrix.symfony }}" - with: - dependency-versions: "${{ matrix.dependencies }}" - - - name: "Static analysis" - run: "vendor/bin/psalm --php-version=${{ matrix.php-version }}" - unit-tests: name: "Unit tests" diff --git a/composer.json b/composer.json index 8fe11b0..ad7dea7 100644 --- a/composer.json +++ b/composer.json @@ -32,8 +32,7 @@ "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", - "symplify/easy-coding-standard": "^12.3.6", - "vimeo/psalm": "^6.0" + "symplify/easy-coding-standard": "^12.3.6" }, "prefer-stable": true, "autoload": { From 0c70866f24eda9dee1416ff370790eb0d8129dc0 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 10:03:45 +0100 Subject: [PATCH 07/26] add phpstan --- .github/workflows/build.yaml | 24 ++++++++++++++++++++++++ composer.json | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2f20c23..df569d1 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -91,6 +91,30 @@ jobs: - name: "Run shipmonk/composer-dependency-analyser" run: "vendor/bin/composer-dependency-analyser" + phpstan: + name: "PHPStan" + + runs-on: "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + + - name: "Install PHP with extensions" + uses: "shivammathur/setup-php@v2" + with: + php-version: '8.4' + coverage: "none" + tools: "composer:v2" + + - name: "Install Composer dependencies (highest)" + uses: "ramsey/composer-install@v3" + with: + dependency-versions: "highest" + + - name: "PHPStan" + run: "vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github" + unit-tests: name: "Unit tests" diff --git a/composer.json b/composer.json index ad7dea7..e5a2e2a 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,12 @@ "ergebnis/composer-normalize": "^2.42", "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0 || ^6.0", "phpdocumentor/reflection-docblock": "^5.3", + "phpstan/extension-installer": "^1.0", + "phpstan/phpdoc-parser": "^1.0", + "phpstan/phpstan": "^1.0 || ^2.0", + "phpstan/phpstan-phpunit": "^1.0 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", + "phpstan/phpstan-symfony": "^1.0 || ^2.0", "phpunit/phpunit": "^9.5 || ^12.0", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", From 499ffd74f57918fc025bdab1c8d7fbaf04c06456 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 10:20:08 +0100 Subject: [PATCH 08/26] ~ update packages --- composer.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index e5a2e2a..5b6f80d 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0 || ^6.0", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/extension-installer": "^1.0", - "phpstan/phpdoc-parser": "^1.0", + "phpstan/phpdoc-parser": "^1.0 || ^2.0", "phpstan/phpstan": "^1.0 || ^2.0", "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", @@ -38,7 +38,7 @@ "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", - "symplify/easy-coding-standard": "^12.3.6" + "symplify/easy-coding-standard": "^12.3.6 || ^13.0.0" }, "prefer-stable": true, "autoload": { @@ -54,7 +54,8 @@ "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": false, - "ergebnis/composer-normalize": true + "ergebnis/composer-normalize": true, + "phpstan/extension-installer": true }, "sort-packages": true }, From 487e2af0f698d456536135c5866163a1ed990364 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 11:42:34 +0100 Subject: [PATCH 09/26] add phpstan and fix errors --- phpstan-baseline.neon | 0 phpstan.neon.dist | 23 +++++++++++++++++ .../SetonoCronExpressionExtension.php | 4 +-- .../DBAL/Types/CronExpressionType.php | 7 +++++- .../CronExpressionToPartsTransformer.php | 4 +++ ...CronExpressionToStringPartsTransformer.php | 4 +++ src/Form/Type/CronExpressionType.php | 10 ++++---- .../TypeGuesser/CronExpressionTypeGuesser.php | 6 +++++ src/Resources/config/services.php | 17 +++++++++++++ src/Resources/config/services.xml | 12 --------- src/Validator/CronExpression.php | 7 +++--- .../DBAL/Types/CronExpressionTypeTest.php | 8 +----- tests/Form/DataTransformer/ToPartsTest.php | 2 +- .../DataTransformer/ToStringPartsTest.php | 2 +- tests/Form/DataTransformer/ToStringTest.php | 2 +- .../Type/CronExpressionTypeCallbackTest.php | 11 ++++---- .../Type/CronExpressionTypeStringTest.php | 13 +++++----- tests/Form/Type/CronExpressionTypeTest.php | 11 +++++--- .../Form/Type/CronExpressionTypeTextTest.php | 25 +++++++++++-------- .../CronExpressionTypeGuesserTest.php | 24 +++++++++--------- tests/Form/TypeGuesser/StubAliased.php | 7 ++++-- tests/Form/TypeGuesser/StubFqcn.php | 5 +++- tests/Form/TypeGuesser/StubImported.php | 5 +++- tests/Form/TypeGuesser/StubWithNoPhpDoc.php | 4 ++- tests/Form/TypeGuesser/StubWithTypeHint.php | 3 +++ tests/Form/TypeGuesser/StubWithWrongType.php | 5 +++- tests/Validator/CronExpressionTest.php | 6 ----- tests/Validator/FormCallbackTest.php | 12 +++------ 28 files changed, 146 insertions(+), 93 deletions(-) create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.neon.dist create mode 100644 src/Resources/config/services.php delete mode 100644 src/Resources/config/services.xml diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..e69de29 diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..239010f --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,23 @@ +includes: + - phpstan-baseline.neon + - vendor/phpstan/phpstan/conf/bleedingEdge.neon + +parameters: + level: 8 + paths: + - src + - tests + scanFiles: + - vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php + treatPhpDocTypesAsCertain: false + checkInternalClassCaseSensitivity: true + checkMissingVarTagTypehint: true + checkMissingTypehints: true + checkUninitializedProperties: true + featureToggles: + skipCheckGenericClasses: + - Symfony\Component\Form\AbstractType + - Symfony\Component\Form\FormBuilderInterface + - Symfony\Component\Form\FormInterface + - Symfony\Component\Form\FormTypeExtensionInterface + - Symfony\Component\Form\FormTypeInterface diff --git a/src/DependencyInjection/SetonoCronExpressionExtension.php b/src/DependencyInjection/SetonoCronExpressionExtension.php index c670ebb..db7b3ba 100644 --- a/src/DependencyInjection/SetonoCronExpressionExtension.php +++ b/src/DependencyInjection/SetonoCronExpressionExtension.php @@ -10,14 +10,14 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; final class SetonoCronExpressionExtension extends Extension implements PrependExtensionInterface { #[\Override] public function load(array $configs, ContainerBuilder $container): void { - $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.xml'); } diff --git a/src/Doctrine/DBAL/Types/CronExpressionType.php b/src/Doctrine/DBAL/Types/CronExpressionType.php index 1aa0576..a55d2cb 100644 --- a/src/Doctrine/DBAL/Types/CronExpressionType.php +++ b/src/Doctrine/DBAL/Types/CronExpressionType.php @@ -34,6 +34,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?CronExpr } if (!is_string($value)) { + /** @phpstan-ignore staticMethod.notFound */ throw class_exists(InvalidType::class) ? InvalidType::new($value, CronExpression::class, ['string']) : ConversionException::conversionFailedInvalidType($value, CronExpression::class, ['string']); } @@ -44,6 +45,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?CronExpr try { return CronExpression::factory($value); } catch (\Throwable $e) { + /** @phpstan-ignore staticMethod.notFound */ throw class_exists(ValueNotConvertible::class) ? ValueNotConvertible::new($value, CronExpression::class, null, $e) : ConversionException::conversionFailed($value, CronExpression::class, $e); } } @@ -66,7 +68,10 @@ public function getName(): string return self::CRON_EXPRESSION_TYPE; } - /** @noinspection PhpUnusedParameterInspection */ + /** + * @noinspection PhpUnusedParameterInspection + * @phpstan-ignore return.tooWideBool + */ public function requiresSQLCommentHint(AbstractPlatform $platform): bool { return true; diff --git a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php index 01c5326..0b4ef98 100644 --- a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php @@ -85,6 +85,10 @@ public function reverseTransform($value): CronExpression } } + /** + * @phpstan-assert array> $value + * @phpstan-ignore missingType.iterableValue + */ private static function allArrayScalar(array $value): bool { return array_all($value, fn (mixed $s) => is_array($s) && array_all($s, fn (mixed $o) => is_scalar($o))); diff --git a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php index 8ba158e..bf0dc94 100644 --- a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php @@ -85,6 +85,10 @@ public function reverseTransform($value): CronExpression return $cronExpression; } + /** + * @phpstan-assert array $value + * @phpstan-ignore missingType.iterableValue + */ private static function allString(array $value): bool { return array_all($value, fn (mixed $s) => is_string($s)); diff --git a/src/Form/Type/CronExpressionType.php b/src/Form/Type/CronExpressionType.php index 1e971d4..1d49ab4 100644 --- a/src/Form/Type/CronExpressionType.php +++ b/src/Form/Type/CronExpressionType.php @@ -136,6 +136,7 @@ public function getBlockPrefix(): string /** * Will create an array where the first key is 1 * oneIndexedRange(3) will return [1 => 1, 2 => 2, 3 => 3]. + * @return array */ private function oneIndexedRange(int $end, int $start = 0): array { @@ -147,11 +148,10 @@ private function oneIndexedRange(int $end, int $start = 0): array protected function buildCallback(int $payload): Callback { - // helper function for Symfony 4.4 - return new Callback([ - 'callback' => [$this, 'validateCronField'], - 'payload' => $payload, - ]); + return new Callback( + callback: $this->validateCronField(...), + payload: $payload, + ); } public function validateCronField(?string $value, ExecutionContextInterface $context, int $payload): void diff --git a/src/Form/TypeGuesser/CronExpressionTypeGuesser.php b/src/Form/TypeGuesser/CronExpressionTypeGuesser.php index 7c6b653..6c5caf4 100644 --- a/src/Form/TypeGuesser/CronExpressionTypeGuesser.php +++ b/src/Form/TypeGuesser/CronExpressionTypeGuesser.php @@ -90,8 +90,12 @@ private function createExtractor(): PropertyTypeExtractorInterface ], [], [], [$reflectionExtractor]); } + /** + * @param class-string $class + */ private function isCronExpression(string $class, string $property): bool { + /** @phpstan-ignore function.alreadyNarrowedType */ if (class_exists(Type::class) && method_exists($this->extractor, 'getType')) { $type = $this->extractor->getType($class, $property); if (null === $type) { @@ -101,11 +105,13 @@ private function isCronExpression(string $class, string $property): bool return true; } } else { + /** @phpstan-ignore method.notFound */ $types = $this->extractor->getTypes($class, $property); if (null === $types) { return false; } foreach ($types as $lType) { + /** @phpstan-ignore class.notFound */ if (LegacyType::BUILTIN_TYPE_OBJECT === $lType->getBuiltinType() && CronExpression::class === $lType->getClassName()) { return true; diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php new file mode 100644 index 0000000..20e26d7 --- /dev/null +++ b/src/Resources/config/services.php @@ -0,0 +1,17 @@ +services(); + + $services->set('setono_cron_expression.form.type_guesser.cron_expression', CronExpressionTypeGuesser::class) + ->args([ + service('property_info'), + ]) + ->tag('form.type_guesser'); +}; diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml deleted file mode 100644 index 41a9a93..0000000 --- a/src/Resources/config/services.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/src/Validator/CronExpression.php b/src/Validator/CronExpression.php index 54d0ecd..f99f247 100644 --- a/src/Validator/CronExpression.php +++ b/src/Validator/CronExpression.php @@ -23,12 +23,11 @@ class CronExpression extends Constraint * @param string[]|null $groups */ public function __construct( - string $message = null, + ?string $message = null, ?array $groups = null, - mixed $payload = null, - array $options = [], + mixed $payload = null ) { - parent::__construct($options, $groups, $payload); + parent::__construct(null, $groups, $payload); $this->message = $message ?? $this->message; } diff --git a/tests/Doctrine/DBAL/Types/CronExpressionTypeTest.php b/tests/Doctrine/DBAL/Types/CronExpressionTypeTest.php index 80d910e..7bd0449 100644 --- a/tests/Doctrine/DBAL/Types/CronExpressionTypeTest.php +++ b/tests/Doctrine/DBAL/Types/CronExpressionTypeTest.php @@ -18,7 +18,7 @@ final class CronExpressionTypeTest extends TestCase { public function testTypeName(): void { - self::assertEquals('cron_expression', $this->getType()->getName()); + self::assertSame('cron_expression', $this->getType()->getName()); } public function testTypeRequiresHint(): void @@ -60,9 +60,6 @@ public function testConvertFaultyTypeToPhpThrowsException(): void { self::expectException(ConversionException::class); if (class_exists(InvalidType::class)) { - /** - * @psalm-suppress InvalidArgument - */ self::expectException(InvalidType::class); } @@ -73,9 +70,6 @@ public function testConvertFaultyStringToPhpThrowsException(): void { self::expectException(ConversionException::class); if (class_exists(ValueNotConvertible::class)) { - /** - * @psalm-suppress InvalidArgument - */ self::expectException(ValueNotConvertible::class); } diff --git a/tests/Form/DataTransformer/ToPartsTest.php b/tests/Form/DataTransformer/ToPartsTest.php index 3087b39..f8321dd 100644 --- a/tests/Form/DataTransformer/ToPartsTest.php +++ b/tests/Form/DataTransformer/ToPartsTest.php @@ -71,6 +71,6 @@ protected function invalidReverseTransform(mixed $value): void protected function expectedReverseTransform(mixed $input, string $expected): void { $transformer = new CronExpressionToPartsTransformer(); - $this->assertSame($expected, $transformer->reverseTransform($input)->getExpression()); + self::assertSame($expected, $transformer->reverseTransform($input)->getExpression()); } } diff --git a/tests/Form/DataTransformer/ToStringPartsTest.php b/tests/Form/DataTransformer/ToStringPartsTest.php index 8310b5a..66c1baa 100644 --- a/tests/Form/DataTransformer/ToStringPartsTest.php +++ b/tests/Form/DataTransformer/ToStringPartsTest.php @@ -60,6 +60,6 @@ protected function invalidReverseTransform(mixed $value): void protected function expectedReverseTransform(mixed $input, string $expected): void { $transformer = new CronExpressionToStringPartsTransformer(); - $this->assertSame($expected, $transformer->reverseTransform($input)->getExpression()); + self::assertSame($expected, $transformer->reverseTransform($input)->getExpression()); } } diff --git a/tests/Form/DataTransformer/ToStringTest.php b/tests/Form/DataTransformer/ToStringTest.php index f78d473..d49864c 100644 --- a/tests/Form/DataTransformer/ToStringTest.php +++ b/tests/Form/DataTransformer/ToStringTest.php @@ -36,6 +36,6 @@ protected function invalidReverseTransform(mixed $value): void protected function expectedReverseTransform(mixed $input, string $expected): void { $transformer = new CronExpressionToStringTransformer(); - $this->assertSame($expected, $transformer->reverseTransform($input)->getExpression()); + self::assertSame($expected, $transformer->reverseTransform($input)->getExpression()); } } diff --git a/tests/Form/Type/CronExpressionTypeCallbackTest.php b/tests/Form/Type/CronExpressionTypeCallbackTest.php index 2ce3cdd..fde7679 100644 --- a/tests/Form/Type/CronExpressionTypeCallbackTest.php +++ b/tests/Form/Type/CronExpressionTypeCallbackTest.php @@ -5,7 +5,6 @@ namespace Setono\CronExpressionBundle\Tests\Form\Type; use Cron\CronExpression; -use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; use PHPUnit\Framework\TestCase; use Setono\CronExpressionBundle\Form\Type\CronExpressionType; use Symfony\Component\Validator\Context\ExecutionContextInterface; @@ -14,23 +13,23 @@ final class CronExpressionTypeCallbackTest extends TestCase { public function testNullNoViolation(): void { - $this->callValidateCronField(null, $this->never()); + $this->callValidateCronField(null, false); } public function testValidNoViolation(): void { - $this->callValidateCronField('59', $this->never()); + $this->callValidateCronField('59', false); } public function testViolationAdded(): void { - $this->callValidateCronField('61', $this->once()); + $this->callValidateCronField('61', true); } - protected function callValidateCronField(?string $value, InvokedCountMatcher $counter): void + protected function callValidateCronField(?string $value, bool $match): void { $mock = $this->createMock(ExecutionContextInterface::class); - $mock->expects($counter)->method('addViolation') + $mock->expects($match ? $this->once() : $this->never())->method('addViolation') ->with('{{value}} is not a valid cron part', ['value' => $value]) ; diff --git a/tests/Form/Type/CronExpressionTypeStringTest.php b/tests/Form/Type/CronExpressionTypeStringTest.php index a06c770..9618a12 100644 --- a/tests/Form/Type/CronExpressionTypeStringTest.php +++ b/tests/Form/Type/CronExpressionTypeStringTest.php @@ -41,13 +41,13 @@ private function _submit(?string $formData, string $expected): void // submit the data to the form directly $form->submit($formData); - $this->assertTrue($form->isSynchronized()); + self::assertTrue($form->isSynchronized()); /** @var CronExpression $cronExpression */ $cronExpression = $form->getData(); - $this->assertInstanceOf(CronExpression::class, $cronExpression); - $this->assertSame($expected, $cronExpression->getExpression()); + self::assertInstanceOf(CronExpression::class, $cronExpression); + self::assertSame($expected, $cronExpression->getExpression()); } public function testSubmitFaultyEmpty(): void @@ -63,9 +63,10 @@ public function testSubmitFaultyArray(): void } /** - * @param string|array|null $formData + * @param array|string|null $formData + * @phpstan-ignore missingType.iterableValue */ - private function _submitFaultyData($formData): void + private function _submitFaultyData(array|string|null $formData): void { $form = $this->factory->create(CronExpressionType::class, null, [ 'widget' => 'single_text', @@ -74,7 +75,7 @@ private function _submitFaultyData($formData): void // submit the data to the form directly $form->submit($formData); - $this->assertFalse($form->isSynchronized()); + self::assertFalse($form->isSynchronized()); } public function testCreateWithFaultyData(): void diff --git a/tests/Form/Type/CronExpressionTypeTest.php b/tests/Form/Type/CronExpressionTypeTest.php index ca8f894..c7ea779 100644 --- a/tests/Form/Type/CronExpressionTypeTest.php +++ b/tests/Form/Type/CronExpressionTypeTest.php @@ -46,6 +46,9 @@ public function testSubmitEmpty(): void $this->_submit([], '* * * * *'); } + /** + * @param array> $formData + */ private function _submit(array $formData, string $expected): void { $form = $this->factory->create(CronExpressionType::class); @@ -53,20 +56,20 @@ private function _submit(array $formData, string $expected): void // submit the data to the form directly $form->submit($formData); - $this->assertTrue($form->isSynchronized()); + self::assertTrue($form->isSynchronized()); $view = $form->createView(); $children = $view->children; foreach (array_keys($formData) as $key) { - $this->assertArrayHasKey($key, $children); + self::assertArrayHasKey($key, $children); } /** @var CronExpression $cronExpression */ $cronExpression = $form->getData(); - $this->assertInstanceOf(CronExpression::class, $cronExpression); - $this->assertSame($expected, $cronExpression->getExpression()); + self::assertInstanceOf(CronExpression::class, $cronExpression); + self::assertSame($expected, $cronExpression->getExpression()); } public function testCreateWithFaultyData(): void diff --git a/tests/Form/Type/CronExpressionTypeTextTest.php b/tests/Form/Type/CronExpressionTypeTextTest.php index a3e47fc..18845fe 100644 --- a/tests/Form/Type/CronExpressionTypeTextTest.php +++ b/tests/Form/Type/CronExpressionTypeTextTest.php @@ -49,6 +49,9 @@ public function testSubmitEmpty(): void $this->_submit([], '* * * * *'); } + /** + * @param array $formData + */ private function _submit(array $formData, string $expected): void { $form = $this->factory->create(CronExpressionType::class, null, [ @@ -58,20 +61,20 @@ private function _submit(array $formData, string $expected): void // submit the data to the form directly $form->submit($formData); - $this->assertTrue($form->isSynchronized()); + self::assertTrue($form->isSynchronized()); $view = $form->createView(); $children = $view->children; foreach (array_keys($formData) as $key) { - $this->assertArrayHasKey($key, $children); + self::assertArrayHasKey($key, $children); } /** @var CronExpression $cronExpression */ $cronExpression = $form->getData(); - $this->assertInstanceOf(CronExpression::class, $cronExpression); - $this->assertSame($expected, $cronExpression->getExpression()); + self::assertInstanceOf(CronExpression::class, $cronExpression); + self::assertSame($expected, $cronExpression->getExpression()); } public function testSubmitFaultyMinutesOnly(): void @@ -82,9 +85,10 @@ public function testSubmitFaultyMinutesOnly(): void } /** - * @param string|array|null $formData + * @param array|string|null $formData + * @phpstan-ignore missingType.iterableValue */ - private function _submitFaultyData($formData): void + private function _submitFaultyData(array|string|null $formData): void { $form = $this->factory->create(CronExpressionType::class, null, [ 'widget' => 'text', @@ -93,7 +97,7 @@ private function _submitFaultyData($formData): void // submit the data to the form directly $form->submit($formData); - $this->assertFalse($form->isSynchronized()); + self::assertFalse($form->isSynchronized()); } public function testCreateWithFaultyData(): void @@ -130,12 +134,11 @@ public function _submitWithChild($formData, string $expected): void $form = $builder->getForm(); $form->submit(['cron' => $formData]); - /** @var array $data */ + /** @var array $data */ $data = $form->getData(); - /** @var CronExpression $cronExpression */ $cronExpression = $data['cron']; - $this->assertInstanceOf(CronExpression::class, $cronExpression); - $this->assertSame($expected, $cronExpression->getExpression()); + self::assertInstanceOf(CronExpression::class, $cronExpression); + self::assertSame($expected, $cronExpression->getExpression()); } } diff --git a/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php b/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php index c09d4ff..664b387 100644 --- a/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php +++ b/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php @@ -22,22 +22,22 @@ public function setUp(): void public function testItReturnsNullIfClassDoesNotExist(): void { - $this->assertNull($this->typeGuesser->guessType('Class\\Does\\Not\\Exist', 'property')); + self::assertNull($this->typeGuesser->guessType('Class\\Does\\Not\\Exist', 'property')); } public function testItReturnsNullIfNoPhpdocIsPresent(): void { - $this->assertNull($this->typeGuesser->guessType(StubWithNoPhpDoc::class, 'property')); + self::assertNull($this->typeGuesser->guessType(StubWithNoPhpDoc::class, 'property')); } public function testItReturnsNullIfPropertyDoesntExist(): void { - $this->assertNull($this->typeGuesser->guessType(StubWithNoPhpDoc::class, 'property2')); + self::assertNull($this->typeGuesser->guessType(StubWithNoPhpDoc::class, 'property2')); } public function testItReturnsNullIfPropertyHasWrongType(): void { - $this->assertNull($this->typeGuesser->guessType(StubWithWrongType::class, 'property')); + self::assertNull($this->typeGuesser->guessType(StubWithWrongType::class, 'property')); } public function testItGuessesTypeWhenTypeIsAFqcn(): void @@ -62,16 +62,16 @@ public function testItGuessesTypeWhenTypeIsHinted(): void protected function guess_type(string $class): void { - $this->assertCorrectGuess($this->typeGuesser->guessType($class, 'property')); - $this->assertNull($this->typeGuesser->guessRequired($class, 'property')); - $this->assertNull($this->typeGuesser->guessMaxLength($class, 'property')); - $this->assertNull($this->typeGuesser->guessPattern($class, 'property')); + self::assertCorrectGuess($this->typeGuesser->guessType($class, 'property')); + self::assertNull($this->typeGuesser->guessRequired($class, 'property')); + self::assertNull($this->typeGuesser->guessMaxLength($class, 'property')); + self::assertNull($this->typeGuesser->guessPattern($class, 'property')); } - private function assertCorrectGuess(?TypeGuess $res): void + static private function assertCorrectGuess(?TypeGuess $res): void { - $this->assertNotNull($res); - $this->assertSame(CronExpressionType::class, $res->getType()); - $this->assertSame(Guess::VERY_HIGH_CONFIDENCE, $res->getConfidence()); + self::assertNotNull($res); + self::assertSame(CronExpressionType::class, $res->getType()); + self::assertSame(Guess::VERY_HIGH_CONFIDENCE, $res->getConfidence()); } } diff --git a/tests/Form/TypeGuesser/StubAliased.php b/tests/Form/TypeGuesser/StubAliased.php index e6724cd..8983685 100644 --- a/tests/Form/TypeGuesser/StubAliased.php +++ b/tests/Form/TypeGuesser/StubAliased.php @@ -1,4 +1,4 @@ - - * - * @psalm-suppress TooManyTemplateParams */ final class CronExpressionTest extends ConstraintValidatorTestCase { @@ -70,8 +68,6 @@ public function testExpectsStringCompatibleValue(): void * @dataProvider getInvalidValues * * @param mixed $value - * - * @psalm-suppress UndefinedAttributeClass */ #[DataProvider('getInvalidValues')] public function testInvalidValues($value, string $valueAsString): void @@ -80,12 +76,10 @@ public function testInvalidValues($value, string $valueAsString): void $this->validator->validate($value, $constraint); - /** @psalm-suppress InternalMethod,MixedMethodCall */ $this->buildViolation('myMessage')->setParameter('{{ value }}', $valueAsString)->assertRaised(); } /** - * @psalm-return list */ public static function getInvalidValues(): array { diff --git a/tests/Validator/FormCallbackTest.php b/tests/Validator/FormCallbackTest.php index 017924c..717f049 100644 --- a/tests/Validator/FormCallbackTest.php +++ b/tests/Validator/FormCallbackTest.php @@ -12,8 +12,6 @@ /** * @template-extends ConstraintValidatorTestCase - * - * @psalm-suppress TooManyTemplateParams */ final class FormCallbackTest extends ConstraintValidatorTestCase { @@ -39,16 +37,14 @@ public function testOutOfRangeIsNotValid(): void { $value = '61'; $this->validator->validate($value, $this->createConstraint(CronExpression::MINUTE)); - /** @psalm-suppress InternalMethod,MixedMethodCall */ $this->buildViolation('{{value}} is not a valid cron part')->setParameter('value', $value)->assertRaised(); } protected function createConstraint(int $payload): Callback { - // helper function for Symfony 4.4 - return new Callback([ - 'callback' => [new CronExpressionType(), 'validateCronField'], - 'payload' => $payload, - ]); + return new Callback( + callback: [new CronExpressionType(), 'validateCronField'], + payload: $payload, + ); } } From 279f7232b062cbeec04aff1b76310205096e19b7 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 11:50:57 +0100 Subject: [PATCH 10/26] ~ update dependency-analyser file --- composer-dependency-analyser.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index a7801ad..1cf2269 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -4,6 +4,7 @@ use ShipMonk\ComposerDependencyAnalyser\Config\Configuration; use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType; use Symfony\Component\TypeInfo\Type; +use Symfony\Component\PropertyInfo\Type as LegacyType; $config = new Configuration(); @@ -16,6 +17,14 @@ } else { $config->ignoreUnknownClasses([Type::class]); } +if (!class_exists(LegacyType::class)) { + $config->ignoreUnknownClasses([LegacyType::class]); +} +if (!function_exists('Symfony\Component\DependencyInjection\Loader\Configurator\service')) { + $config->ignoreUnknownFunctions([ + 'Symfony\Component\DependencyInjection\Loader\Configurator\service' + ]); +} // ignore polyfill if (version_compare(PHP_VERSION, '8.3.0', '>=')) { From 5b5a0e9b9365c3270f7f79139c15152039e04bea Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 11:56:58 +0100 Subject: [PATCH 11/26] ~ fix services name --- src/DependencyInjection/SetonoCronExpressionExtension.php | 2 +- src/Resources/config/services.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DependencyInjection/SetonoCronExpressionExtension.php b/src/DependencyInjection/SetonoCronExpressionExtension.php index db7b3ba..e42b766 100644 --- a/src/DependencyInjection/SetonoCronExpressionExtension.php +++ b/src/DependencyInjection/SetonoCronExpressionExtension.php @@ -18,7 +18,7 @@ final class SetonoCronExpressionExtension extends Extension implements PrependEx public function load(array $configs, ContainerBuilder $container): void { $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); - $loader->load('services.xml'); + $loader->load('services.php'); } #[\Override] diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index 20e26d7..5aba857 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -4,14 +4,14 @@ use Setono\CronExpressionBundle\Form\TypeGuesser\CronExpressionTypeGuesser; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -use function Symfony\Component\DependencyInjection\Loader\Configurator\service; +use Symfony\Component\DependencyInjection\Loader\Configurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); $services->set('setono_cron_expression.form.type_guesser.cron_expression', CronExpressionTypeGuesser::class) ->args([ - service('property_info'), + Configurator\service('property_info'), ]) ->tag('form.type_guesser'); }; From d3206c6b9434f7f6de4a093a429ca8ebe865de87 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 12:01:03 +0100 Subject: [PATCH 12/26] fix-style --- src/Doctrine/DBAL/Types/CronExpressionType.php | 1 + .../DataTransformer/CronExpressionToPartsTransformer.php | 1 + .../CronExpressionToStringPartsTransformer.php | 1 + src/Form/Type/CronExpressionType.php | 1 + src/Resources/config/services.php | 2 +- src/Validator/CronExpression.php | 2 +- tests/Form/Type/CronExpressionTypeStringTest.php | 1 - tests/Form/Type/CronExpressionTypeTextTest.php | 1 - tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php | 2 +- tests/Form/TypeGuesser/StubAliased.php | 5 ++++- tests/Form/TypeGuesser/StubFqcn.php | 1 + tests/Form/TypeGuesser/StubImported.php | 1 + tests/Form/TypeGuesser/StubWithNoPhpDoc.php | 4 +--- tests/Form/TypeGuesser/StubWithTypeHint.php | 4 +--- tests/Form/TypeGuesser/StubWithWrongType.php | 1 + tests/Validator/CronExpressionTest.php | 2 -- 16 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Doctrine/DBAL/Types/CronExpressionType.php b/src/Doctrine/DBAL/Types/CronExpressionType.php index a55d2cb..3063a16 100644 --- a/src/Doctrine/DBAL/Types/CronExpressionType.php +++ b/src/Doctrine/DBAL/Types/CronExpressionType.php @@ -70,6 +70,7 @@ public function getName(): string /** * @noinspection PhpUnusedParameterInspection + * * @phpstan-ignore return.tooWideBool */ public function requiresSQLCommentHint(AbstractPlatform $platform): bool diff --git a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php index 0b4ef98..ceb043a 100644 --- a/src/Form/DataTransformer/CronExpressionToPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToPartsTransformer.php @@ -87,6 +87,7 @@ public function reverseTransform($value): CronExpression /** * @phpstan-assert array> $value + * * @phpstan-ignore missingType.iterableValue */ private static function allArrayScalar(array $value): bool diff --git a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php index bf0dc94..79caf0e 100644 --- a/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php +++ b/src/Form/DataTransformer/CronExpressionToStringPartsTransformer.php @@ -87,6 +87,7 @@ public function reverseTransform($value): CronExpression /** * @phpstan-assert array $value + * * @phpstan-ignore missingType.iterableValue */ private static function allString(array $value): bool diff --git a/src/Form/Type/CronExpressionType.php b/src/Form/Type/CronExpressionType.php index 1d49ab4..f04573b 100644 --- a/src/Form/Type/CronExpressionType.php +++ b/src/Form/Type/CronExpressionType.php @@ -136,6 +136,7 @@ public function getBlockPrefix(): string /** * Will create an array where the first key is 1 * oneIndexedRange(3) will return [1 => 1, 2 => 2, 3 => 3]. + * * @return array */ private function oneIndexedRange(int $end, int $start = 0): array diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index 5aba857..fb748c0 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -3,8 +3,8 @@ declare(strict_types=1); use Setono\CronExpressionBundle\Form\TypeGuesser\CronExpressionTypeGuesser; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); diff --git a/src/Validator/CronExpression.php b/src/Validator/CronExpression.php index f99f247..9588d62 100644 --- a/src/Validator/CronExpression.php +++ b/src/Validator/CronExpression.php @@ -25,7 +25,7 @@ class CronExpression extends Constraint public function __construct( ?string $message = null, ?array $groups = null, - mixed $payload = null + mixed $payload = null, ) { parent::__construct(null, $groups, $payload); diff --git a/tests/Form/Type/CronExpressionTypeStringTest.php b/tests/Form/Type/CronExpressionTypeStringTest.php index 9618a12..c99bbf3 100644 --- a/tests/Form/Type/CronExpressionTypeStringTest.php +++ b/tests/Form/Type/CronExpressionTypeStringTest.php @@ -63,7 +63,6 @@ public function testSubmitFaultyArray(): void } /** - * @param array|string|null $formData * @phpstan-ignore missingType.iterableValue */ private function _submitFaultyData(array|string|null $formData): void diff --git a/tests/Form/Type/CronExpressionTypeTextTest.php b/tests/Form/Type/CronExpressionTypeTextTest.php index 18845fe..c88a653 100644 --- a/tests/Form/Type/CronExpressionTypeTextTest.php +++ b/tests/Form/Type/CronExpressionTypeTextTest.php @@ -85,7 +85,6 @@ public function testSubmitFaultyMinutesOnly(): void } /** - * @param array|string|null $formData * @phpstan-ignore missingType.iterableValue */ private function _submitFaultyData(array|string|null $formData): void diff --git a/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php b/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php index 664b387..551eecd 100644 --- a/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php +++ b/tests/Form/TypeGuesser/CronExpressionTypeGuesserTest.php @@ -68,7 +68,7 @@ protected function guess_type(string $class): void self::assertNull($this->typeGuesser->guessPattern($class, 'property')); } - static private function assertCorrectGuess(?TypeGuess $res): void + private static function assertCorrectGuess(?TypeGuess $res): void { self::assertNotNull($res); self::assertSame(CronExpressionType::class, $res->getType()); diff --git a/tests/Form/TypeGuesser/StubAliased.php b/tests/Form/TypeGuesser/StubAliased.php index 8983685..2e43a6c 100644 --- a/tests/Form/TypeGuesser/StubAliased.php +++ b/tests/Form/TypeGuesser/StubAliased.php @@ -1,4 +1,6 @@ -buildViolation('myMessage')->setParameter('{{ value }}', $valueAsString)->assertRaised(); } - /** - */ public static function getInvalidValues(): array { return [ From 9a1bf78b66f65a815c9738d8bde773a40c555fbb Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 12:09:06 +0100 Subject: [PATCH 13/26] ~ fix services.php namespace --- composer-dependency-analyser.php | 5 ----- src/Resources/config/services.php | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php index 1cf2269..803f15b 100644 --- a/composer-dependency-analyser.php +++ b/composer-dependency-analyser.php @@ -20,11 +20,6 @@ if (!class_exists(LegacyType::class)) { $config->ignoreUnknownClasses([LegacyType::class]); } -if (!function_exists('Symfony\Component\DependencyInjection\Loader\Configurator\service')) { - $config->ignoreUnknownFunctions([ - 'Symfony\Component\DependencyInjection\Loader\Configurator\service' - ]); -} // ignore polyfill if (version_compare(PHP_VERSION, '8.3.0', '>=')) { diff --git a/src/Resources/config/services.php b/src/Resources/config/services.php index fb748c0..4e33810 100644 --- a/src/Resources/config/services.php +++ b/src/Resources/config/services.php @@ -2,16 +2,16 @@ declare(strict_types=1); +namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use Setono\CronExpressionBundle\Form\TypeGuesser\CronExpressionTypeGuesser; -use Symfony\Component\DependencyInjection\Loader\Configurator; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); $services->set('setono_cron_expression.form.type_guesser.cron_expression', CronExpressionTypeGuesser::class) ->args([ - Configurator\service('property_info'), + service('property_info'), ]) ->tag('form.type_guesser'); }; From e9bf7f88584f02b0e47ce2ece85a320cb5584e98 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:04:51 +0100 Subject: [PATCH 14/26] add Symfony 8 to dependency-analysis --- .github/workflows/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index df569d1..6e01cbf 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -69,6 +69,9 @@ jobs: exclude: - php-version: "8.1" symfony: "^7.0" + include: + - php-version: '8.4' + symfony: '^8.0.0' steps: - name: "Checkout" uses: "actions/checkout@v4" From 0b592bf7462ef85fc22fa642ce872d2409df158a Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:11:37 +0100 Subject: [PATCH 15/26] static-code-analysis for all versions --- .github/workflows/build.yaml | 45 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6e01cbf..53ddeb5 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -94,28 +94,53 @@ jobs: - name: "Run shipmonk/composer-dependency-analyser" run: "vendor/bin/composer-dependency-analyser" - phpstan: - name: "PHPStan" + static-code-analysis: + name: "Static Code Analysis" runs-on: "ubuntu-latest" + strategy: + matrix: + php-version: + - "8.1" + - "8.2" + - "8.3" + - "8.4" + + dependencies: + - "highest" + + symfony: + - "^5.4" + - "^6.0" + - "^7.0" + + exclude: + - php-version: "8.1" + symfony: "^7.0" + include: + - php-version: '8.4' + symfony: '^8.0.0' steps: - name: "Checkout" uses: "actions/checkout@v4" - - name: "Install PHP with extensions" + - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" with: - php-version: '8.4' coverage: "none" - tools: "composer:v2" + extensions: "${{ env.PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" + tools: "flex" - - name: "Install Composer dependencies (highest)" + - name: "Install composer dependencies" uses: "ramsey/composer-install@v3" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" with: - dependency-versions: "highest" + dependency-versions: "${{ matrix.dependencies }}" - - name: "PHPStan" + - name: "Static analysis" run: "vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github" unit-tests: @@ -154,9 +179,9 @@ jobs: - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" with: - php-version: "${{ matrix.php-version }}" - extensions: "${{ env.PHP_EXTENSIONS }}" coverage: "none" + extensions: "${{ env.PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" tools: "flex" - name: "Install composer dependencies" From ff88531d685e888da548ec64cf1fed7ca1cb89c8 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:18:48 +0100 Subject: [PATCH 16/26] reportUnmatchedIgnoredErrors disabled --- phpstan-baseline.neon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e69de29..0d4287d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -0,0 +1,2 @@ +parameters: + reportUnmatchedIgnoredErrors: false From e12b3a6c7b10675ca529c7fd77dd95315bca19e7 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:22:27 +0100 Subject: [PATCH 17/26] bump phpunit version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5b6f80d..f53d083 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", "phpstan/phpstan-symfony": "^1.0 || ^2.0", - "phpunit/phpunit": "^9.5 || ^12.0", + "phpunit/phpunit": "^10.0 || ^12.0", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", From 4c84c15bb0e2e01daa0863c04eaa6cd014a9ad50 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:30:43 +0100 Subject: [PATCH 18/26] drop PHP 8.1 support --- .github/workflows/build.yaml | 14 +------------- composer.json | 4 ++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 53ddeb5..634ccc3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,7 +15,7 @@ jobs: strategy: matrix: php-version: - - "8.1" + - "8.2" dependencies: - "highest" @@ -53,7 +53,6 @@ jobs: strategy: matrix: php-version: - - "8.1" - "8.2" - "8.3" - "8.4" @@ -66,9 +65,6 @@ jobs: - "^6.0" - "^7.0" - exclude: - - php-version: "8.1" - symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' @@ -102,7 +98,6 @@ jobs: strategy: matrix: php-version: - - "8.1" - "8.2" - "8.3" - "8.4" @@ -115,9 +110,6 @@ jobs: - "^6.0" - "^7.0" - exclude: - - php-version: "8.1" - symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' @@ -151,7 +143,6 @@ jobs: strategy: matrix: php-version: - - "8.1" - "8.2" - "8.3" - "8.4" @@ -165,9 +156,6 @@ jobs: - "^6.0" - "^7.0" - exclude: - - php-version: "8.1" - symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' diff --git a/composer.json b/composer.json index f53d083..3ed2e5e 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "doctrine/dbal": "^3.4 || ^4.0", "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0 || ^4.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", @@ -34,7 +34,7 @@ "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", "phpstan/phpstan-symfony": "^1.0 || ^2.0", - "phpunit/phpunit": "^10.0 || ^12.0", + "phpunit/phpunit": "^11.0 || ^12.0", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", From 853da44f2223b391e6bea80602f35df4bc4cbe1f Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:43:37 +0100 Subject: [PATCH 19/26] dump versions --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3ed2e5e..89e95bd 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "symfony/validator": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "ergebnis/composer-normalize": "^2.42", + "ergebnis/composer-normalize": "^2.45", "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.0 || ^6.0", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/extension-installer": "^1.0", @@ -34,7 +34,7 @@ "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", "phpstan/phpstan-symfony": "^1.0 || ^2.0", - "phpunit/phpunit": "^11.0 || ^12.0", + "phpunit/phpunit": "^11.0.1 || ^12.0", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", From 387451f3e5667f9c3075428c6db6cc32e1fb48ed Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:51:08 +0100 Subject: [PATCH 20/26] ignore generics.notGeneric --- tests/Validator/CronExpressionTest.php | 1 + tests/Validator/FormCallbackTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Validator/CronExpressionTest.php b/tests/Validator/CronExpressionTest.php index 7aa4aab..c08b4f6 100644 --- a/tests/Validator/CronExpressionTest.php +++ b/tests/Validator/CronExpressionTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** + * @phpstan-ignore generics.notGeneric * @template-extends ConstraintValidatorTestCase */ final class CronExpressionTest extends ConstraintValidatorTestCase diff --git a/tests/Validator/FormCallbackTest.php b/tests/Validator/FormCallbackTest.php index 717f049..5cbbe17 100644 --- a/tests/Validator/FormCallbackTest.php +++ b/tests/Validator/FormCallbackTest.php @@ -11,6 +11,7 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** + * @phpstan-ignore generics.notGeneric * @template-extends ConstraintValidatorTestCase */ final class FormCallbackTest extends ConstraintValidatorTestCase From 1caf520fb833ad8365e9f81ee8dbb2de9479cb42 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 13:59:29 +0100 Subject: [PATCH 21/26] dump versions --- composer.json | 14 +++++++------- tests/Validator/CronExpressionTest.php | 3 ++- tests/Validator/FormCallbackTest.php | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 89e95bd..5f27a85 100644 --- a/composer.json +++ b/composer.json @@ -14,15 +14,15 @@ "doctrine/dbal": "^3.4 || ^4.0", "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0 || ^4.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", - "symfony/config": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/form": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/config": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/form": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0 || ^8.0", "symfony/polyfill-php83": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/property-info": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/validator": "^5.4 || ^6.0 || ^7.0 || ^8.0" + "symfony/property-info": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/validator": "^5.4 || ^6.4 || ^7.0 || ^8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.45", diff --git a/tests/Validator/CronExpressionTest.php b/tests/Validator/CronExpressionTest.php index c08b4f6..a176657 100644 --- a/tests/Validator/CronExpressionTest.php +++ b/tests/Validator/CronExpressionTest.php @@ -15,8 +15,9 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** - * @phpstan-ignore generics.notGeneric * @template-extends ConstraintValidatorTestCase + * + * @phpstan-ignore generics.notGeneric */ final class CronExpressionTest extends ConstraintValidatorTestCase { diff --git a/tests/Validator/FormCallbackTest.php b/tests/Validator/FormCallbackTest.php index 5cbbe17..0bce2ba 100644 --- a/tests/Validator/FormCallbackTest.php +++ b/tests/Validator/FormCallbackTest.php @@ -11,8 +11,9 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** - * @phpstan-ignore generics.notGeneric * @template-extends ConstraintValidatorTestCase + * + * @phpstan-ignore generics.notGeneric */ final class FormCallbackTest extends ConstraintValidatorTestCase { From a393526e195934048eb33f41903921293e11b2e4 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 14:04:42 +0100 Subject: [PATCH 22/26] dump versions --- composer.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 5f27a85..c09525c 100644 --- a/composer.json +++ b/composer.json @@ -14,15 +14,15 @@ "doctrine/dbal": "^3.4 || ^4.0", "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0 || ^4.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", - "symfony/config": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/form": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/http-kernel": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/config": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", + "symfony/dependency-injection": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", + "symfony/form": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", + "symfony/http-kernel": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", "symfony/polyfill-php83": "^1.33", "symfony/polyfill-php84": "^1.33", - "symfony/property-info": "^5.4 || ^6.4 || ^7.0 || ^8.0", - "symfony/validator": "^5.4 || ^6.4 || ^7.0 || ^8.0" + "symfony/property-info": "^5.4.22 || ^6.4 || ^7.0 || ^8.0", + "symfony/validator": "^5.4.22 || ^6.4 || ^7.0 || ^8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.45", From bce9c9cfb1562d0dcbf5e7ac3c710478700088b8 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 14:16:41 +0100 Subject: [PATCH 23/26] ~ revert php-8.1 drop and bump lowest phpunit/phpunit --- .github/workflows/build.yaml | 16 +++++++++++++--- composer.json | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 634ccc3..b14a3b6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,7 +15,7 @@ jobs: strategy: matrix: php-version: - - "8.2" + - "8.1" dependencies: - "highest" @@ -53,6 +53,7 @@ jobs: strategy: matrix: php-version: + - "8.1" - "8.2" - "8.3" - "8.4" @@ -65,6 +66,9 @@ jobs: - "^6.0" - "^7.0" + exclude: + - php-version: "8.1" + symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' @@ -98,6 +102,7 @@ jobs: strategy: matrix: php-version: + - "8.1" - "8.2" - "8.3" - "8.4" @@ -110,6 +115,9 @@ jobs: - "^6.0" - "^7.0" + exclude: + - php-version: "8.1" + symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' @@ -143,6 +151,7 @@ jobs: strategy: matrix: php-version: + - "8.1" - "8.2" - "8.3" - "8.4" @@ -156,6 +165,9 @@ jobs: - "^6.0" - "^7.0" + exclude: + - php-version: "8.1" + symfony: "^7.0" include: - php-version: '8.4' symfony: '^8.0.0' @@ -167,8 +179,6 @@ jobs: - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" with: - coverage: "none" - extensions: "${{ env.PHP_EXTENSIONS }}" php-version: "${{ matrix.php-version }}" tools: "flex" diff --git a/composer.json b/composer.json index c09525c..dd009aa 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=8.2", + "php": ">=8.1", "doctrine/dbal": "^3.4 || ^4.0", "doctrine/doctrine-bundle": "^1.9 || ^2.0 || ^3.0 || ^4.0", "dragonmantank/cron-expression": "^2.2 || ^3.0", @@ -34,7 +34,7 @@ "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpstan/phpstan-strict-rules": "^1.0 || ^2.0", "phpstan/phpstan-symfony": "^1.0 || ^2.0", - "phpunit/phpunit": "^11.0.1 || ^12.0", + "phpunit/phpunit": "^10.5 || ^11.0.1 || ^12.0", "roave/security-advisories": "dev-latest", "shipmonk/composer-dependency-analyser": "^1.8", "sylius-labs/coding-standard": "^4.1.1", From ab7a7691f43567a1253229050a5e86cbbd2f4055 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 14:23:47 +0100 Subject: [PATCH 24/26] @phpstan-ignore staticMethod.dynamicCall --- tests/Form/Type/CronExpressionTypeCallbackTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Form/Type/CronExpressionTypeCallbackTest.php b/tests/Form/Type/CronExpressionTypeCallbackTest.php index fde7679..8333e10 100644 --- a/tests/Form/Type/CronExpressionTypeCallbackTest.php +++ b/tests/Form/Type/CronExpressionTypeCallbackTest.php @@ -29,6 +29,7 @@ public function testViolationAdded(): void protected function callValidateCronField(?string $value, bool $match): void { $mock = $this->createMock(ExecutionContextInterface::class); + /** @phpstan-ignore staticMethod.dynamicCall */ $mock->expects($match ? $this->once() : $this->never())->method('addViolation') ->with('{{value}} is not a valid cron part', ['value' => $value]) ; From 206fb76775c8e97e4a0d4a7cc3d12851547885c6 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 14:32:28 +0100 Subject: [PATCH 25/26] check-style --- tests/Form/Type/CronExpressionTypeCallbackTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/Form/Type/CronExpressionTypeCallbackTest.php b/tests/Form/Type/CronExpressionTypeCallbackTest.php index 8333e10..bd4c45a 100644 --- a/tests/Form/Type/CronExpressionTypeCallbackTest.php +++ b/tests/Form/Type/CronExpressionTypeCallbackTest.php @@ -29,8 +29,13 @@ public function testViolationAdded(): void protected function callValidateCronField(?string $value, bool $match): void { $mock = $this->createMock(ExecutionContextInterface::class); - /** @phpstan-ignore staticMethod.dynamicCall */ - $mock->expects($match ? $this->once() : $this->never())->method('addViolation') + + $mock->expects( + $match ? +/** @phpstan-ignore staticMethod.dynamicCall */ $this->once() : +/** @phpstan-ignore staticMethod.dynamicCall */ $this->never(), + ) + ->method('addViolation') ->with('{{value}} is not a valid cron part', ['value' => $value]) ; From 552186437fac70f6d9ddb38eb24db3491aa19873 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 1 Dec 2025 15:00:57 +0100 Subject: [PATCH 26/26] add PHP 8.5 workflow --- .github/workflows/build.yaml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b14a3b6..d03e885 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -57,6 +57,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" dependencies: - "highest" @@ -71,7 +72,9 @@ jobs: symfony: "^7.0" include: - php-version: '8.4' - symfony: '^8.0.0' + symfony: '^8.0' + - php-version: '8.5' + symfony: '^8.0' steps: - name: "Checkout" uses: "actions/checkout@v4" @@ -106,6 +109,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" dependencies: - "highest" @@ -120,7 +124,9 @@ jobs: symfony: "^7.0" include: - php-version: '8.4' - symfony: '^8.0.0' + symfony: '^8.0' + - php-version: '8.5' + symfony: '^8.0' steps: - name: "Checkout" uses: "actions/checkout@v4" @@ -155,6 +161,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" dependencies: - "lowest" @@ -170,7 +177,9 @@ jobs: symfony: "^7.0" include: - php-version: '8.4' - symfony: '^8.0.0' + symfony: '^8.0' + - php-version: '8.5' + symfony: '^8.0' steps: - name: "Checkout" @@ -200,7 +209,7 @@ jobs: strategy: matrix: php-version: - - "8.4" + - "8.5" dependencies: - "highest"