From ca142ace49cbbf0db4c953d7759b27d8e1f51e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Mon, 13 Mar 2023 16:27:59 +0100 Subject: [PATCH] Add missing specs to cover PersistProcessor, RemoveProcessor, ClassInfoTrait & DoctrineResourceMetadataCollectionFactory --- phpstan.neon | 1 + psalm.xml | 1 + ...trineResourceMetadataCollectionFactory.php | 2 +- .../Tests/Reflection/ClassInfoTraitTest.php | 51 ++++++++ src/Component/composer.json | 1 + ...eResourceMetadataCollectionFactorySpec.php | 117 ++++++++++++++++++ .../Common/State/PersistProcessorSpec.php | 113 +++++++++++++++++ .../Common/State/RemoveProcessorSpec.php | 68 ++++++++++ 8 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 src/Component/Tests/Reflection/ClassInfoTraitTest.php create mode 100644 src/Component/spec/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactorySpec.php create mode 100644 src/Component/spec/Doctrine/Common/State/PersistProcessorSpec.php create mode 100644 src/Component/spec/Doctrine/Common/State/RemoveProcessorSpec.php diff --git a/phpstan.neon b/phpstan.neon index 33cd67920..5778e1c1e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -31,6 +31,7 @@ parameters: - '/Call to method getArguments\(\) on an unknown class ReflectionAttribute./' - '/Call to method isChangeTrackingDeferredExplicit\(\) on an unknown class Doctrine\\ODM\\MongoDB\\Mapping\\ClassMetadata./' - '/Call to an undefined method ReflectionClass::getAttributes\(\)./' + - '/Call to an undefined method object::getRealClassName\(\)./' - '/Class Doctrine\\Bundle\\MongoDBBundle/' - '/Class Doctrine\\Bundle\\PHPCRBundle/' - '/Class Doctrine\\Common\\Persistence\\ObjectManager not found\./' diff --git a/psalm.xml b/psalm.xml index 85937eea5..60a7274ba 100644 --- a/psalm.xml +++ b/psalm.xml @@ -157,6 +157,7 @@ + diff --git a/src/Component/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactory.php b/src/Component/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactory.php index dd0cae607..ce1a1c48b 100644 --- a/src/Component/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactory.php +++ b/src/Component/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactory.php @@ -23,7 +23,7 @@ use Sylius\Component\Resource\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use Sylius\Component\Resource\Metadata\Resource\ResourceMetadataCollection; -class DoctrineResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface +final class DoctrineResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface { public function __construct( private RegistryInterface $resourceRegistry, diff --git a/src/Component/Tests/Reflection/ClassInfoTraitTest.php b/src/Component/Tests/Reflection/ClassInfoTraitTest.php new file mode 100644 index 000000000..6e6a84ee2 --- /dev/null +++ b/src/Component/Tests/Reflection/ClassInfoTraitTest.php @@ -0,0 +1,51 @@ +getClassInfoTraitImplementation(); + + $this->assertSame(Book::class, $classInfo->getRealClassName('Proxies\__CG__\App\Entity\Book')); + } + + public function testProxyManagerRealClassName(): void + { + $classInfo = $this->getClassInfoTraitImplementation(); + + $this->assertSame(Book::class, $classInfo->getRealClassName('MongoDBODMProxies\__PM__\App\Entity\Book\Generated')); + } + + public function testUnmarkedRealClassName(): void + { + $classInfo = $this->getClassInfoTraitImplementation(); + + $this->assertSame(Book::class, $classInfo->getRealClassName(Book::class)); + } +} diff --git a/src/Component/composer.json b/src/Component/composer.json index 23b45cbdb..606ef6274 100644 --- a/src/Component/composer.json +++ b/src/Component/composer.json @@ -42,6 +42,7 @@ }, "require-dev": { "behat/transliterator": "^1.3", + "doctrine/orm": "^2.5", "phpspec/phpspec": "^7.2", "phpunit/phpunit": "^9.5", "sylius/grid": "^1.7 || ^1.12", diff --git a/src/Component/spec/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactorySpec.php b/src/Component/spec/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactorySpec.php new file mode 100644 index 000000000..3b1bbb47b --- /dev/null +++ b/src/Component/spec/Doctrine/Common/Metadata/Resource/Factory/DoctrineResourceMetadataCollectionFactorySpec.php @@ -0,0 +1,117 @@ +beConstructedWith($resourceRegistry, $decorated); + } + + function it_is_initializable(): void + { + $this->shouldHaveType(DoctrineResourceMetadataCollectionFactory::class); + } + + function it_adds_persist_processor_to_operations_for_resource_with_doctrine_orm_driver( + ResourceMetadataCollectionFactoryInterface $decorated, + RegistryInterface $resourceRegistry, + MetadataInterface $metadata, + ): void { + $resource = new Resource(alias: 'app.dummy'); + $operation = new Create(name: 'app_dummy_create'); + $resource = $resource->withOperations(new Operations([$operation])); + + $resourceMetadataCollection = new ResourceMetadataCollection([$resource]); + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.dummy')->willReturn($metadata); + $metadata->getDriver()->willReturn('doctrine/orm'); + + $result = $this->create('App\Resource'); + + $result + ->getOperation('app.dummy', 'app_dummy_create') + ->getProcessor() + ->shouldReturn(PersistProcessor::class) + ; + } + + function it_adds_persist_processor_to_operations_for_resource_with_doctrine_dbal_driver( + ResourceMetadataCollectionFactoryInterface $decorated, + RegistryInterface $resourceRegistry, + MetadataInterface $metadata, + ): void { + $resource = new Resource(alias: 'app.dummy'); + $operation = new Create(name: 'app_dummy_create'); + $resource = $resource->withOperations(new Operations([$operation])); + + $resourceMetadataCollection = new ResourceMetadataCollection([$resource]); + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.dummy')->willReturn($metadata); + $metadata->getDriver()->willReturn('doctrine/dbal'); + + $result = $this->create('App\Resource'); + + $result + ->getOperation('app.dummy', 'app_dummy_create') + ->getProcessor() + ->shouldReturn(PersistProcessor::class) + ; + } + + function it_adds_remove_processor_to_delete_operations_for_resource_with_doctrine_driver( + ResourceMetadataCollectionFactoryInterface $decorated, + RegistryInterface $resourceRegistry, + MetadataInterface $metadata, + ): void { + $resource = new Resource(alias: 'app.dummy'); + $operation = new Delete(name: 'app_dummy_delete'); + $resource = $resource->withOperations(new Operations([$operation])); + + $resourceMetadataCollection = new ResourceMetadataCollection([$resource]); + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.dummy')->willReturn($metadata); + $metadata->getDriver()->willReturn('doctrine/orm'); + + $result = $this->create('App\Resource'); + + $result + ->getOperation('app.dummy', 'app_dummy_delete') + ->getProcessor() + ->shouldReturn(RemoveProcessor::class) + ; + } +} diff --git a/src/Component/spec/Doctrine/Common/State/PersistProcessorSpec.php b/src/Component/spec/Doctrine/Common/State/PersistProcessorSpec.php new file mode 100644 index 000000000..4460a5e43 --- /dev/null +++ b/src/Component/spec/Doctrine/Common/State/PersistProcessorSpec.php @@ -0,0 +1,113 @@ +beConstructedWith($managerRegistry); + } + + function it_is_initializable(): void + { + $this->shouldHaveType(PersistProcessor::class); + } + + function it_persists_data_when_manager_does_not_contains_the_resource_yet( + ManagerRegistry $managerRegistry, + Operation $operation, + ObjectManager $manager, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn($manager); + + $manager->contains($data)->willReturn(false); + + $manager->persist($data)->shouldBeCalled(); + $manager->flush()->shouldBeCalled(); + $manager->refresh($data)->shouldBeCalled(); + + $this->process($data, $operation, new Context()); + } + + function it_only_flush_when_manager_contains_the_resource( + ManagerRegistry $managerRegistry, + Operation $operation, + ObjectManager $manager, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn($manager); + + $manager->contains($data)->willReturn(true); + $manager->getClassMetadata(\stdClass::class)->willReturn($data); + + $manager->persist($data)->shouldNotBeCalled(); + + $manager->flush()->shouldBeCalled(); + $manager->refresh($data)->shouldBeCalled(); + + $this->process($data, $operation, new Context()); + } + + function it_persists_when_it_is_deferred_explicitly( + ManagerRegistry $managerRegistry, + Operation $operation, + ObjectManager $manager, + ClassMetadataInfo $classMetadataInfo, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn($manager); + + $manager->contains($data)->willReturn(true); + + $manager->getClassMetadata(\stdClass::class)->willReturn($classMetadataInfo); + + $classMetadataInfo->isChangeTrackingDeferredExplicit()->willReturn(true)->shouldBeCalled(); + + $manager->persist($data)->shouldBeCalled(); + $manager->flush()->shouldBeCalled(); + $manager->refresh($data)->shouldBeCalled(); + + $this->process($data, $operation, new Context()); + } + + function it_does_nothing_when_data_is_not_managed_by_doctrine( + ManagerRegistry $managerRegistry, + Operation $operation, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn(null); + + $this->process($data, $operation, new Context())->shouldReturn($data); + } + + function it_does_nothing_when_data_is_not_an_object( + Operation $operation, + ): void { + $this->process(1, $operation, new Context())->shouldReturn(1); + } +} diff --git a/src/Component/spec/Doctrine/Common/State/RemoveProcessorSpec.php b/src/Component/spec/Doctrine/Common/State/RemoveProcessorSpec.php new file mode 100644 index 000000000..6ac8daaea --- /dev/null +++ b/src/Component/spec/Doctrine/Common/State/RemoveProcessorSpec.php @@ -0,0 +1,68 @@ +beConstructedWith($managerRegistry); + } + + function it_is_initializable(): void + { + $this->shouldHaveType(RemoveProcessor::class); + } + + function it_removes_data( + ManagerRegistry $managerRegistry, + Operation $operation, + ObjectManager $manager, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn($manager); + + $manager->contains($data)->willReturn(false); + + $manager->remove($data)->shouldBeCalled(); + $manager->flush()->shouldBeCalled(); + + $this->process($data, $operation, new Context()); + } + + function it_does_nothing_when_data_is_not_managed_by_doctrine( + ManagerRegistry $managerRegistry, + Operation $operation, + ): void { + $data = new \stdClass(); + + $managerRegistry->getManagerForClass(\stdClass::class)->willReturn(null); + + $this->process($data, $operation, new Context())->shouldReturn(null); + } + + function it_does_nothing_when_data_is_not_an_object( + Operation $operation, + ): void { + $this->process(1, $operation, new Context())->shouldReturn(null); + } +}