Skip to content

Commit 6d65f89

Browse files
VincentLangletondrejmirtes
authored andcommitted
Add support for union of class string
1 parent a1ba454 commit 6d65f89

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

src/Type/Doctrine/GetRepositoryDynamicReturnTypeExtension.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use PHPStan\Type\ObjectType;
2222
use PHPStan\Type\ObjectWithoutClassType;
2323
use PHPStan\Type\Type;
24+
use PHPStan\Type\TypeCombinator;
2425
use function count;
2526

2627
class GetRepositoryDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
@@ -96,22 +97,26 @@ public function getTypeFromMethodCall(
9697

9798
$classType = $argType->getClassStringObjectType();
9899
$objectNames = $classType->getObjectClassNames();
99-
if (count($objectNames) !== 1) {
100+
101+
if (count($objectNames) === 0) {
100102
return new GenericObjectType(
101103
$defaultRepositoryClass,
102104
[$classType]
103105
);
104106
}
105107

106-
try {
107-
$repositoryClass = $this->getRepositoryClass($objectNames[0], $defaultRepositoryClass);
108-
} catch (\Doctrine\Persistence\Mapping\MappingException | MappingException | AnnotationException $e) {
109-
return $this->getDefaultReturnType($scope, $methodCall->getArgs(), $methodReflection, $defaultRepositoryClass);
108+
$repositoryTypes = [];
109+
foreach ($objectNames as $objectName) {
110+
try {
111+
$repositoryClass = $this->getRepositoryClass($objectName, $defaultRepositoryClass);
112+
} catch (\Doctrine\Persistence\Mapping\MappingException | MappingException | AnnotationException $e) {
113+
return $this->getDefaultReturnType($scope, $methodCall->getArgs(), $methodReflection, $defaultRepositoryClass);
114+
}
115+
116+
$repositoryTypes[] = new GenericObjectType($repositoryClass, [$classType]);
110117
}
111118

112-
return new GenericObjectType($repositoryClass, [
113-
$classType,
114-
]);
119+
return TypeCombinator::union(...$repositoryTypes);
115120
}
116121

117122
/**

tests/Rules/Doctrine/ORM/MagicRepositoryMethodCallRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ public function testRule(): void
8888
'Method Doctrine\Persistence\ObjectRepository<PHPStan\Rules\Doctrine\ORM\MyEntity>::countByTitle() invoked with 2 parameters, 1 required.',
8989
85,
9090
],
91+
[
92+
'Call to an undefined method PHPStan\Rules\Doctrine\ORM\TestRepository<PHPStan\Rules\Doctrine\ORM\MySecondEntity|PHPStan\Rules\Doctrine\ORM\MyThirdEntity>::findByTransient().',
93+
97,
94+
],
95+
[
96+
'Call to an undefined method PHPStan\Rules\Doctrine\ORM\TestRepository<PHPStan\Rules\Doctrine\ORM\MySecondEntity|PHPStan\Rules\Doctrine\ORM\MyThirdEntity>::findByNonexistent().',
97+
98,
98+
],
9199
]);
92100
}
93101

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Doctrine\ORM;
4+
5+
use Doctrine\ORM\Mapping as ORM;
6+
7+
/**
8+
* @ORM\Entity(repositoryClass="PHPStan\Rules\Doctrine\ORM\TestRepository")
9+
*/
10+
class MyThirdEntity
11+
{
12+
/**
13+
* @ORM\Id()
14+
* @ORM\GeneratedValue()
15+
* @ORM\Column(type="integer")
16+
*
17+
* @var int
18+
*/
19+
private $id;
20+
21+
/**
22+
* @var string
23+
* @ORM\Column(type="string")
24+
*/
25+
private $title;
26+
27+
/**
28+
* @var string
29+
*/
30+
private $transient;
31+
32+
}

tests/Rules/Doctrine/ORM/data/magic-repository.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,18 @@ public function doCountByWithOptionals(): void
8484
$entityRepository = $this->entityManager->getRepository(MyEntity::class);
8585
$entityRepository->countByTitle('test', ['id' => 'DESC']);
8686
}
87+
88+
/**
89+
* @param class-string<MySecondEntity|MyThirdEntity> $entityClass
90+
*/
91+
public function doFindByWithRepositoryOfMultiplesClasses(string $entityClass): void
92+
{
93+
$entityRepository = $this->entityManager->getRepository($entityClass);
94+
$entityRepository->findBy(['id' => 1]);
95+
$entityRepository->findById(1);
96+
$entityRepository->findByTitle('test');
97+
$entityRepository->findByTransient('test');
98+
$entityRepository->findByNonexistent('test');
99+
$entityRepository->findByCustomMethod();
100+
}
87101
}

0 commit comments

Comments
 (0)