From ad3850aec1afae14c2a462988f64edf2289c3a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 18 Aug 2018 15:03:45 +0200 Subject: [PATCH 1/5] Add integration test for entity manager dynamic return --- phpstan.neon | 4 ++ .../ORM/EntityManagerIntegrationTest.php | 33 ++++++++++ .../ORM/data/entityManagerDynamicReturn.php | 62 +++++++++++++++++++ tests/DoctrineIntegration/ORM/phpstan.neon | 2 + 4 files changed, 101 insertions(+) create mode 100644 tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturn.php create mode 100644 tests/DoctrineIntegration/ORM/phpstan.neon diff --git a/phpstan.neon b/phpstan.neon index 78c68c2d..d72de844 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,3 +2,7 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon + +parameters: + excludes_analyse: + - */tests/*/data/* diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php new file mode 100644 index 00000000..ec75b48f --- /dev/null +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -0,0 +1,33 @@ +entityManager = $entityManager; + } + + public function findDynamicType(): void + { + $test = $this->entityManager->find(MyEntity::class, 1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function getReferenceDynamicType(): void + { + $test = $this->entityManager->getReference(MyEntity::class, 1); + $test->doSomething(); + } + + public function getPartialReferenceDynamicType(): void + { + $test = $this->entityManager->getPartialReference(MyEntity::class, 1); + $test->doSomething(); + } +} + +/** + * @ORM\Entity() + */ +class MyEntity +{ + /** + * @ORM\Id() + * @ORM\GeneratedValue() + * @ORM\Column(type="integer") + * + * @var int + */ + private $id; + + public function doSomething(): void + { + } +} diff --git a/tests/DoctrineIntegration/ORM/phpstan.neon b/tests/DoctrineIntegration/ORM/phpstan.neon new file mode 100644 index 00000000..e6dd2808 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/phpstan.neon @@ -0,0 +1,2 @@ +includes: + - ../../../extension.neon From 68786efc0986e234875702a1aae79e8633f97aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 18 Aug 2018 15:04:40 +0200 Subject: [PATCH 2/5] Fix return type of entity manager dynamic return The methods `EntityManagerInterface#getReference()` and `EntityManagerInterface#getPartialReference()` have nullable return. That's properly documented for `getReference()` but had to be fixed for `getPartialReference()`. --- .../EntityManagerFindDynamicReturnTypeExtension.php | 7 +------ .../ORM/data/entityManagerDynamicReturn.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php b/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php index 2498cc8d..fa0884d6 100644 --- a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php @@ -43,12 +43,7 @@ public function getTypeFromMethodCall( return $mixedType; } - $type = new ObjectType($argType->getValue()); - if ($methodReflection->getName() === 'find') { - $type = TypeCombinator::addNull($type); - } - - return $type; + return TypeCombinator::addNull(new ObjectType($argType->getValue())); } } diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturn.php b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturn.php index 71b2cade..0f18ec85 100644 --- a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturn.php +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturn.php @@ -32,12 +32,22 @@ public function findDynamicType(): void public function getReferenceDynamicType(): void { $test = $this->entityManager->getReference(MyEntity::class, 1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + $test->doSomething(); } public function getPartialReferenceDynamicType(): void { $test = $this->entityManager->getPartialReference(MyEntity::class, 1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + $test->doSomething(); } } From b2fb483b41e70e7e60c5984944bd2d7bbcdaa974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 18 Aug 2018 15:22:13 +0200 Subject: [PATCH 3/5] Add integration test for entity repository dynamic return --- .../ORM/EntityManagerIntegrationTest.php | 5 +- .../data/entityRepositoryDynamicReturn.php | 80 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/DoctrineIntegration/ORM/data/entityRepositoryDynamicReturn.php diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php index ec75b48f..b41bf007 100644 --- a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -12,7 +12,10 @@ final class EntityManagerIntegrationTest extends LevelsTestCase */ public function dataTopics(): array { - return [['entityManagerDynamicReturn']]; + return [ + ['entityManagerDynamicReturn'], + ['entityRepositoryDynamicReturn'], + ]; } public function getDataPath(): string diff --git a/tests/DoctrineIntegration/ORM/data/entityRepositoryDynamicReturn.php b/tests/DoctrineIntegration/ORM/data/entityRepositoryDynamicReturn.php new file mode 100644 index 00000000..d26b037d --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityRepositoryDynamicReturn.php @@ -0,0 +1,80 @@ +repository = $entityManager->getRepository(MyEntity::class); + } + + public function findDynamicType(): void + { + $test = $this->repository->find(1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function findOneByDynamicType(): void + { + $test = $this->repository->findOneBy(['blah' => 'testing']); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function findAllDynamicType(): void + { + $items = $this->repository->findAll(); + + foreach ($items as $test) { + $test->doSomething(); + } + } + + public function findByDynamicType(): void + { + $items = $this->repository->findBy(['blah' => 'testing']); + + foreach ($items as $test) { + $test->doSomething(); + } + } +} + +/** + * @ORM\Entity() + */ +class MyEntity +{ + /** + * @ORM\Id() + * @ORM\GeneratedValue() + * @ORM\Column(type="integer") + * + * @var int + */ + private $id; + + public function doSomething(): void + { + } +} From 2c6400376fab08d91cc17105e28da19726d0ae59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 18 Aug 2018 18:10:09 +0200 Subject: [PATCH 4/5] Add integration tests for entity manager merge return --- .../ORM/EntityManagerIntegrationTest.php | 1 + .../ORM/data/entityManagerMergeReturn.php | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerMergeReturn.php diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php index b41bf007..a6353a59 100644 --- a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -15,6 +15,7 @@ public function dataTopics(): array return [ ['entityManagerDynamicReturn'], ['entityRepositoryDynamicReturn'], + ['entityManagerMergeReturn'], ]; } diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerMergeReturn.php b/tests/DoctrineIntegration/ORM/data/entityManagerMergeReturn.php new file mode 100644 index 00000000..b72a5df2 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerMergeReturn.php @@ -0,0 +1,44 @@ +entityManager = $entityManager; + } + + public function merge(): void + { + $test = $this->entityManager->merge(new MyEntity()); + $test->doSomething(); + } +} + +/** + * @ORM\Entity() + */ +class MyEntity +{ + /** + * @ORM\Id() + * @ORM\GeneratedValue() + * @ORM\Column(type="integer") + * + * @var int + */ + private $id; + + public function doSomething(): void + { + } +} From cd96d3219a576ebe02f83da8e7dfcc602d17ca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Sat, 18 Aug 2018 18:30:48 +0200 Subject: [PATCH 5/5] Use abstract names provided by doctrine/persistence So that things would be compatible with both ORM and ODM. --- extension.neon | 6 +++--- ....php => ObjectManagerFindDynamicReturnTypeExtension.php} | 2 +- ...bjectManagerGetRepositoryDynamicReturnTypeExtension.php} | 4 ++-- ...n.php => ObjectRepositoryDynamicReturnTypeExtension.php} | 6 +++--- .../{EntityRepositoryType.php => ObjectRepositoryType.php} | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) rename src/Type/Doctrine/{EntityManagerFindDynamicReturnTypeExtension.php => ObjectManagerFindDynamicReturnTypeExtension.php} (94%) rename src/Type/Doctrine/{EntityManagerGetRepositoryDynamicReturnTypeExtension.php => ObjectManagerGetRepositoryDynamicReturnTypeExtension.php} (90%) rename src/Type/Doctrine/{EntityRepositoryDynamicReturnTypeExtension.php => ObjectRepositoryDynamicReturnTypeExtension.php} (87%) rename src/Type/Doctrine/{EntityRepositoryType.php => ObjectRepositoryType.php} (92%) diff --git a/extension.neon b/extension.neon index 21e8e248..25fa2283 100644 --- a/extension.neon +++ b/extension.neon @@ -12,11 +12,11 @@ services: tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\EntityManagerFindDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectManagerFindDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\EntityManagerGetRepositoryDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension arguments: repositoryClass: %doctrine.repositoryClass% tags: @@ -26,6 +26,6 @@ services: tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\EntityRepositoryDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectRepositoryDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension diff --git a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php similarity index 94% rename from src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php rename to src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php index fa0884d6..f0c5fa26 100644 --- a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php @@ -11,7 +11,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -class EntityManagerFindDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class ObjectManagerFindDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { public function getClass(): string diff --git a/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php similarity index 90% rename from src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php rename to src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php index b383c18f..871f12b0 100644 --- a/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php @@ -10,7 +10,7 @@ use PHPStan\Type\MixedType; use PHPStan\Type\Type; -class EntityManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class ObjectManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { /** @var string */ @@ -47,7 +47,7 @@ public function getTypeFromMethodCall( return new MixedType(); } - return new EntityRepositoryType($argType->getValue(), $this->repositoryClass); + return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass); } } diff --git a/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php similarity index 87% rename from src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php rename to src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php index b542508c..be363648 100644 --- a/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php @@ -12,12 +12,12 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -class EntityRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class ObjectRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { public function getClass(): string { - return 'Doctrine\ORM\EntityRepository'; + return 'Doctrine\Common\Persistence\ObjectRepository'; } public function isMethodSupported(MethodReflection $methodReflection): bool @@ -36,7 +36,7 @@ public function getTypeFromMethodCall( ): Type { $calledOnType = $scope->getType($methodCall->var); - if (!$calledOnType instanceof EntityRepositoryType) { + if (!$calledOnType instanceof ObjectRepositoryType) { return new MixedType(); } $methodName = $methodReflection->getName(); diff --git a/src/Type/Doctrine/EntityRepositoryType.php b/src/Type/Doctrine/ObjectRepositoryType.php similarity index 92% rename from src/Type/Doctrine/EntityRepositoryType.php rename to src/Type/Doctrine/ObjectRepositoryType.php index 49c8c510..f5538b35 100644 --- a/src/Type/Doctrine/EntityRepositoryType.php +++ b/src/Type/Doctrine/ObjectRepositoryType.php @@ -5,7 +5,7 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\VerbosityLevel; -class EntityRepositoryType extends ObjectType +class ObjectRepositoryType extends ObjectType { /** @var string */