Skip to content

Commit fdc9f57

Browse files
authored
Merge pull request #497 from Boegie/496
2 parents 10819c6 + a2f6de8 commit fdc9f57

File tree

4 files changed

+83
-6
lines changed

4 files changed

+83
-6
lines changed

extension.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,7 @@ services:
297297
-
298298
class: mglaman\PHPStanDrupal\Drupal\DrupalStubFilesExtension
299299
tags: [phpstan.stubFilesExtension]
300+
-
301+
class: mglaman\PHPStanDrupal\Type\EntityQuery\AccessCheckTypeSpecifyingExtension
302+
tags:
303+
- phpstan.typeSpecifier.methodTypeSpecifyingExtension
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Type\EntityQuery;
4+
5+
use Drupal\Core\Entity\Query\QueryInterface;
6+
use PhpParser\Node\Expr\MethodCall;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Analyser\SpecifiedTypes;
9+
use PHPStan\Analyser\TypeSpecifier;
10+
use PHPStan\Analyser\TypeSpecifierAwareExtension;
11+
use PHPStan\Analyser\TypeSpecifierContext;
12+
use PHPStan\Reflection\MethodReflection;
13+
use PHPStan\Reflection\ParametersAcceptorSelector;
14+
use PHPStan\Type\MethodTypeSpecifyingExtension;
15+
16+
final class AccessCheckTypeSpecifyingExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
17+
{
18+
private TypeSpecifier $typeSpecifier;
19+
public function setTypeSpecifier(TypeSpecifier $typeSpecifier) : void
20+
{
21+
$this->typeSpecifier = $typeSpecifier;
22+
}
23+
24+
public function getClass(): string
25+
{
26+
return QueryInterface::class;
27+
}
28+
29+
public function isMethodSupported(
30+
MethodReflection $methodReflection,
31+
MethodCall $node,
32+
TypeSpecifierContext $context
33+
): bool {
34+
return $methodReflection->getName() === 'accessCheck';
35+
}
36+
37+
public function specifyTypes(
38+
MethodReflection $methodReflection,
39+
MethodCall $node,
40+
Scope $scope,
41+
TypeSpecifierContext $context
42+
): SpecifiedTypes {
43+
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
44+
$expr = $node->var;
45+
if (!$returnType instanceof EntityQueryType) {
46+
return $this->typeSpecifier->create($expr, $returnType, TypeSpecifierContext::createTruthy());
47+
}
48+
return $this->typeSpecifier->create($expr, $returnType->withAccessCheck(), TypeSpecifierContext::createTruthy());
49+
}
50+
}

tests/src/Rules/EntityQueryHasAccessCheckRuleTest.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,14 @@ public function cases(): \Generator
6060
]
6161
];
6262

63-
// @todo 396a2 this passes when run individually, somehow.
64-
/*
6563
yield 'bug-396a2.php' => [
6664
[__DIR__ . '/data/bug-396a2.php'],
6765
[]
68-
];*/
69-
// @todo not chained call, return type extension has no influence.
70-
/*
66+
];
7167
yield 'bug-396a3.php' => [
7268
[__DIR__ . '/data/bug-396a3.php'],
7369
[]
74-
];*/
70+
];
7571
yield 'bug-396b.php' => [
7672
[__DIR__ . '/data/bug-396b.php'],
7773
[]
@@ -131,5 +127,10 @@ public function cases(): \Generator
131127
],
132128
]
133129
];
130+
131+
yield 'bug-496.php' => [
132+
[__DIR__.'/data/bug-496.php'],
133+
[]
134+
];
134135
}
135136
}

tests/src/Rules/data/bug-496.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Bug496Example;
4+
5+
class TestClass {
6+
7+
/**
8+
* Tests non-chained entity queries with access check.
9+
*/
10+
public function bug496(string $entity_type): void
11+
{
12+
$query = \Drupal::entityQuery('node');
13+
$query->accessCheck(FALSE);
14+
$query->condition('field_test', 'foo', '=');
15+
$query->execute();
16+
17+
$query = \Drupal::entityQuery('node');
18+
$query->condition('field_test', 'foo', '=');
19+
$query->accessCheck(FALSE);
20+
$query->execute();
21+
}
22+
}

0 commit comments

Comments
 (0)