Skip to content

Commit 98f4b8f

Browse files
fix(metadata): Operations priority sort (#6206)
* fix(metadata): fix Operations sort * test: priority test --------- Co-authored-by: soyuka <[email protected]>
1 parent 055fb38 commit 98f4b8f

9 files changed

+93
-5
lines changed

src/Metadata/ApiResource.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,7 @@ public function withOperations(Operations $operations): self
10181018
{
10191019
$self = clone $this;
10201020
$self->operations = $operations;
1021+
$self->operations->sort();
10211022

10221023
return $self;
10231024
}

src/Metadata/Operation.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,12 @@ public function __construct(
794794
protected ?bool $serialize = null,
795795
protected ?bool $fetchPartial = null,
796796
protected ?bool $forceEager = null,
797+
/**
798+
* The priority helps with the order of operations when looping over a resource's operations.
799+
* It can be usefull when we loop over operations to find a matching IRI, although most of the use cases
800+
* should be covered by the HttpOperation::itemUriTemplate or the ApiProperty::uriTemplate functionalities.
801+
* Sort is ascendant: a lower priority comes first in the list.
802+
*/
797803
protected ?int $priority = null,
798804
protected ?string $name = null,
799805
protected $provider = null,

src/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,11 @@ private function buildResourceOperations(array $attributes, string $resourceClas
119119
}
120120

121121
[$key, $operation] = $this->getOperationWithDefaults($resources[$index], $operationAttribute);
122-
$operation = $operation->withPriority(++$operationPriority);
122+
if (null === $operation->getPriority()) {
123+
$operation = $operation->withPriority(++$operationPriority);
124+
}
123125
$operations = $resources[$index]->getOperations() ?? new Operations();
124-
$resources[$index] = $resources[$index]->withOperations($operations->add($key, $operation)->sort());
126+
$resources[$index] = $resources[$index]->withOperations($operations->add($key, $operation));
125127
}
126128

127129
// Loop again and set default operations if none where found

src/Metadata/Resource/Factory/MainControllerResourceMetadataCollectionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
5252
}
5353
}
5454

55-
$resource = $resource->withOperations($operations->sort());
55+
$resource = $resource->withOperations($operations);
5656
$resourceMetadataCollection[$i] = $resource;
5757
}
5858

src/Metadata/Resource/Factory/OperationNameResourceMetadataCollectionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
5656
$operations->remove($operationName)->add($newOperationName, $operation->withName($newOperationName));
5757
}
5858

59-
$resourceMetadataCollection[$i] = $resource->withOperations($operations->sort());
59+
$resourceMetadataCollection[$i] = $resource->withOperations($operations);
6060
}
6161

6262
return $resourceMetadataCollection;

src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
8888
$operations->add($operation->getName(), $operation);
8989
}
9090

91-
$resource = $resource->withOperations($operations->sort());
91+
$resource = $resource->withOperations($operations);
9292
$resourceMetadataCollection[$i] = $resource;
9393
}
9494

src/Metadata/Tests/OperationsTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Metadata\Tests;
15+
16+
use ApiPlatform\Metadata\Get;
17+
use ApiPlatform\Metadata\Operations;
18+
use PHPUnit\Framework\TestCase;
19+
20+
final class OperationsTest extends TestCase
21+
{
22+
public function testOperationsHaveNameIfNotSet(): void
23+
{
24+
$operations = new Operations([new Get(name: 'a'), new Get(name: 'b')]);
25+
26+
foreach ($operations as $name => $operation) {
27+
$this->assertEquals($name, $operation->getName());
28+
}
29+
}
30+
31+
public function testOperationAreSorted(): void
32+
{
33+
$operations = new Operations(['a' => new Get(priority: 0), 'b' => new Get(priority: -1)]);
34+
$this->assertEquals(['b', 'a'], array_keys(iterator_to_array($operations)));
35+
}
36+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource;
15+
16+
use ApiPlatform\Metadata\Get;
17+
18+
#[Get(name: 'a', priority: 1, uriTemplate: 'operation_priority/{id}', provider: [self::class, 'shouldNotBeCalled'])]
19+
#[Get(name: 'b', priority: -1, uriTemplate: 'operation_priority/{id}', provider: [self::class, 'shouldBeCalled'])]
20+
class OperationPriorities
21+
{
22+
public int $id = 1;
23+
24+
public static function shouldBeCalled(): self
25+
{
26+
return new self();
27+
}
28+
29+
public static function shouldNotBeCalled(): self
30+
{
31+
throw new \Exception('fail');
32+
}
33+
}

tests/Symfony/Bundle/Test/ApiTestCaseTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,16 @@ public function testFindIriBy(): void
267267
$this->assertNull(self::findIriBy($resource, ['name' => 'not-exist']));
268268
}
269269

270+
public function testGetPrioritizedOperation(): void
271+
{
272+
$r = self::createClient()->request('GET', '/operation_priority/1', [
273+
'headers' => [
274+
'accept' => 'application/ld+json',
275+
],
276+
]);
277+
$this->assertResponseIsSuccessful();
278+
}
279+
270280
/**
271281
* @group mercure
272282
*/

0 commit comments

Comments
 (0)