Skip to content

Commit ec12e6f

Browse files
committed
Introduce ArgumentsProcessor
1 parent 1635ed0 commit ec12e6f

File tree

4 files changed

+81
-55
lines changed

4 files changed

+81
-55
lines changed

extension.neon

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@ parameters:
44
queryBuilderClass: null
55
allCollectionsSelectable: true
66
objectManagerLoader: null
7-
queryBuilderGetQueryNotOverride: true
87

98
conditionalTags:
109
PHPStan\Reflection\Doctrine\DoctrineSelectableClassReflectionExtension:
1110
phpstan.broker.methodsClassReflectionExtension: %doctrine.allCollectionsSelectable%
12-
PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderGetQueryDynamicReturnTypeExtension:
13-
phpstan.broker.dynamicMethodReturnTypeExtension: %doctrine.queryBuilderGetQueryNotOverride%
1411

1512
services:
1613
-
@@ -56,6 +53,9 @@ services:
5653
class: PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderGetQueryDynamicReturnTypeExtension
5754
arguments:
5855
queryBuilderClass: %doctrine.queryBuilderClass%
56+
argumentsProcessor: @argumentsProcessor
57+
tags:
58+
- phpstan.broker.dynamicMethodReturnTypeExtension
5959
-
6060
class: PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderMethodDynamicReturnTypeExtension
6161
arguments:
@@ -78,6 +78,10 @@ services:
7878
tags:
7979
- phpstan.phpDoc.typeNodeResolverExtension
8080

81+
argumentsProcessor:
82+
class: PHPStan\Type\Doctrine\ArgumentsProcessor
83+
autowired: false
84+
8185
managerRegistryGetRepository:
8286
class: PHPStan\Type\Doctrine\GetRepositoryDynamicReturnTypeExtension
8387
tags:
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Doctrine;
4+
5+
use PHPStan\Analyser\Scope;
6+
use PHPStan\Rules\Doctrine\ORM\DynamicQueryBuilderArgumentException;
7+
use PHPStan\Type\Constant\ConstantArrayType;
8+
use PHPStan\Type\ConstantScalarType;
9+
use PHPStan\Type\Doctrine\QueryBuilder\Expr\ExprType;
10+
11+
class ArgumentsProcessor
12+
{
13+
14+
/**
15+
* @param \PHPStan\Analyser\Scope $scope
16+
* @param string $methodName
17+
* @param \PhpParser\Node\Arg[] $methodCallArgs
18+
* @return mixed[]
19+
*/
20+
public function processArgs(
21+
Scope $scope,
22+
string $methodName,
23+
array $methodCallArgs
24+
): array
25+
{
26+
$args = [];
27+
foreach ($methodCallArgs as $arg) {
28+
$value = $scope->getType($arg->value);
29+
if (
30+
$value instanceof ExprType
31+
&& strpos($value->getClassName(), 'Doctrine\ORM\Query\Expr') === 0
32+
) {
33+
$className = $value->getClassName();
34+
$args[] = new $className(...$this->processArgs($scope, '__construct', $value->getConstructorArgs()));
35+
continue;
36+
}
37+
// todo $qb->expr() support
38+
if ($value instanceof ConstantArrayType) {
39+
$array = [];
40+
foreach ($value->getKeyTypes() as $i => $keyType) {
41+
$valueType = $value->getValueTypes()[$i];
42+
if (!$valueType instanceof ConstantScalarType) {
43+
throw new DynamicQueryBuilderArgumentException();
44+
}
45+
$array[$keyType->getValue()] = $valueType->getValue();
46+
}
47+
48+
$args[] = $array;
49+
continue;
50+
}
51+
if (!$value instanceof ConstantScalarType) {
52+
throw new DynamicQueryBuilderArgumentException();
53+
}
54+
55+
$args[] = $value->getValue();
56+
}
57+
58+
return $args;
59+
}
60+
61+
}

src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php

