From 496aee16d0abed4e75d4d4b8901abbc35cbc68bd Mon Sep 17 00:00:00 2001 From: Maciej Malarz Date: Wed, 13 Dec 2017 13:24:27 +0100 Subject: [PATCH 1/4] Resolve custom repository classes --- extension.neon | 9 ++- src/DoctrineClassMetadataProvider.php | 81 +++++++++++++++++++ ...etRepositoryDynamicReturnTypeExtension.php | 36 ++++++++- 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 src/DoctrineClassMetadataProvider.php diff --git a/extension.neon b/extension.neon index 87b2841a..1b5b841b 100644 --- a/extension.neon +++ b/extension.neon @@ -1,6 +1,7 @@ parameters: doctrine: repositoryClass: Doctrine\ORM\EntityRepository + metadata: [] allCollectionsSelectable: true conditionalTags: @@ -21,7 +22,7 @@ services: - class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension arguments: - repositoryClass: %doctrine.repositoryClass% + metadataProvider: @PHPStan\DoctrineClassMetadataProvider tags: - phpstan.broker.dynamicMethodReturnTypeExtension - @@ -32,3 +33,9 @@ services: class: PHPStan\Type\Doctrine\ObjectRepositoryDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\DoctrineClassMetadataProvider + arguments: + repositoryClass: %doctrine.repositoryClass% + mapping: %doctrine.metadata% + diff --git a/src/DoctrineClassMetadataProvider.php b/src/DoctrineClassMetadataProvider.php new file mode 100644 index 00000000..41169ea7 --- /dev/null +++ b/src/DoctrineClassMetadataProvider.php @@ -0,0 +1,81 @@ +setDefaultRepositoryClassName($repositoryClass); + $configuration->setMetadataDriverImpl($this->setupMappingDriver($mapping)); + $configuration->setProxyDir('/dev/null'); + $configuration->setProxyNamespace('__DP__'); + $configuration->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_EVAL); + $evm = new EventManager(); + $this->em = EntityManager::create( + \Doctrine\DBAL\DriverManager::getConnection(['host' => '/:memory:', 'driver' => 'pdo_sqlite'], $configuration, $evm), + $configuration, + $evm + ); + $this->repositoryClass = $repositoryClass; + } + + private function setupMappingDriver(array $mapping): MappingDriver + { + $driver = new MappingDriverChain(); + foreach ($mapping as $namespace => $config) { + switch ($config['type']) { + case 'annotation': + $nested = new Mapping\Driver\AnnotationDriver(new AnnotationReader(), $config['paths']); + break; + case 'yml': + case 'yaml': + $nested = new Mapping\Driver\YamlDriver($config['paths']); + break; + case 'xml': + $nested = new Mapping\Driver\XmlDriver($config['paths']); + break; + default: + throw new \InvalidArgumentException('Unknown mapping type: ' . $config['type']); + } + $driver->addDriver($nested, $namespace); + } + return $driver; + } + + public function getBaseRepositoryClass(): string + { + return $this->repositoryClass; + } + + /** + * @throws \Doctrine\Common\Persistence\Mapping\MappingException + * @throws \ReflectionException + */ + public function getMetadataFor(string $className): Mapping\ClassMetadataInfo + { + return $this->em->getClassMetadata($className); + } + +} diff --git a/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php index 871f12b0..fb46daa2 100644 --- a/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php @@ -2,8 +2,11 @@ namespace PHPStan\Type\Doctrine; +use Doctrine\Common\Annotations\AnnotationRegistry; +use Doctrine\Common\Persistence\Mapping\MappingException; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; +use PHPStan\DoctrineClassMetadataProvider; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\Constant\ConstantStringType; @@ -16,10 +19,16 @@ class ObjectManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\T /** @var string */ private $repositoryClass; - public function __construct(string $repositoryClass) + /** + * @var DoctrineClassMetadataProvider + */ + private $metadataProvider; + + public function __construct(DoctrineClassMetadataProvider $metadataProvider) { - $this->repositoryClass = $repositoryClass; - } + $this->metadataProvider = $metadataProvider; + AnnotationRegistry::registerLoader('class_exists'); + } public function getClass(): string { @@ -48,6 +57,27 @@ public function getTypeFromMethodCall( } return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass); + + $class = $arg->class; + if (!($class instanceof \PhpParser\Node\Name)) { + return $methodReflection->getReturnType(); + } + + $class = (string) $class; + if ($class === 'static') { + return $methodReflection->getReturnType(); + } + + if ($class === 'self') { + $class = $scope->getClassReflection()->getName(); + } + + try { + $metadata = $this->metadataProvider->getMetadataFor($class); + return new EntityRepositoryType($class, $metadata->customRepositoryClassName ?: $this->metadataProvider->getBaseRepositoryClass()); + } catch (MappingException $e) { + return new EntityRepositoryType($class, $this->metadataProvider->getBaseRepositoryClass()); + } } } From df0181315b2570652708785223e1937de09a9008 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 12 Feb 2019 12:14:09 +0200 Subject: [PATCH 2/4] Fixed --- src/DoctrineClassMetadataProvider.php | 130 ++++++++++-------- ...etRepositoryDynamicReturnTypeExtension.php | 41 +----- .../ORM/EntityManagerIntegrationTest.php | 1 + .../entityManagerDynamicReturnRepository.php | 61 ++++++++ tests/DoctrineIntegration/ORM/phpstan.neon | 6 + 5 files changed, 145 insertions(+), 94 deletions(-) create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php diff --git a/src/DoctrineClassMetadataProvider.php b/src/DoctrineClassMetadataProvider.php index 41169ea7..bc351076 100644 --- a/src/DoctrineClassMetadataProvider.php +++ b/src/DoctrineClassMetadataProvider.php @@ -3,9 +3,11 @@ namespace PHPStan; use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\Common\Annotations\AnnotationRegistry; use Doctrine\Common\EventManager; use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain; +use Doctrine\Common\Persistence\Mapping\MappingException; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping; @@ -14,68 +16,78 @@ class DoctrineClassMetadataProvider { - /** - * @var EntityManager - */ - private $em; + /** @var ?EntityManager */ + private $em; - /** - * @var string - */ - private $repositoryClass; + /** @var string */ + private $repositoryClass; - public function __construct(string $repositoryClass, array $mapping) - { - $configuration = new Configuration(); - $configuration->setDefaultRepositoryClassName($repositoryClass); - $configuration->setMetadataDriverImpl($this->setupMappingDriver($mapping)); - $configuration->setProxyDir('/dev/null'); - $configuration->setProxyNamespace('__DP__'); - $configuration->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_EVAL); - $evm = new EventManager(); - $this->em = EntityManager::create( - \Doctrine\DBAL\DriverManager::getConnection(['host' => '/:memory:', 'driver' => 'pdo_sqlite'], $configuration, $evm), - $configuration, - $evm - ); - $this->repositoryClass = $repositoryClass; - } + /** + * @param string $repositoryClass + * @param mixed[] $mapping + */ + public function __construct(string $repositoryClass, array $mapping) + { + if (count($mapping) > 0) { + $configuration = new Configuration(); + $configuration->setDefaultRepositoryClassName($repositoryClass); + $configuration->setMetadataDriverImpl($this->setupMappingDriver($mapping)); + $configuration->setProxyDir('/dev/null'); + $configuration->setProxyNamespace('__DP__'); + $configuration->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_EVAL); + $evm = new EventManager(); + $this->em = EntityManager::create( + \Doctrine\DBAL\DriverManager::getConnection(['host' => '/:memory:', 'driver' => 'pdo_sqlite'], $configuration, $evm), + $configuration, + $evm + ); + } + $this->repositoryClass = $repositoryClass; + } - private function setupMappingDriver(array $mapping): MappingDriver - { - $driver = new MappingDriverChain(); - foreach ($mapping as $namespace => $config) { - switch ($config['type']) { - case 'annotation': - $nested = new Mapping\Driver\AnnotationDriver(new AnnotationReader(), $config['paths']); - break; - case 'yml': - case 'yaml': - $nested = new Mapping\Driver\YamlDriver($config['paths']); - break; - case 'xml': - $nested = new Mapping\Driver\XmlDriver($config['paths']); - break; - default: - throw new \InvalidArgumentException('Unknown mapping type: ' . $config['type']); - } - $driver->addDriver($nested, $namespace); - } - return $driver; - } + /** + * @param mixed[] $mapping + */ + private function setupMappingDriver(array $mapping): MappingDriver + { + $driver = new MappingDriverChain(); + foreach ($mapping as $namespace => $config) { + switch ($config['type']) { + case 'annotation': + AnnotationRegistry::registerUniqueLoader('class_exists'); + $nested = new Mapping\Driver\AnnotationDriver(new AnnotationReader(), $config['paths']); + break; + case 'yml': + case 'yaml': + $nested = new Mapping\Driver\YamlDriver($config['paths']); + break; + case 'xml': + $nested = new Mapping\Driver\XmlDriver($config['paths']); + break; + default: + throw new \InvalidArgumentException('Unknown mapping type: ' . $config['type']); + } + $driver->addDriver($nested, $namespace); + } + return $driver; + } - public function getBaseRepositoryClass(): string - { - return $this->repositoryClass; - } + public function getBaseRepositoryClass(): string + { + return $this->repositoryClass; + } + + public function getRepositoryClass(string $className): string + { + if ($this->em === null) { + return $this->getBaseRepositoryClass(); + } + + try { + return $this->em->getClassMetadata($className)->customRepositoryClassName ?: $this->getBaseRepositoryClass(); + } catch (MappingException $e) { + return $this->getBaseRepositoryClass(); + } + } - /** - * @throws \Doctrine\Common\Persistence\Mapping\MappingException - * @throws \ReflectionException - */ - public function getMetadataFor(string $className): Mapping\ClassMetadataInfo - { - return $this->em->getClassMetadata($className); - } - } diff --git a/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php index fb46daa2..f0d52100 100644 --- a/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php @@ -2,8 +2,6 @@ namespace PHPStan\Type\Doctrine; -use Doctrine\Common\Annotations\AnnotationRegistry; -use Doctrine\Common\Persistence\Mapping\MappingException; use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\DoctrineClassMetadataProvider; @@ -16,19 +14,13 @@ class ObjectManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { - /** @var string */ - private $repositoryClass; + /** @var DoctrineClassMetadataProvider */ + private $metadataProvider; - /** - * @var DoctrineClassMetadataProvider - */ - private $metadataProvider; - - public function __construct(DoctrineClassMetadataProvider $metadataProvider) + public function __construct(DoctrineClassMetadataProvider $metadataProvider) { - $this->metadataProvider = $metadataProvider; - AnnotationRegistry::registerLoader('class_exists'); - } + $this->metadataProvider = $metadataProvider; + } public function getClass(): string { @@ -56,28 +48,7 @@ public function getTypeFromMethodCall( return new MixedType(); } - return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass); - - $class = $arg->class; - if (!($class instanceof \PhpParser\Node\Name)) { - return $methodReflection->getReturnType(); - } - - $class = (string) $class; - if ($class === 'static') { - return $methodReflection->getReturnType(); - } - - if ($class === 'self') { - $class = $scope->getClassReflection()->getName(); - } - - try { - $metadata = $this->metadataProvider->getMetadataFor($class); - return new EntityRepositoryType($class, $metadata->customRepositoryClassName ?: $this->metadataProvider->getBaseRepositoryClass()); - } catch (MappingException $e) { - return new EntityRepositoryType($class, $this->metadataProvider->getBaseRepositoryClass()); - } + return new ObjectRepositoryType($argType->getValue(), $this->metadataProvider->getRepositoryClass($argType->getValue())); } } diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php index a6353a59..292f1485 100644 --- a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -15,6 +15,7 @@ public function dataTopics(): array return [ ['entityManagerDynamicReturn'], ['entityRepositoryDynamicReturn'], + ['entityManagerDynamicReturnRepository'], ['entityManagerMergeReturn'], ]; } diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php new file mode 100644 index 00000000..38e4b7d8 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php @@ -0,0 +1,61 @@ +entityManager = $entityManager; + } + + public function findDynamicType(): void + { + $test = $this->entityManager->getRepository(MyEntity::class)->findMyEntity(1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } +} + +/** + * @ORM\Entity(repositoryClass="MyEntityRepository") + */ +class MyEntity +{ + /** + * @ORM\Id() + * @ORM\GeneratedValue() + * @ORM\Column(type="integer") + * + * @var int + */ + private $id; + + public function doSomething(): void + { + } +} + +class MyEntityRepository extends EntityRepository +{ + public function findMyEntity($id): ?MyEntity + { + return $this->findOneBy([ + 'id' => $id + ]); + } +} diff --git a/tests/DoctrineIntegration/ORM/phpstan.neon b/tests/DoctrineIntegration/ORM/phpstan.neon index e6dd2808..c6f6fddf 100644 --- a/tests/DoctrineIntegration/ORM/phpstan.neon +++ b/tests/DoctrineIntegration/ORM/phpstan.neon @@ -1,2 +1,8 @@ includes: - ../../../extension.neon +parameters: + doctrine: + metadata: + PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnRepository: + type: annotation + paths: [] From d492221393f7e78bb922b6b92df198770db1fe00 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 12 Feb 2019 13:17:04 +0200 Subject: [PATCH 3/4] Update composer json with extra dependencyes for the require-checker --- composer.json | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 5148ff56..280f7145 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,13 @@ "require": { "php": "~7.1", "phpstan/phpstan": "^0.11", - "nikic/php-parser": "^4.0" + "nikic/php-parser": "^4.0", + "doctrine/orm": "^2.5", + "doctrine/common": "^2.7", + "doctrine/annotations": "^1.5", + "doctrine/persistence": "^1.1", + "doctrine/dbal": "^2.5", + "doctrine/event-manager": "^1.0" }, "require-dev": { "consistence/coding-standard": "^3.0.1", @@ -23,15 +29,8 @@ "phpstan/phpstan-strict-rules": "^0.11", "phpunit/phpunit": "^7.0", "slevomat/coding-standard": "^4.5.2", - "doctrine/common": "^2.7", - "doctrine/orm": "^2.5", "doctrine/collections": "^1.0" }, - "conflict": { - "doctrine/common": "<2.7", - "doctrine/orm": "<2.5", - "doctrine/collections": "<1.0" - }, "autoload": { "psr-4": { "PHPStan\\": "src/" From 733a3e8abc2aa0b3bdbb7ad1f33064565210d4ee Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 12 Feb 2019 15:16:45 +0200 Subject: [PATCH 4/4] Add tests for xml and yaml mappings --- .../ORM/EntityManagerIntegrationTest.php | 4 +- ...icReturnCustomRepositoryAnnotations-2.json | 7 +++ ...amicReturnCustomRepositoryAnnotations.php} | 7 ++- ...gerDynamicReturnCustomRepositoryXml-2.json | 7 +++ ...anagerDynamicReturnCustomRepositoryXml.php | 56 +++++++++++++++++++ ...gerDynamicReturnCustomRepositoryYml-2.json | 7 +++ ...anagerDynamicReturnCustomRepositoryYml.php | 56 +++++++++++++++++++ ...ReturnCustomRepositoryXml.MyEntity.dcm.xml | 8 +++ ...ReturnCustomRepositoryYml.MyEntity.dcm.yml | 8 +++ tests/DoctrineIntegration/ORM/phpstan.neon | 10 +++- 10 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations-2.json rename tests/DoctrineIntegration/ORM/data/{entityManagerDynamicReturnRepository.php => entityManagerDynamicReturnCustomRepositoryAnnotations.php} (87%) create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml-2.json create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml.php create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml-2.json create mode 100644 tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml.php create mode 100644 tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryXml.MyEntity.dcm.xml create mode 100644 tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryYml.MyEntity.dcm.yml diff --git a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php index 292f1485..27ec7503 100644 --- a/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php +++ b/tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php @@ -14,8 +14,10 @@ public function dataTopics(): array { return [ ['entityManagerDynamicReturn'], + ['entityManagerDynamicReturnCustomRepositoryAnnotations'], + ['entityManagerDynamicReturnCustomRepositoryXml'], + ['entityManagerDynamicReturnCustomRepositoryYml'], ['entityRepositoryDynamicReturn'], - ['entityManagerDynamicReturnRepository'], ['entityManagerMergeReturn'], ]; } diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations-2.json b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations-2.json new file mode 100644 index 00000000..ed64c52e --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations-2.json @@ -0,0 +1,7 @@ +[ + { + "message": "Call to an undefined method PHPStan\\DoctrineIntegration\\ORM\\EntityManagerDynamicReturnCustomRepositoryAnnotations\\MyEntityRepository::nonexistant().", + "line": 35, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations.php similarity index 87% rename from tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php rename to tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations.php index 38e4b7d8..7818c10c 100644 --- a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnRepository.php +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryAnnotations.php @@ -1,6 +1,6 @@ doSomething(); } + + public function errorDynamicType(): void + { + $this->entityManager->getRepository(MyEntity::class)->nonexistant(); + } } /** diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml-2.json b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml-2.json new file mode 100644 index 00000000..55597387 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml-2.json @@ -0,0 +1,7 @@ +[ + { + "message": "Call to an undefined method PHPStan\\DoctrineIntegration\\ORM\\EntityManagerDynamicReturnCustomRepositoryXml\\MyEntityRepository::nonexistant().", + "line": 35, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml.php b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml.php new file mode 100644 index 00000000..a2ba1080 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryXml.php @@ -0,0 +1,56 @@ +entityManager = $entityManager; + } + + public function findDynamicType(): void + { + $test = $this->entityManager->getRepository(MyEntity::class)->findMyEntity(1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function errorDynamicType(): void + { + $this->entityManager->getRepository(MyEntity::class)->nonexistant(); + } +} + +class MyEntity +{ + private $id; + + public function doSomething(): void + { + } +} + +class MyEntityRepository extends EntityRepository +{ + public function findMyEntity($id): ?MyEntity + { + return $this->findOneBy([ + 'id' => $id + ]); + } +} diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml-2.json b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml-2.json new file mode 100644 index 00000000..f698df88 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml-2.json @@ -0,0 +1,7 @@ +[ + { + "message": "Call to an undefined method PHPStan\\DoctrineIntegration\\ORM\\EntityManagerDynamicReturnCustomRepositoryYml\\MyEntityRepository::nonexistant().", + "line": 35, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml.php b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml.php new file mode 100644 index 00000000..69cf89b1 --- /dev/null +++ b/tests/DoctrineIntegration/ORM/data/entityManagerDynamicReturnCustomRepositoryYml.php @@ -0,0 +1,56 @@ +entityManager = $entityManager; + } + + public function findDynamicType(): void + { + $test = $this->entityManager->getRepository(MyEntity::class)->findMyEntity(1); + + if ($test === null) { + throw new RuntimeException('Sorry, but no...'); + } + + $test->doSomething(); + } + + public function errorDynamicType(): void + { + $this->entityManager->getRepository(MyEntity::class)->nonexistant(); + } +} + +class MyEntity +{ + private $id; + + public function doSomething(): void + { + } +} + +class MyEntityRepository extends EntityRepository +{ + public function findMyEntity($id): ?MyEntity + { + return $this->findOneBy([ + 'id' => $id + ]); + } +} diff --git a/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryXml.MyEntity.dcm.xml b/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryXml.MyEntity.dcm.xml new file mode 100644 index 00000000..cc7f2edd --- /dev/null +++ b/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryXml.MyEntity.dcm.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryYml.MyEntity.dcm.yml b/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryYml.MyEntity.dcm.yml new file mode 100644 index 00000000..74739e1e --- /dev/null +++ b/tests/DoctrineIntegration/ORM/mappings/PHPStan.DoctrineIntegration.ORM.EntityManagerDynamicReturnCustomRepositoryYml.MyEntity.dcm.yml @@ -0,0 +1,8 @@ +PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnCustomRepositoryYml\MyEntity: + type: entity + repositoryClass: PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnCustomRepositoryYml\MyEntityRepository + id: + id: + type: integer + generator: + strategy: AUTO diff --git a/tests/DoctrineIntegration/ORM/phpstan.neon b/tests/DoctrineIntegration/ORM/phpstan.neon index c6f6fddf..8d035ab1 100644 --- a/tests/DoctrineIntegration/ORM/phpstan.neon +++ b/tests/DoctrineIntegration/ORM/phpstan.neon @@ -3,6 +3,14 @@ includes: parameters: doctrine: metadata: - PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnRepository: + PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnCustomRepositoryAnnotations: type: annotation paths: [] + PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnCustomRepositoryXml: + type: xml + paths: + - tests/DoctrineIntegration/ORM/mappings/ + PHPStan\DoctrineIntegration\ORM\EntityManagerDynamicReturnCustomRepositoryYml: + type: yml + paths: + - tests/DoctrineIntegration/ORM/mappings/