From e0aa3c5e49b77f3e2d556aee8e08120ec5e5c03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Tue, 14 Jan 2025 11:36:47 +0100 Subject: [PATCH] Add support for Doctrine ORM 3 --- .github/workflows/build.yml | 18 +++++++++++++++--- composer.json | 7 ++++--- .../ORM/ContainerRepositoryFactory.php | 18 ++++++++++++------ .../Doctrine/ORM/ResourceRepositoryTrait.php | 12 ++++++------ .../ORMMappedSuperClassSubscriber.php | 13 ++++++++++++- .../EventListener/ORMTranslatableListener.php | 3 ++- src/Component/composer.json | 4 ++-- .../src/Entity/GedmoBaseExample.php | 2 -- .../src/Entity/GedmoExtendedExample.php | 2 -- 9 files changed, 53 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1f3787a25..350a00bdb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,16 +13,22 @@ on: jobs: tests: runs-on: ubuntu-latest - name: "PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}" + name: "PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, ORM ${{ matrix.orm }}, ${{ matrix.composer-flags }}" env: APP_ENV: ${{ matrix.app_env }} strategy: fail-fast: false matrix: + orm: ['2.*', '3.*'] php: ["8.1", "8.2", "8.3"] composer-flags: ['--no-scripts --prefer-stable --prefer-dist'] symfony: ["^6.4", "^7.1"] app_env: ["test"] + include: + - php: "8.3" + symfony: "^7.1" + orm: '2.*' + composer-flags: '--no-scripts --prefer-stable --prefer-dist --prefer-lowest' exclude: - php: "8.1" symfony: "^7.1" @@ -47,6 +53,13 @@ jobs: composer config extra.symfony.require "${{ matrix.symfony }}" (cd src/Component && composer config extra.symfony.require "${{ matrix.symfony }}") + - + name: Restrict ORM version + if: matrix.orm != '' + run: | + composer require --dev doctrine/orm "${{ matrix.orm }}" --no-update --no-scripts + (cd src/Component && composer require --dev doctrine/orm "${{ matrix.orm }}" --no-update --no-scripts) + - name: Remove hateoas on Symfony 7 if: matrix.symfony == '^7.0' @@ -55,13 +68,12 @@ jobs: - name: Install dependencies run: | - composer update --no-scripts + composer update ${{ matrix.composer-flags }} (cd src/Component && composer update ${{ matrix.composer-flags }}) - name: Prepare test application run: | - (cd tests/Application && bin/console doctrine:database:create) (cd tests/Application && bin/console doctrine:schema:create) - diff --git a/composer.json b/composer.json index 58bc55da8..805daa6e8 100644 --- a/composer.json +++ b/composer.json @@ -56,10 +56,11 @@ }, "require-dev": { "doctrine/doctrine-bundle": "^2.13", - "doctrine/orm": "^2.18", + "doctrine/orm": "^2.18 || ^3.3", + "theofidry/alice-data-fixtures": "^1.8", "friendsofsymfony/rest-bundle": "^3.7", "jms/serializer-bundle": "^3.5 || ^4.0 || ^5.0", - "lchrusciel/api-test-case": "^5.0", + "lchrusciel/api-test-case": "^5.3", "matthiasnoback/symfony-dependency-injection-test": "^4.2.1 || ^5.1", "pagerfanta/pagerfanta": "^4.4", "pamil/phpspec-skip-example-extension": "^4.2", @@ -89,7 +90,7 @@ "winzou/state-machine-bundle": "^0.6.2" }, "conflict": { - "doctrine/orm": "<2.18 || ^3.0", + "doctrine/orm": "<2.18", "doctrine/doctrine-bundle": "<2.0 || ^3.0", "friendsofsymfony/rest-bundle": "<3.0", "jms/serializer-bundle": "<3.5", diff --git a/src/Bundle/Doctrine/ORM/ContainerRepositoryFactory.php b/src/Bundle/Doctrine/ORM/ContainerRepositoryFactory.php index 2d0fc21b8..334ba3267 100644 --- a/src/Bundle/Doctrine/ORM/ContainerRepositoryFactory.php +++ b/src/Bundle/Doctrine/ORM/ContainerRepositoryFactory.php @@ -14,9 +14,9 @@ namespace Sylius\Bundle\ResourceBundle\Doctrine\ORM; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository as DoctrineEntityRepository; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Repository\RepositoryFactory; -use Doctrine\Persistence\ObjectRepository; final class ContainerRepositoryFactory implements RepositoryFactory { @@ -25,7 +25,7 @@ final class ContainerRepositoryFactory implements RepositoryFactory /** @var string[] */ private array $genericEntities; - /** @var ObjectRepository[] */ + /** @var DoctrineEntityRepository[] */ private array $managedRepositories = []; /** @@ -37,8 +37,11 @@ public function __construct(RepositoryFactory $doctrineFactory, array $genericEn $this->genericEntities = $genericEntities; } - /** @psalm-suppress InvalidReturnType */ - public function getRepository(EntityManagerInterface $entityManager, $entityName): ObjectRepository + /** + * @psalm-suppress InvalidReturnStatement + * @psalm-suppress InvalidReturnType + */ + public function getRepository(EntityManagerInterface $entityManager, $entityName): DoctrineEntityRepository { $metadata = $entityManager->getClassMetadata($entityName); @@ -47,13 +50,16 @@ public function getRepository(EntityManagerInterface $entityManager, $entityName return $this->getOrCreateRepository($entityManager, $metadata); } - return $this->doctrineFactory->getRepository($entityManager, $entityName); + /** @var DoctrineEntityRepository $repository */ + $repository = $this->doctrineFactory->getRepository($entityManager, $entityName); + + return $repository; } private function getOrCreateRepository( EntityManagerInterface $entityManager, ClassMetadata $metadata, - ): ObjectRepository { + ): DoctrineEntityRepository { $repositoryHash = $metadata->getName() . spl_object_hash($entityManager); if (!isset($this->managedRepositories[$repositoryHash])) { diff --git a/src/Bundle/Doctrine/ORM/ResourceRepositoryTrait.php b/src/Bundle/Doctrine/ORM/ResourceRepositoryTrait.php index 1ad59dded..abd6fad6c 100644 --- a/src/Bundle/Doctrine/ORM/ResourceRepositoryTrait.php +++ b/src/Bundle/Doctrine/ORM/ResourceRepositoryTrait.php @@ -32,15 +32,15 @@ trait ResourceRepositoryTrait { public function add(ResourceInterface $resource): void { - $this->_em->persist($resource); - $this->_em->flush(); + $this->getEntityManager()->persist($resource); + $this->getEntityManager()->flush(); } public function remove(ResourceInterface $resource): void { if (null !== $this->find($resource->getId())) { - $this->_em->remove($resource); - $this->_em->flush(); + $this->getEntityManager()->remove($resource); + $this->getEntityManager()->flush(); } } @@ -78,7 +78,7 @@ protected function getArrayPaginator($objects): Pagerfanta protected function applyCriteria(QueryBuilder $queryBuilder, array $criteria = []): void { foreach ($criteria as $property => $value) { - if (!in_array($property, array_merge($this->_class->getAssociationNames(), $this->_class->getFieldNames()), true)) { + if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) { continue; } @@ -101,7 +101,7 @@ protected function applyCriteria(QueryBuilder $queryBuilder, array $criteria = [ protected function applySorting(QueryBuilder $queryBuilder, array $sorting = []): void { foreach ($sorting as $property => $order) { - if (!in_array($property, array_merge($this->_class->getAssociationNames(), $this->_class->getFieldNames()), true)) { + if (!in_array($property, array_merge($this->getClassMetadata()->getAssociationNames(), $this->getClassMetadata()->getFieldNames()), true)) { continue; } diff --git a/src/Bundle/EventListener/ORMMappedSuperClassSubscriber.php b/src/Bundle/EventListener/ORMMappedSuperClassSubscriber.php index 11a434613..a7e71889f 100644 --- a/src/Bundle/EventListener/ORMMappedSuperClassSubscriber.php +++ b/src/Bundle/EventListener/ORMMappedSuperClassSubscriber.php @@ -80,9 +80,17 @@ private function setAssociationMappings(ClassMetadata $metadata, Configuration $ } if ($parentMetadata->isMappedSuperclass) { + /** + * @var array{type: int} $value + */ foreach ($parentMetadata->getAssociationMappings() as $key => $value) { if ($this->isRelation($value['type']) && !isset($metadata->associationMappings[$key])) { - $metadata->associationMappings[$key] = $value; + // TODO Fix that for ORM 3 + /** + * @psalm-suppress PropertyTypeCoercion + * @psalm-suppress InvalidPropertyAssignmentValue + */ + $metadata->associationMappings[$key] = $value; /** @phpstan-ignore-line */ } } } @@ -96,6 +104,9 @@ private function unsetAssociationMappings(ClassMetadata $metadata): void return; } + /** + * @var array{type: int} $value + */ foreach ($metadata->getAssociationMappings() as $key => $value) { if ($this->isRelation($value['type'])) { unset($metadata->associationMappings[$key]); diff --git a/src/Bundle/EventListener/ORMTranslatableListener.php b/src/Bundle/EventListener/ORMTranslatableListener.php index b64e43867..5b95d861b 100644 --- a/src/Bundle/EventListener/ORMTranslatableListener.php +++ b/src/Bundle/EventListener/ORMTranslatableListener.php @@ -58,6 +58,7 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void $classMetadata = $eventArgs->getClassMetadata(); $reflection = $classMetadata->getReflectionClass(); + /** @psalm-suppress PossiblyNullReference */ if ($reflection->isAbstract()) { return; } @@ -109,7 +110,7 @@ private function mapTranslatable(ClassMetadata $metadata): void 'mappedBy' => 'translatable', 'fetch' => ClassMetadata::FETCH_EXTRA_LAZY, 'indexBy' => 'locale', - 'cascade' => ['persist', 'merge', 'remove'], + 'cascade' => ['persist', 'remove'], 'orphanRemoval' => true, ]); } diff --git a/src/Component/composer.json b/src/Component/composer.json index 800ef515e..4cc4d95f5 100644 --- a/src/Component/composer.json +++ b/src/Component/composer.json @@ -48,7 +48,7 @@ }, "require-dev": { "behat/transliterator": "^1.3", - "doctrine/orm": "^2.18", + "doctrine/orm": "^2.18 || ^3.3", "matthiasnoback/symfony-dependency-injection-test": "^4.2.1 || ^5.1", "phpspec/phpspec": "^7.3", "phpspec/prophecy-phpunit": "^2.0", @@ -59,7 +59,7 @@ "twig/twig": "^3.0" }, "conflict": { - "doctrine/orm": "<2.18 || ^3.0", + "doctrine/orm": "<2.18", "twig/twig": "<3.0" }, "extra": { diff --git a/tests/Application/src/Entity/GedmoBaseExample.php b/tests/Application/src/Entity/GedmoBaseExample.php index 224b3a3b3..29eb16a81 100644 --- a/tests/Application/src/Entity/GedmoBaseExample.php +++ b/tests/Application/src/Entity/GedmoBaseExample.php @@ -17,9 +17,7 @@ use Gedmo\Mapping\Annotation as Gedmo; use Sylius\Resource\Model\ResourceInterface; -#[ORM\Entity] #[ORM\MappedSuperclass] -#[ORM\Table(name: 'gedmo')] class GedmoBaseExample implements ResourceInterface { #[ORM\Id] diff --git a/tests/Application/src/Entity/GedmoExtendedExample.php b/tests/Application/src/Entity/GedmoExtendedExample.php index 265fce55b..4461e25af 100644 --- a/tests/Application/src/Entity/GedmoExtendedExample.php +++ b/tests/Application/src/Entity/GedmoExtendedExample.php @@ -16,8 +16,6 @@ use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] -#[ORM\MappedSuperclass] - class GedmoExtendedExample extends GedmoBaseExample { #[ORM\Column(length: 255)]