Lines changed: 11 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
use PHPStan\Reflection\MethodReflection;
99
use PHPStan\Reflection\ParametersAcceptorSelector;
1010
use PHPStan\Rules\Doctrine\ORM\DynamicQueryBuilderArgumentException;
11-
use PHPStan\Type\Constant\ConstantArrayType;
12-
use PHPStan\Type\ConstantScalarType;
11+
use PHPStan\Type\Doctrine\ArgumentsProcessor;
1312
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
1413
use PHPStan\Type\Doctrine\Query\QueryType;
15-
use PHPStan\Type\Doctrine\QueryBuilder\Expr\ExprType;
1614
use PHPStan\Type\Type;
1715
use function in_array;
1816
use function method_exists;
@@ -21,19 +19,24 @@
2119
class QueryBuilderGetQueryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
2220
{
2321

24-
/** @var string|null */
25-
private $queryBuilderClass;
26-
2722
/** @var ObjectMetadataResolver */
2823
private $objectMetadataResolver;
2924

25+
/** @var \PHPStan\Type\Doctrine\ArgumentsProcessor */
26+
private $argumentsProcessor;
27+
28+
/** @var string|null */
29+
private $queryBuilderClass;
30+
3031
public function __construct(
3132
ObjectMetadataResolver $objectMetadataResolver,
33+
ArgumentsProcessor $argumentsProcessor,
3234
?string $queryBuilderClass
3335
)
3436
{
35-
$this->queryBuilderClass = $queryBuilderClass;
3637
$this->objectMetadataResolver = $objectMetadataResolver;
38+
$this->argumentsProcessor = $argumentsProcessor;
39+
$this->queryBuilderClass = $queryBuilderClass;
3740
}
3841

3942
public function getClass(): string
@@ -105,7 +108,7 @@ public function getTypeFromMethodCall(
105108
}
106109

107110
try {
108-
$args = $this->processArgs($scope, $methodName, $calledMethodCall->args);
111+
$args = $this->argumentsProcessor->processArgs($scope, $methodName, $calledMethodCall->args);
109112
} catch (DynamicQueryBuilderArgumentException $e) {
110113
// todo parameter "detectDynamicQueryBuilders" a hlasit jako error - pro oddebugovani
111114
return $defaultReturnType;
@@ -117,47 +120,4 @@ public function getTypeFromMethodCall(
117120
return new QueryType($queryBuilder->getDQL());
118121
}
119122

120-
/**
121-
* @param \PHPStan\Analyser\Scope $scope
122-
* @param string $methodName
123-
* @param \PhpParser\Node\Arg[] $methodCallArgs
124-
* @return mixed[]
125-
*/
126-
protected function processArgs(Scope $scope, string $methodName, array $methodCallArgs): array
127-
{
128-
$args = [];
129-
foreach ($methodCallArgs as $arg) {
130-
$value = $scope->getType($arg->value);
131-
if (
132-
$value instanceof ExprType
133-
&& strpos($value->getClassName(), 'Doctrine\ORM\Query\Expr') === 0
134-
) {
135-
$className = $value->getClassName();
136-
$args[] = new $className(...$this->processArgs($scope, '__construct', $value->getConstructorArgs()));
137-
continue;
138-
}
139-
// todo $qb->expr() support
140-
if ($value instanceof ConstantArrayType) {
141-
$array = [];
142-
foreach ($value->getKeyTypes() as $i => $keyType) {
143-
$valueType = $value->getValueTypes()[$i];
144-
if (!$valueType instanceof ConstantScalarType) {
145-
throw new DynamicQueryBuilderArgumentException();
146-
}
147-
$array[$keyType->getValue()] = $valueType->getValue();
148-
}
149-
150-
$args[] = $array;
151-
continue;
152-
}
153-
if (!$value instanceof ConstantScalarType) {
154-
throw new DynamicQueryBuilderArgumentException();
155-
}
156-
157-
$args[] = $value->getValue();
158-
}
159-
160-
return $args;
161-
}
162-
163123
}

tests/Rules/Doctrine/ORM/QueryBuilderDqlRuleTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Doctrine\ORM\Query\Expr\OrderBy;
77
use PHPStan\Rules\Rule;
88
use PHPStan\Testing\RuleTestCase;
9+
use PHPStan\Type\Doctrine\ArgumentsProcessor;
910
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
1011
use PHPStan\Type\Doctrine\Query\QueryGetDqlDynamicReturnTypeExtension;
1112
use PHPStan\Type\Doctrine\QueryBuilder\CreateQueryBuilderDynamicReturnTypeExtension;
@@ -84,7 +85,7 @@ public function getDynamicMethodReturnTypeExtensions(): array
8485
return [
8586
new CreateQueryBuilderDynamicReturnTypeExtension(null),
8687
new QueryBuilderMethodDynamicReturnTypeExtension(null),
87-
new QueryBuilderGetQueryDynamicReturnTypeExtension(new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', null), null),
88+
new QueryBuilderGetQueryDynamicReturnTypeExtension(new ObjectMetadataResolver(__DIR__ . '/entity-manager.php', null), new ArgumentsProcessor(), null),
8889
new QueryGetDqlDynamicReturnTypeExtension(),
8990
];
9091
}

0 commit comments

Comments
 (0)