Skip to content

Commit

Permalink
fix(serializer): read groups off the root operation
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Nov 17, 2022
1 parent cd3fb78 commit f609ced
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 1 deletion.
16 changes: 16 additions & 0 deletions features/serializer/groups_related.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Feature: Groups to embed relations
In order to show embed relations on a Resource
As a client software developer
I need to set up groups on the Resource embed properties

Scenario: Get a single resource
When I send a "GET" request to "/relation_group_impact_on_collections/1"
Then the response status code should be 200
And the response should be in JSON
And the JSON node "related.title" should be equal to "foo"

Scenario: Get a collection resource not impacted by groups
When I send a "GET" request to "/relation_group_impact_on_collections"
Then the response status code should be 200
And the response should be in JSON
And the JSON node "hydra:member[0].related" should be equal to "/relation_group_impact_on_collection_relations/1"
12 changes: 12 additions & 0 deletions src/Hydra/Serializer/CollectionNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ public function normalize($object, $format = null, array $context = []): array
} else {
unset($context['operation']);
}

// We need to keep this operation for serialization groups for later
if (isset($context['operation'])) {
$context['root_operation'] = $context['operation'];
}

if (isset($context['operation_name'])) {
$context['root_operation_name'] = $context['operation_name'];
}

// We need to unset the operation to ensure a proper IRI generation inside items
unset($context['operation']);
unset($context['operation_name'], $context['uri_variables']);

foreach ($object as $obj) {
Expand Down
11 changes: 11 additions & 0 deletions src/Serializer/AbstractCollectionNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ public function normalize($object, $format = null, array $context = [])
} else {
unset($context['operation']);
}

// We need to keep this operation for serialization groups for later
if (isset($context['operation'])) {
$context['root_operation'] = $context['operation'];
}

if (isset($context['operation_name'])) {
$context['root_operation_name'] = $context['operation_name'];
}

unset($context['operation']);
unset($context['operation_type'], $context['operation_name']);
$itemsData = $this->getItemsData($object, $format, $context);

Expand Down
2 changes: 1 addition & 1 deletion src/Serializer/AbstractItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ protected function getFactoryOptions(array $context): array
if (isset($context['resource_class']) && $this->resourceClassResolver->isResourceClass($context['resource_class']) && $this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
$resourceClass = $this->resourceClassResolver->getResourceClass(null, $context['resource_class']); // fix for abstract classes and interfaces
// This is a hot spot, we should avoid calling this here but in many cases we can't
$operation = $context['operation'] ?? $this->resourceMetadataFactory->create($resourceClass)->getOperation($context['operation_name'] ?? null);
$operation = $context['root_operation'] ?? $context['operation'] ?? $this->resourceMetadataFactory->create($resourceClass)->getOperation($context['root_operation_name'] ?? $context['operation_name'] ?? null);
$options['normalization_groups'] = $operation->getNormalizationContext()['groups'] ?? null;
$options['denormalization_groups'] = $operation->getDenormalizationContext()['groups'] ?? null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\CollectionOperationInterface;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use Symfony\Component\Serializer\Annotation\Groups;

#[ApiResource(
provider: [RelationGroupImpactOnCollection::class, 'getData'],
operations: [
new GetCollection(),
new Get(normalizationContext: ['groups' => 'related']),
]
)]
class RelationGroupImpactOnCollection
{
public function __construct(
public ?int $id = null,
#[Groups('related')]
public ?RelationGroupImpactOnCollectionRelation $related = null)
{
}

public static function getData(Operation $operation, array $uriVariables = [], array $context = []): self|array
{
$item = new self($uriVariables['id'] ?? 1, new RelationGroupImpactOnCollectionRelation(id: $uriVariables['id'] ?? 1, title: 'foo'));
if ($operation instanceof CollectionOperationInterface) {
return [$item];
}

return $item;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?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\Entity;

use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;

#[ApiResource]
class RelationGroupImpactOnCollectionRelation
{
public function __construct(
public ?int $id = null,
#[Groups('related')]
public ?string $title = null
) {
}
}
1 change: 1 addition & 0 deletions tests/Hal/Serializer/CollectionNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ private function normalizePaginator($partial = false)
$itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'bar',
])->willReturn(['_links' => ['self' => '/me'], 'name' => 'Kévin']);

$normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page', $resourceMetadataFactoryProphecy->reveal());
Expand Down
5 changes: 5 additions & 0 deletions tests/JsonApi/Serializer/CollectionNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public function testNormalizePaginator()
'uri' => 'http://example.com/foos?page=3',
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'get',
])->willReturn([
'data' => [
'type' => 'Foo',
Expand Down Expand Up @@ -144,6 +145,7 @@ public function testNormalizePartialPaginator()
'uri' => 'http://example.com/foos?page=3',
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'get',
])->willReturn([
'data' => [
'type' => 'Foo',
Expand Down Expand Up @@ -201,6 +203,7 @@ public function testNormalizeArray()
'uri' => 'http://example.com/foos',
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'get',
])->willReturn([
'data' => [
'type' => 'Foo',
Expand Down Expand Up @@ -253,6 +256,7 @@ public function testNormalizeIncludedData()
'uri' => 'http://example.com/foos',
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'get',
])->willReturn([
'data' => [
'type' => 'Foo',
Expand Down Expand Up @@ -328,6 +332,7 @@ public function testNormalizeWithoutDataKey()
'uri' => 'http://example.com/foos',
'api_sub_level' => true,
'resource_class' => 'Foo',
'root_operation_name' => 'get',
])->willReturn([]);

$normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page', $resourceMetadataFactoryProphecy->reveal());
Expand Down

0 comments on commit f609ced

Please sign in to comment.