Skip to content

Commit

Permalink
fix(metadata): Operations priority sort (#6206)
Browse files Browse the repository at this point in the history
* fix(metadata): fix Operations sort

* test: priority test

---------

Co-authored-by: soyuka <soyuka@users.noreply.github.com>
  • Loading branch information
vincentchalamon and soyuka committed Mar 7, 2024
1 parent 055fb38 commit 98f4b8f
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/Metadata/ApiResource.php
Expand Up @@ -1018,6 +1018,7 @@ public function withOperations(Operations $operations): self
{
$self = clone $this;
$self->operations = $operations;
$self->operations->sort();

return $self;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Metadata/Operation.php
Expand Up @@ -794,6 +794,12 @@ public function __construct(
protected ?bool $serialize = null,
protected ?bool $fetchPartial = null,
protected ?bool $forceEager = null,
/**
* The priority helps with the order of operations when looping over a resource's operations.
* It can be usefull when we loop over operations to find a matching IRI, although most of the use cases
* should be covered by the HttpOperation::itemUriTemplate or the ApiProperty::uriTemplate functionalities.
* Sort is ascendant: a lower priority comes first in the list.
*/
protected ?int $priority = null,
protected ?string $name = null,
protected $provider = null,
Expand Down
Expand Up @@ -119,9 +119,11 @@ private function buildResourceOperations(array $attributes, string $resourceClas
}

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

// Loop again and set default operations if none where found
Expand Down
Expand Up @@ -52,7 +52,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
}
}

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

Expand Down
Expand Up @@ -56,7 +56,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
$operations->remove($operationName)->add($newOperationName, $operation->withName($newOperationName));
}

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

return $resourceMetadataCollection;
Expand Down
Expand Up @@ -88,7 +88,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
$operations->add($operation->getName(), $operation);
}

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

Expand Down
36 changes: 36 additions & 0 deletions src/Metadata/Tests/OperationsTest.php
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Metadata\Tests;

use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Operations;
use PHPUnit\Framework\TestCase;

final class OperationsTest extends TestCase
{
public function testOperationsHaveNameIfNotSet(): void
{
$operations = new Operations([new Get(name: 'a'), new Get(name: 'b')]);

foreach ($operations as $name => $operation) {
$this->assertEquals($name, $operation->getName());
}
}

public function testOperationAreSorted(): void
{
$operations = new Operations(['a' => new Get(priority: 0), 'b' => new Get(priority: -1)]);
$this->assertEquals(['b', 'a'], array_keys(iterator_to_array($operations)));
}
}
33 changes: 33 additions & 0 deletions tests/Fixtures/TestBundle/ApiResource/OperationPriorities.php
@@ -0,0 +1,33 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource;

use ApiPlatform\Metadata\Get;

#[Get(name: 'a', priority: 1, uriTemplate: 'operation_priority/{id}', provider: [self::class, 'shouldNotBeCalled'])]
#[Get(name: 'b', priority: -1, uriTemplate: 'operation_priority/{id}', provider: [self::class, 'shouldBeCalled'])]
class OperationPriorities
{
public int $id = 1;

public static function shouldBeCalled(): self
{
return new self();
}

public static function shouldNotBeCalled(): self
{
throw new \Exception('fail');
}
}
10 changes: 10 additions & 0 deletions tests/Symfony/Bundle/Test/ApiTestCaseTest.php
Expand Up @@ -267,6 +267,16 @@ public function testFindIriBy(): void
$this->assertNull(self::findIriBy($resource, ['name' => 'not-exist']));
}

public function testGetPrioritizedOperation(): void
{
$r = self::createClient()->request('GET', '/operation_priority/1', [
'headers' => [
'accept' => 'application/ld+json',
],
]);
$this->assertResponseIsSuccessful();
}

/**
* @group mercure
*/
Expand Down

0 comments on commit 98f4b8f

Please sign in to comment.