diff --git a/.travis.yml b/.travis.yml index 7f46b336..06f69511 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ php: - 7.1 - 7.2 before_script: + - pecl install -f mongodb-stable - composer self-update - composer install script: diff --git a/composer.json b/composer.json index 6b438d95..e7991569 100644 --- a/composer.json +++ b/composer.json @@ -25,12 +25,15 @@ "slevomat/coding-standard": "^4.5.2", "doctrine/common": "^2.7", "doctrine/orm": "^2.5", - "doctrine/collections": "^1.0" + "doctrine/collections": "^1.0", + "doctrine/mongodb-odm": "^1.2", + "alcaeus/mongo-php-adapter": "^1.1" }, "conflict": { "doctrine/common": "<2.7", "doctrine/orm": "<2.5", - "doctrine/collections": "<1.0" + "doctrine/collections": "<1.0", + "doctrine/mongodb-odm": "<1.2" }, "autoload": { "psr-4": { @@ -39,5 +42,10 @@ }, "autoload-dev": { "classmap": ["tests/"] + }, + "config": { + "platform": { + "ext-mongo": "1.6.16" + } } } 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/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/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php similarity index 82% rename from src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php rename to src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php index 2498cc8d..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 @@ -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/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 */ diff --git a/tests/DoctrineIntegration/ODM/DocumentManagerIntegrationTest.php b/tests/DoctrineIntegration/ODM/DocumentManagerIntegrationTest.php new file mode 100644 index 00000000..f46b795b --- /dev/null +++ b/tests/DoctrineIntegration/ODM/DocumentManagerIntegrationTest.php @@ -0,0 +1,37 @@ +documentManager = $documentManager; + } + + public function findDynamicType(): void + { + $test = $this->documentManager->find(MyDocument::class, 'blah-123'); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function getReferenceDynamicType(): void + { + $test = $this->documentManager->getReference(MyDocument::class, 'blah-123'); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function getPartialReferenceDynamicType(): void + { + $test = $this->documentManager->getPartialReference(MyDocument::class, 'blah-123'); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } +} + +/** + * @Document() + */ +class MyDocument +{ + /** + * @Id(strategy="NONE", type="string") + * + * @var string + */ + private $id; + + public function doSomething(): void + { + } +} diff --git a/tests/DoctrineIntegration/ODM/data/documentManagerMergeReturn.php b/tests/DoctrineIntegration/ODM/data/documentManagerMergeReturn.php new file mode 100644 index 00000000..4a190fe1 --- /dev/null +++ b/tests/DoctrineIntegration/ODM/data/documentManagerMergeReturn.php @@ -0,0 +1,43 @@ +documentManager = $documentManager; + } + + public function merge(): void + { + $test = $this->documentManager->merge(new MyDocument()); + $test->doSomething(); + } +} + +/** + * @Document() + */ +class MyDocument +{ + /** + * @Id(strategy="NONE", type="string") + * + * @var string + */ + private $id; + + public function doSomething(): void + { + } +} diff --git a/tests/DoctrineIntegration/ODM/data/documentRepositoryDynamicReturn.php b/tests/DoctrineIntegration/ODM/data/documentRepositoryDynamicReturn.php new file mode 100644 index 00000000..590bdedc --- /dev/null +++ b/tests/DoctrineIntegration/ODM/data/documentRepositoryDynamicReturn.php @@ -0,0 +1,79 @@ +repository = $documentManager->getRepository(MyDocument::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(); + } + } +} + +/** + * @Document() + */ +class MyDocument +{ + /** + * @Id(strategy="NONE", type="string") + * + * @var string + */ + private $id; + + public function doSomething(): void + { + } +} diff --git a/tests/DoctrineIntegration/ODM/phpstan.neon b/tests/DoctrineIntegration/ODM/phpstan.neon new file mode 100644 index 00000000..446f214a --- /dev/null +++ b/tests/DoctrineIntegration/ODM/phpstan.neon @@ -0,0 +1,6 @@ +includes: + - ../../../extension.neon + +parameters: + doctrine: + repositoryClass: Doctrine\ODM\MongoDB\DocumentRepository diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php new file mode 100644 index 00000000..a6353a59 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -0,0 +1,37 @@ +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); + + 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(); + } +} + +/** + * @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/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 + { + } +} 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 + { + } +} 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