Skip to content

Commit ebaad51

Browse files
authored
fix(serializer): read groups off the root operation (#5196)
* fix(serializer): read groups off the root operation
1 parent abed742 commit ebaad51

File tree

6 files changed

+120
-1
lines changed

6 files changed

+120
-1
lines changed
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@php8
2+
@!mongodb
3+
Feature: Groups to embed relations
4+
In order to show embed relations on a Resource
5+
As a client software developer
6+
I need to set up groups on the Resource embed properties
7+
8+
Scenario: Get a single resource
9+
When I send a "GET" request to "/relation_group_impact_on_collections/1"
10+
Then the response status code should be 200
11+
And the response should be in JSON
12+
And the JSON node "related.title" should be equal to "foo"
13+
14+
Scenario: Get a collection resource not impacted by groups
15+
When I send a "GET" request to "/relation_group_impact_on_collections"
16+
Then the response status code should be 200
17+
And the response should be in JSON
18+
And the JSON node "hydra:member[0].related" should be equal to "/relation_group_impact_on_collection_relations/1"

src/Hydra/Serializer/CollectionNormalizer.php

+10
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,21 @@ public function normalize($object, $format = null, array $context = []): array
101101
$data['hydra:member'] = [];
102102
$iriOnly = $context[self::IRI_ONLY] ?? $this->defaultContext[self::IRI_ONLY];
103103

104+
// We need to keep this operation for serialization groups for later
105+
if (isset($context['operation'])) {
106+
$context['root_operation'] = $context['operation'];
107+
}
108+
109+
if (isset($context['operation_name'])) {
110+
$context['root_operation_name'] = $context['operation_name'];
111+
}
112+
104113
if ($this->resourceMetadataCollectionFactory && ($operation = $context['operation'] ?? null) instanceof CollectionOperationInterface && ($itemUriTemplate = $operation->getItemUriTemplate())) {
105114
$context['operation'] = $this->resourceMetadataCollectionFactory->create($resourceClass)->getOperation($operation->getItemUriTemplate());
106115
} else {
107116
unset($context['operation']);
108117
}
118+
109119
unset($context['operation_name'], $context['uri_variables']);
110120

111121
foreach ($object as $obj) {

src/Serializer/AbstractCollectionNormalizer.php

+10
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,23 @@ public function normalize($object, $format = null, array $context = [])
9292
$data = [];
9393
$paginationData = $this->getPaginationData($object, $context);
9494

95+
// We need to keep this operation for serialization groups for later
96+
if (isset($context['operation'])) {
97+
$context['root_operation'] = $context['operation'];
98+
}
99+
100+
if (isset($context['operation_name'])) {
101+
$context['root_operation_name'] = $context['operation_name'];
102+
}
103+
95104
/** @var ResourceMetadata|ResourceMetadataCollection */
96105
$metadata = $this->resourceMetadataFactory->create($context['resource_class'] ?? '');
97106
if ($metadata instanceof ResourceMetadataCollection && ($operation = $context['operation'] ?? null) instanceof CollectionOperationInterface && ($itemUriTemplate = $operation->getItemUriTemplate())) {
98107
$context['operation'] = $metadata->getOperation($itemUriTemplate);
99108
} else {
100109
unset($context['operation']);
101110
}
111+
102112
unset($context['operation_type'], $context['operation_name']);
103113
$itemsData = $this->getItemsData($object, $format, $context);
104114

src/Serializer/AbstractItemNormalizer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ protected function getFactoryOptions(array $context): array
712712
if (isset($context['resource_class']) && $this->resourceClassResolver->isResourceClass($context['resource_class']) && $this->resourceMetadataFactory instanceof ResourceMetadataCollectionFactoryInterface) {
713713
$resourceClass = $this->resourceClassResolver->getResourceClass(null, $context['resource_class']); // fix for abstract classes and interfaces
714714
// This is a hot spot, we should avoid calling this here but in many cases we can't
715-
$operation = $context['operation'] ?? $this->resourceMetadataFactory->create($resourceClass)->getOperation($context['operation_name'] ?? null);
715+
$operation = $context['root_operation'] ?? $context['operation'] ?? $this->resourceMetadataFactory->create($resourceClass)->getOperation($context['root_operation_name'] ?? $context['operation_name'] ?? null);
716716
$options['normalization_groups'] = $operation->getNormalizationContext()['groups'] ?? null;
717717
$options['denormalization_groups'] = $operation->getDenormalizationContext()['groups'] ?? null;
718718
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Entity;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\CollectionOperationInterface;
18+
use ApiPlatform\Metadata\Get;
19+
use ApiPlatform\Metadata\GetCollection;
20+
use ApiPlatform\Metadata\Operation;
21+
use Symfony\Component\Serializer\Annotation\Groups;
22+
23+
#[ApiResource(
24+
provider: [RelationGroupImpactOnCollection::class, 'getData']
25+
)]
26+
#[GetCollection]
27+
#[Get(normalizationContext: ['groups' => 'related'])]
28+
class RelationGroupImpactOnCollection
29+
{
30+
public ?int $id;
31+
#[Groups('related')]
32+
public ?RelationGroupImpactOnCollectionRelation $related;
33+
34+
public function __construct($id = null, $related = null)
35+
{
36+
$this->id = $id;
37+
$this->related = $related;
38+
}
39+
40+
public static function getData(Operation $operation, array $uriVariables = [], array $context = []): self|array
41+
{
42+
$item = new self($uriVariables['id'] ?? 1, new RelationGroupImpactOnCollectionRelation(id: $uriVariables['id'] ?? 1, title: 'foo'));
43+
if ($operation instanceof CollectionOperationInterface) {
44+
return [$item];
45+
}
46+
47+
return $item;
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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\Entity;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use Symfony\Component\Serializer\Annotation\Groups;
18+
19+
#[ApiResource]
20+
class RelationGroupImpactOnCollectionRelation
21+
{
22+
public ?int $id;
23+
24+
#[Groups('related')]
25+
public ?string $title;
26+
27+
public function __construct($id, $title)
28+
{
29+
$this->id = $id;
30+
$this->title = $title;
31+
}
32+
}

0 commit comments

Comments
 (0)