From 622eea170a7b0b00bad448c5ae066eb7555fa744 Mon Sep 17 00:00:00 2001 From: LDA Date: Tue, 3 Jun 2025 22:58:51 +0200 Subject: [PATCH 1/2] Add symfony date point descriptor @see https://symfony.com/blog/new-in-symfony-7-3-dx-improvements-part-1\#datepoint-doctrine-type --- composer.json | 5 ++- extension.neon | 3 ++ .../Descriptors/Symfony/DatePointType.php | 34 +++++++++++++++++++ .../Doctrine/ORM/EntityColumnRuleTest.php | 22 ++++++++++++ .../Doctrine/ORM/data/MyBrokenEntity.php | 14 ++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/Type/Doctrine/Descriptors/Symfony/DatePointType.php diff --git a/composer.json b/composer.json index 24ea4782..b9467cbc 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,10 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6.20", "ramsey/uuid": "^4.2", - "symfony/cache": "^5.4" + "symfony/cache": "^6.4", + "symfony/clock": "^6.4", + "symfony/doctrine-bridge": "^7.3", + "symfony/validator": "^6.4" }, "config": { "sort-packages": true, diff --git a/extension.neon b/extension.neon index 93102dc0..f0469eb9 100644 --- a/extension.neon +++ b/extension.neon @@ -412,6 +412,9 @@ services: tags: [phpstan.doctrine.typeDescriptor] arguments: uuidTypeName: Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType + - + class: PHPStan\Type\Doctrine\Descriptors\Symfony\DatePointType + tags: [phpstan.doctrine.typeDescriptor] # Doctrine Collection - diff --git a/src/Type/Doctrine/Descriptors/Symfony/DatePointType.php b/src/Type/Doctrine/Descriptors/Symfony/DatePointType.php new file mode 100644 index 00000000..b82d4c93 --- /dev/null +++ b/src/Type/Doctrine/Descriptors/Symfony/DatePointType.php @@ -0,0 +1,34 @@ +objectManagerLoader, __DIR__ . '/../../../../tmp'), @@ -79,6 +84,7 @@ protected function getRule(): Rule new ReflectionDescriptor(CarbonType::class, $this->createReflectionProvider(), self::getContainer()), new ReflectionDescriptor(CustomType::class, $this->createReflectionProvider(), self::getContainer()), new ReflectionDescriptor(CustomNumericType::class, $this->createReflectionProvider(), self::getContainer()), + new DatePointType(), ]), $this->createReflectionProvider(), true, @@ -166,6 +172,14 @@ public function testRule(?string $objectManagerLoader): void 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array but database expects array.', 162, ], + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: database can contain Symfony\Component\Clock\DatePoint but property expects DateTime.', + 175, + ], + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: property can contain DateTime but database expects Symfony\Component\Clock\DatePoint.', + 175, + ], ]; $dbalVersion = InstalledVersions::getVersion('doctrine/dbal'); @@ -237,6 +251,14 @@ public function testRuleWithAllowedNullableProperty(?string $objectManagerLoader 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array but database expects array.', 162, ], + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: database can contain Symfony\Component\Clock\DatePoint but property expects DateTime.', + 175, + ], + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: property can contain DateTime but database expects Symfony\Component\Clock\DatePoint.', + 175, + ], ]; $dbalVersion = InstalledVersions::getVersion('doctrine/dbal'); diff --git a/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php b/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php index a2a9e3f7..690e844b 100644 --- a/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php +++ b/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php @@ -166,4 +166,18 @@ class MyBrokenEntity extends MyBrokenSuperclass * @var list */ private $validSimpleArray; + + + /** + * @ORM\Column(type="date_point") + * @var \DateTime + */ + private $invalidDatePoint; + + /** + * @ORM\Column(type="date_point") + * @var \Symfony\Component\Clock\DatePoint + */ + private $validDatePoint; + } From c657b6b545d75271c5772370e9531d228e01be9f Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 5 Jun 2025 14:07:45 +0200 Subject: [PATCH 2/2] Try to fix build --- .github/workflows/build.yml | 2 + .github/workflows/platform-test.yml | 2 +- .../without-symfony-bridge-baseline.php | 14 +++++ composer.json | 5 +- extension.neon | 2 +- phpstan-baseline-without-symfony-bridge.neon | 25 +++++++++ phpstan.neon | 1 + ...ntType.php => DatePointTypeDescriptor.php} | 5 +- .../Doctrine/ORM/EntityColumnRuleTest.php | 54 +++++++++++-------- .../Doctrine/ORM/data/MyBrokenEntity.php | 13 ----- .../ORM/data/MySymfonyBrokenEntity.php | 24 +++++++++ 11 files changed, 105 insertions(+), 42 deletions(-) create mode 100644 compatibility/without-symfony-bridge-baseline.php create mode 100644 phpstan-baseline-without-symfony-bridge.neon rename src/Type/Doctrine/Descriptors/Symfony/{DatePointType.php => DatePointTypeDescriptor.php} (80%) create mode 100644 tests/Rules/Doctrine/ORM/data/MySymfonyBrokenEntity.php diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad3633e9..e4eb02e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -164,6 +164,8 @@ jobs: include: - php-version: "8.3" update-packages: "composer require --dev doctrine/orm:^3.0 doctrine/dbal:^4.0 carbonphp/carbon-doctrine-types:^3 gedmo/doctrine-extensions:^3 -W" + - php-version: "8.4" + update-packages: "composer require --dev doctrine/orm:^3.0 doctrine/dbal:^4.0 carbonphp/carbon-doctrine-types:^3 gedmo/doctrine-extensions:^3 symfony/cache:^6.4 symfony/clock:^6.4 symfony/doctrine-bridge:^7.3 symfony/validator:^6.4 -W" steps: - name: "Checkout" diff --git a/.github/workflows/platform-test.yml b/.github/workflows/platform-test.yml index 38110353..f168cf8c 100644 --- a/.github/workflows/platform-test.yml +++ b/.github/workflows/platform-test.yml @@ -37,7 +37,7 @@ jobs: - php-version: "8.3" update-packages: doctrine/orm:^3.0 doctrine/dbal:^4.0 carbonphp/carbon-doctrine-types:^3 gedmo/doctrine-extensions:^3 - php-version: "8.4" - update-packages: doctrine/orm:^3.0 doctrine/dbal:^4.0 carbonphp/carbon-doctrine-types:^3 gedmo/doctrine-extensions:^3 + update-packages: doctrine/orm:^3.0 doctrine/dbal:^4.0 carbonphp/carbon-doctrine-types:^3 gedmo/doctrine-extensions:^3 symfony/cache:^6.4 symfony/clock:^6.4 symfony/doctrine-bridge:^7.3 symfony/validator:^6.4 steps: - name: "Checkout" diff --git a/compatibility/without-symfony-bridge-baseline.php b/compatibility/without-symfony-bridge-baseline.php new file mode 100644 index 00000000..24437da4 --- /dev/null +++ b/compatibility/without-symfony-bridge-baseline.php @@ -0,0 +1,14 @@ + but returns string\.$#' + identifier: return.type + count: 1 + path: src/Type/Doctrine/Descriptors/Symfony/DatePointTypeDescriptor.php + + - + message: '#^Parameter \#2 \$className of static method Doctrine\\DBAL\\Types\\Type\:\:addType\(\) expects class\-string\, string given\.$#' + identifier: argument.type + count: 1 + path: tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php diff --git a/phpstan.neon b/phpstan.neon index efbf455d..8d9a184b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,6 +5,7 @@ includes: - phpstan-baseline-deprecations.neon - phpstan-baseline-dbal-3.neon - compatibility/orm-3-baseline.php + - compatibility/without-symfony-bridge-baseline.php - vendor/phpstan/phpstan-strict-rules/rules.neon - vendor/phpstan/phpstan-deprecation-rules/rules.neon - vendor/phpstan/phpstan-phpunit/extension.neon diff --git a/src/Type/Doctrine/Descriptors/Symfony/DatePointType.php b/src/Type/Doctrine/Descriptors/Symfony/DatePointTypeDescriptor.php similarity index 80% rename from src/Type/Doctrine/Descriptors/Symfony/DatePointType.php rename to src/Type/Doctrine/Descriptors/Symfony/DatePointTypeDescriptor.php index b82d4c93..8833d09e 100644 --- a/src/Type/Doctrine/Descriptors/Symfony/DatePointType.php +++ b/src/Type/Doctrine/Descriptors/Symfony/DatePointTypeDescriptor.php @@ -6,14 +6,15 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; use PHPStan\Type\Type; +use Symfony\Bridge\Doctrine\Types\DatePointType; use Symfony\Component\Clock\DatePoint; -class DatePointType implements DoctrineTypeDescriptor +class DatePointTypeDescriptor implements DoctrineTypeDescriptor { public function getType(): string { - return \Symfony\Bridge\Doctrine\Types\DatePointType::class; + return DatePointType::class; } public function getWritableToPropertyType(): Type diff --git a/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php b/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php index 0db5b2d7..50a1c6fc 100644 --- a/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php +++ b/tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php @@ -24,10 +24,11 @@ use PHPStan\Type\Doctrine\Descriptors\ReflectionDescriptor; use PHPStan\Type\Doctrine\Descriptors\SimpleArrayType; use PHPStan\Type\Doctrine\Descriptors\StringType; -use PHPStan\Type\Doctrine\Descriptors\Symfony\DatePointType; +use PHPStan\Type\Doctrine\Descriptors\Symfony\DatePointTypeDescriptor; use PHPStan\Type\Doctrine\ObjectMetadataResolver; -use Symfony\Component\Clock\DatePoint; +use Symfony\Bridge\Doctrine\Types\DatePointType; use function array_unshift; +use function class_exists; use function strpos; use const PHP_VERSION_ID; @@ -61,8 +62,8 @@ protected function getRule(): Rule if (!Type::hasType('array')) { Type::addType('array', \Doctrine\DBAL\Types\ArrayType::class); } - if (!Type::hasType('date_point')) { - Type::addType('date_point', \Symfony\Bridge\Doctrine\Types\DatePointType::class); + if (!Type::hasType('date_point') && class_exists(DatePointType::class)) { + Type::addType('date_point', DatePointType::class); } return new EntityColumnRule( @@ -84,7 +85,7 @@ protected function getRule(): Rule new ReflectionDescriptor(CarbonType::class, $this->createReflectionProvider(), self::getContainer()), new ReflectionDescriptor(CustomType::class, $this->createReflectionProvider(), self::getContainer()), new ReflectionDescriptor(CustomNumericType::class, $this->createReflectionProvider(), self::getContainer()), - new DatePointType(), + new DatePointTypeDescriptor(), ]), $this->createReflectionProvider(), true, @@ -172,14 +173,6 @@ public function testRule(?string $objectManagerLoader): void 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array but database expects array.', 162, ], - [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: database can contain Symfony\Component\Clock\DatePoint but property expects DateTime.', - 175, - ], - [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: property can contain DateTime but database expects Symfony\Component\Clock\DatePoint.', - 175, - ], ]; $dbalVersion = InstalledVersions::getVersion('doctrine/dbal'); @@ -194,6 +187,33 @@ public function testRule(?string $objectManagerLoader): void $this->analyse([__DIR__ . '/data/MyBrokenEntity.php'], $errors); } + + /** + * @dataProvider dataObjectManagerLoader + */ + public function testRuleSymfony(?string $objectManagerLoader): void + { + if (!InstalledVersions::isInstalled('symfony/doctrine-bridge')) { + self::markTestSkipped('symfony/doctrine-bridge'); + } + + $this->allowNullablePropertyForRequiredField = false; + $this->objectManagerLoader = $objectManagerLoader; + + $errors = [ + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: database can contain Symfony\Component\Clock\DatePoint but property expects DateTime.', + 175, + ], + [ + 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: property can contain DateTime but database expects Symfony\Component\Clock\DatePoint.', + 175, + ], + ]; + + $this->analyse([__DIR__ . '/data/MySymfonyBrokenEntity.php'], $errors); + } + /** * @dataProvider dataObjectManagerLoader */ @@ -251,14 +271,6 @@ public function testRuleWithAllowedNullableProperty(?string $objectManagerLoader 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidSimpleArray type mapping mismatch: property can contain array but database expects array.', 162, ], - [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: database can contain Symfony\Component\Clock\DatePoint but property expects DateTime.', - 175, - ], - [ - 'Property PHPStan\Rules\Doctrine\ORM\MyBrokenEntity::$invalidDatePoint type mapping mismatch: property can contain DateTime but database expects Symfony\Component\Clock\DatePoint.', - 175, - ], ]; $dbalVersion = InstalledVersions::getVersion('doctrine/dbal'); diff --git a/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php b/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php index 690e844b..e35c84a2 100644 --- a/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php +++ b/tests/Rules/Doctrine/ORM/data/MyBrokenEntity.php @@ -167,17 +167,4 @@ class MyBrokenEntity extends MyBrokenSuperclass */ private $validSimpleArray; - - /** - * @ORM\Column(type="date_point") - * @var \DateTime - */ - private $invalidDatePoint; - - /** - * @ORM\Column(type="date_point") - * @var \Symfony\Component\Clock\DatePoint - */ - private $validDatePoint; - } diff --git a/tests/Rules/Doctrine/ORM/data/MySymfonyBrokenEntity.php b/tests/Rules/Doctrine/ORM/data/MySymfonyBrokenEntity.php new file mode 100644 index 00000000..2105761d --- /dev/null +++ b/tests/Rules/Doctrine/ORM/data/MySymfonyBrokenEntity.php @@ -0,0 +1,24 @@ +