Skip to content

Commit 84a7e56

Browse files
authored
fix(metadata): getOperation cache matches arguments (#5215)
fixes #5204
1 parent 0f89161 commit 84a7e56

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

src/Metadata/Operations.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct(array $operations = [])
2424
{
2525
foreach ($operations as $operationName => $operation) {
2626
// When we use an int-indexed array in the constructor, compute priorities
27-
if (\is_int($operationName)) {
27+
if (\is_int($operationName) && null === $operation->getPriority()) {
2828
$operation = $operation->withPriority($operationName);
2929
$operationName = (string) $operationName;
3030
}

src/Metadata/Resource/ResourceMetadataCollection.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ final class ResourceMetadataCollection extends \ArrayObject
2626
{
2727
private const GRAPHQL_PREFIX = 'g_';
2828
private const HTTP_PREFIX = 'h_';
29+
private const FORCE_COLLECTION = 'co_';
30+
private const HTTP_OPERATION = 'ht_';
31+
2932
private array $operationCache = [];
3033

3134
public function __construct(private readonly string $resourceClass, array $input = [])
@@ -36,12 +39,15 @@ public function __construct(private readonly string $resourceClass, array $input
3639
public function getOperation(?string $operationName = null, bool $forceCollection = false, bool $httpOperation = false): Operation
3740
{
3841
$operationName ??= '';
39-
if (isset($this->operationCache[self::HTTP_PREFIX.$operationName])) {
40-
return $this->operationCache[self::HTTP_PREFIX.$operationName];
42+
$cachePrefix = ($forceCollection ? self::FORCE_COLLECTION : '').($httpOperation ? self::HTTP_OPERATION : '');
43+
$httpCacheKey = self::HTTP_PREFIX.$cachePrefix.$operationName;
44+
if (isset($this->operationCache[$httpCacheKey])) {
45+
return $this->operationCache[$httpCacheKey];
4146
}
4247

43-
if (isset($this->operationCache[self::GRAPHQL_PREFIX.$operationName])) {
44-
return $this->operationCache[self::GRAPHQL_PREFIX.$operationName];
48+
$gqlCacheKey = self::GRAPHQL_PREFIX.$cachePrefix.$operationName;
49+
if (isset($this->operationCache[$gqlCacheKey])) {
50+
return $this->operationCache[$gqlCacheKey];
4551
}
4652

4753
$it = $this->getIterator();
@@ -56,26 +62,26 @@ public function getOperation(?string $operationName = null, bool $forceCollectio
5662
$method = $operation->getMethod() ?? HttpOperation::METHOD_GET;
5763
$isGetOperation = HttpOperation::METHOD_GET === $method || HttpOperation::METHOD_OPTIONS === $method || HttpOperation::METHOD_HEAD === $method;
5864
if ('' === $operationName && $isGetOperation && ($forceCollection ? $isCollection : !$isCollection)) {
59-
return $this->operationCache[self::HTTP_PREFIX.$operationName] = $operation;
65+
return $this->operationCache[$httpCacheKey] = $operation;
6066
}
6167

6268
if ($name === $operationName) {
63-
return $this->operationCache[self::HTTP_PREFIX.$operationName] = $operation;
69+
return $this->operationCache[$httpCacheKey] = $operation;
6470
}
6571

6672
if ($operation->getUriTemplate() === $operationName) {
67-
return $this->operationCache[self::HTTP_PREFIX.$operationName] = $operation;
73+
return $this->operationCache[$httpCacheKey] = $operation;
6874
}
6975
}
7076

7177
foreach ($metadata->getGraphQlOperations() ?? [] as $name => $operation) {
7278
$isCollection = $operation instanceof CollectionOperationInterface;
7379
if ('' === $operationName && ($forceCollection ? $isCollection : !$isCollection) && false === $httpOperation) {
74-
return $this->operationCache[self::GRAPHQL_PREFIX.$operationName] = $operation;
80+
return $this->operationCache[$gqlCacheKey] = $operation;
7581
}
7682

7783
if ($name === $operationName) {
78-
return $this->operationCache[self::GRAPHQL_PREFIX.$operationName] = $operation;
84+
return $this->operationCache[$httpCacheKey] = $operation;
7985
}
8086
}
8187

tests/Metadata/Resource/ResourceMetadataCollectionTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
use ApiPlatform\Exception\OperationNotFoundException;
1717
use ApiPlatform\Metadata\ApiResource;
1818
use ApiPlatform\Metadata\Get;
19+
use ApiPlatform\Metadata\GetCollection;
1920
use ApiPlatform\Metadata\GraphQl\Query;
21+
use ApiPlatform\Metadata\GraphQl\QueryCollection;
2022
use ApiPlatform\Metadata\Operations;
2123
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
2224
use PHPUnit\Framework\TestCase;
@@ -46,4 +48,46 @@ public function testOperationNotFound(): void
4648

4749
$this->assertSame($operation, $resourceMetadataCollection->getOperation('noname'));
4850
}
51+
52+
public function testCache(): void
53+
{
54+
$defaultOperation = new Get(name: 'get');
55+
$defaultGqlOperation = new Query();
56+
$defaultCollectionOperation = new GetCollection(name: 'get_collection');
57+
$defaultGqlCollectionOperation = new QueryCollection();
58+
$resource = new ApiResource(
59+
operations: [
60+
'get' => $defaultOperation,
61+
'get_collection' => $defaultCollectionOperation,
62+
],
63+
graphQlOperations: [
64+
'query' => $defaultGqlOperation,
65+
'query_collection' => $defaultGqlCollectionOperation,
66+
]
67+
);
68+
69+
$resourceMetadataCollection = new ResourceMetadataCollection('class', [$resource]);
70+
71+
$this->assertEquals($resourceMetadataCollection->getOperation(), $defaultOperation);
72+
$this->assertEquals($resourceMetadataCollection->getOperation(null, true), $defaultCollectionOperation);
73+
$this->assertEquals($resourceMetadataCollection->getOperation(null, false, true), $defaultOperation);
74+
75+
$resource = new ApiResource(
76+
graphQlOperations: [
77+
'query' => $defaultGqlOperation,
78+
'query_collection' => $defaultGqlCollectionOperation,
79+
]
80+
);
81+
82+
$resourceMetadataCollection = new ResourceMetadataCollection('class', [$resource]);
83+
84+
$this->assertEquals($resourceMetadataCollection->getOperation(), $defaultGqlOperation);
85+
$this->assertEquals($resourceMetadataCollection->getOperation(null, true), $defaultGqlCollectionOperation);
86+
87+
try {
88+
$resourceMetadataCollection->getOperation(null, false, true);
89+
} catch (\Exception $e) {
90+
$this->assertInstanceOf(OperationNotFoundException::class, $e);
91+
}
92+
}
4993
}

0 commit comments

Comments
 (0)