Skip to content

Commit 266474c

Browse files
authored
Count entity queries on config entities incorrectly require accesCheck() (#531)
1 parent d24bc3a commit 266474c

File tree

5 files changed

+92
-15
lines changed

5 files changed

+92
-15
lines changed

src/Type/EntityQuery/EntityQueryDynamicReturnTypeExtension.php

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,21 @@ public function getTypeFromMethodCall(
4444
}
4545

4646
if ($methodName === 'count') {
47-
$returnType = new EntityQueryCountType(
47+
if ($varType instanceof EntityQueryType) {
48+
return $varType->asCount();
49+
}
50+
return new EntityQueryCountType(
4851
$varType->getClassName(),
4952
$varType->getSubtractedType(),
5053
$varType->getClassReflection()
5154
);
52-
if ($varType instanceof EntityQueryType && $varType->hasAccessCheck()) {
53-
return $returnType->withAccessCheck();
54-
}
55-
56-
return $returnType;
5755
}
5856

5957
if ($methodName === 'execute') {
60-
if ($varType instanceof EntityQueryCountType) {
58+
if (!$varType instanceof EntityQueryType) {
59+
return $defaultReturnType;
60+
}
61+
if ($varType->isCount()) {
6162
return $varType->hasAccessCheck()
6263
? new IntegerType()
6364
: new EntityQueryExecuteWithoutAccessCheckCountType();
@@ -72,12 +73,9 @@ public function getTypeFromMethodCall(
7273
? new ArrayType(new IntegerType(), new StringType())
7374
: new EntityQueryExecuteWithoutAccessCheckType(new IntegerType(), new StringType());
7475
}
75-
if ($varType instanceof EntityQueryType) {
76-
return $varType->hasAccessCheck()
77-
? new ArrayType(new IntegerType(), new StringType())
78-
: new EntityQueryExecuteWithoutAccessCheckType(new IntegerType(), new StringType());
79-
}
80-
return $defaultReturnType;
76+
return $varType->hasAccessCheck()
77+
? new ArrayType(new IntegerType(), new StringType())
78+
: new EntityQueryExecuteWithoutAccessCheckType(new IntegerType(), new StringType());
8179
}
8280

8381
return $defaultReturnType;

src/Type/EntityQuery/EntityQueryType.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@ class EntityQueryType extends ObjectType
1010
{
1111
private bool $hasAccessCheck = false;
1212

13+
private bool $isCount = false;
14+
1315
public function hasAccessCheck(): bool
1416
{
1517
return $this->hasAccessCheck;
1618
}
1719

20+
public function isCount(): bool
21+
{
22+
return $this->isCount;
23+
}
24+
1825
public function withAccessCheck(): self
1926
{
2027
// The constructor of ObjectType is under backward compatibility promise.
@@ -26,11 +33,29 @@ public function withAccessCheck(): self
2633
$this->getClassReflection()
2734
);
2835
$type->hasAccessCheck = true;
36+
$type->isCount = $this->isCount;
37+
return $type;
38+
}
39+
40+
public function asCount(): self
41+
{
42+
// @phpstan-ignore-next-line
43+
$type = new static(
44+
$this->getClassName(),
45+
$this->getSubtractedType(),
46+
$this->getClassReflection()
47+
);
48+
$type->hasAccessCheck = $this->hasAccessCheck;
49+
$type->isCount = true;
2950
return $type;
3051
}
3152

3253
protected function describeAdditionalCacheKey(): string
3354
{
34-
return $this->hasAccessCheck ? 'with-access-check' : 'without-access-check';
55+
$parts = [
56+
$this->hasAccessCheck ? 'with-access-check' : 'without-access-check',
57+
$this->isCount ? '' : 'count'
58+
];
59+
return implode('-', $parts);
3560
}
3661
}

src/Type/EntityStorage/GetQueryReturnTypeExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function getTypeFromMethodCall(
4242
}
4343

4444
$callerType = $scope->getType($methodCall->var);
45-
if (!$callerType instanceof ObjectType) {
45+
if (!$callerType->isObject()->yes()) {
4646
return $returnType;
4747
}
4848

tests/src/Rules/EntityQueryHasAccessCheckRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,11 @@ public function cases(): \Generator
137137
[__DIR__.'/data/bug-479.php'],
138138
[]
139139
];
140+
141+
yield 'bug-530.php' => [
142+
[__DIR__.'/data/bug-530.php'],
143+
[]
144+
];
145+
140146
}
141147
}

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Bug530;
4+
5+
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
6+
7+
/**
8+
* Tests entity count queries with access check.
9+
*/
10+
class TestClass {
11+
12+
public ConfigEntityStorageInterface $storage;
13+
14+
public function setUp(): void
15+
{
16+
$this->storage = \Drupal::entityTypeManager()->getStorage('menu');
17+
}
18+
19+
public function bug530(string $entity_type): void
20+
{
21+
// Test "normal" entity query with class property.
22+
$this->storage->getQuery()
23+
->condition('field_test', 'foo', '=')
24+
->execute();
25+
26+
// Test "normal" entity query with inline type hint.
27+
/** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
28+
$storage = \Drupal::entityTypeManager()->getStorage('menu');
29+
$count = $storage->getQuery()
30+
->condition('field_test', 'foo', '=')
31+
->execute();
32+
33+
// Test count entity query with class property.
34+
$this->storage->getQuery()
35+
->condition('field_test', 'foo', '=')
36+
->count()
37+
->execute();
38+
39+
// Test count entity query with inline type hint.
40+
/** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
41+
$storage = \Drupal::entityTypeManager()->getStorage('menu');
42+
$count = $storage->getQuery()
43+
->condition('field_test', 'foo', '=')
44+
->count()
45+
->execute();
46+
}
47+
48+
}

0 commit comments

Comments
 (0)