44
55use PhpParser \Node \Expr \MethodCall ;
66use PHPStan \Analyser \Scope ;
7+ use PHPStan \Broker \Broker ;
8+ use PHPStan \Reflection \BrokerAwareExtension ;
79use PHPStan \Reflection \MethodReflection ;
10+ use PHPStan \Reflection \ParametersAcceptorSelector ;
811use PHPStan \Type \ArrayType ;
912use PHPStan \Type \IntegerType ;
1013use PHPStan \Type \MixedType ;
1114use PHPStan \Type \ObjectType ;
1215use PHPStan \Type \Type ;
1316use PHPStan \Type \TypeCombinator ;
17+ use PHPStan \Type \TypeWithClassName ;
1418
15- class ObjectRepositoryDynamicReturnTypeExtension implements \PHPStan \Type \DynamicMethodReturnTypeExtension
19+ class ObjectRepositoryDynamicReturnTypeExtension implements \PHPStan \Type \DynamicMethodReturnTypeExtension, BrokerAwareExtension
1620{
1721
22+ /** @var Broker */
23+ private $ broker ;
24+
25+ public function setBroker (Broker $ broker ): void
26+ {
27+ $ this ->broker = $ broker ;
28+ }
29+
1830 public function getClass (): string
1931 {
2032 return 'Doctrine\Common\Persistence\ObjectRepository ' ;
@@ -36,10 +48,35 @@ public function getTypeFromMethodCall(
3648 ): Type
3749 {
3850 $ calledOnType = $ scope ->getType ($ methodCall ->var );
39- if (!$ calledOnType instanceof ObjectRepositoryType ) {
51+ if (!$ calledOnType instanceof TypeWithClassName ) {
4052 return new MixedType ();
4153 }
54+
4255 $ methodName = $ methodReflection ->getName ();
56+ $ repositoryClassReflection = $ this ->broker ->getClass ($ calledOnType ->getClassName ());
57+ if (
58+ (
59+ (
60+ strpos ($ methodName , 'findBy ' ) === 0
61+ && strlen ($ methodName ) > strlen ('findBy ' )
62+ ) || (
63+ strpos ($ methodName , 'findOneBy ' ) === 0
64+ && strlen ($ methodName ) > strlen ('findOneBy ' )
65+ )
66+ )
67+ && $ repositoryClassReflection ->hasNativeMethod ($ methodName )
68+ ) {
69+ return ParametersAcceptorSelector::selectFromArgs (
70+ $ scope ,
71+ $ methodCall ->args ,
72+ $ repositoryClassReflection ->getNativeMethod ($ methodName )->getVariants ()
73+ )->getReturnType ();
74+ }
75+
76+ if (!$ calledOnType instanceof ObjectRepositoryType) {
77+ return new MixedType ();
78+ }
79+
4380 $ entityType = new ObjectType ($ calledOnType ->getEntityClass ());
4481
4582 if ($ methodName === 'find ' || strpos ($ methodName , 'findOneBy ' ) === 0 ) {
0 commit comments