Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd0b05a

Browse files
authored
fix(serializer): dynamic groups should not be cached (#5207)
fixes #5202
1 parent 7d1a4fe commit bd0b05a

5 files changed

Lines changed: 74 additions & 7 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@!mongodb
2+
Feature: Dynamic serialization context
3+
In order to customize the Resource representation dynamically
4+
As a developer
5+
I should be able to add and remove groups
6+
7+
@createSchema
8+
Scenario:
9+
When I add "Content-Type" header equal to "application/ld+json"
10+
And I send a "GET" request to "/relation_group_impact_on_collections/1"
11+
And the JSON node "related.title" should be equal to "foo"

src/Serializer/AbstractItemNormalizer.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -507,18 +507,17 @@ protected function denormalizeRelation(string $attributeName, ApiProperty $prope
507507
*/
508508
protected function getFactoryOptions(array $context): array
509509
{
510-
$operationCacheKey = ($context['resource_class'] ?? '').($context['operation_name'] ?? '').($context['api_normalize'] ?? '');
511-
if ($operationCacheKey && isset($this->localFactoryOptionsCache[$operationCacheKey])) {
512-
return $this->localFactoryOptionsCache[$operationCacheKey];
513-
}
514-
515510
$options = [];
516-
517511
if (isset($context[self::GROUPS])) {
518512
/* @see https://github.com/symfony/symfony/blob/v4.2.6/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php */
519513
$options['serializer_groups'] = (array) $context[self::GROUPS];
520514
}
521515

516+
$operationCacheKey = ($context['resource_class'] ?? '').($context['operation_name'] ?? '').($context['api_normalize'] ?? '');
517+
if ($operationCacheKey && isset($this->localFactoryOptionsCache[$operationCacheKey])) {
518+
return $options + $this->localFactoryOptionsCache[$operationCacheKey];
519+
}
520+
522521
// This is a hot spot
523522
if (isset($context['resource_class'])) {
524523
// Note that the groups need to be read on the root operation
@@ -536,7 +535,7 @@ protected function getFactoryOptions(array $context): array
536535
}
537536
}
538537

539-
return $this->localFactoryOptionsCache[$operationCacheKey] = $options;
538+
return $options + $this->localFactoryOptionsCache[$operationCacheKey] = $options;
540539
}
541540

542541
/**

tests/Fixtures/TestBundle/Entity/RelationGroupImpactOnCollection.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
operations: [
2626
new GetCollection(),
2727
new Get(normalizationContext: ['groups' => 'related']),
28+
// This adds a "related" group in the "AddGroupNormalizer"
29+
new Get(uriTemplate: '/custom_normalizer_relation_group_impact_on_collection'),
2830
]
2931
)]
3032
class RelationGroupImpactOnCollection
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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\Serializer\Normalizer;
15+
16+
use ApiPlatform\Metadata\Get;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelationGroupImpactOnCollection;
18+
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
19+
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
20+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
21+
22+
final class AddGroupNormalizer implements NormalizerAwareInterface, NormalizerInterface
23+
{
24+
use NormalizerAwareTrait;
25+
26+
private const ALREADY_CALLED = 'RELATED_GROUP_IMPACT_ON_COLLECTION_NORMALIZER_ALREADY_CALLED';
27+
28+
public function normalize($object, $format = null, array $context = []): array|string|int|float|bool|\ArrayObject
29+
{
30+
$context[self::ALREADY_CALLED] = true;
31+
if (!($operation = $context['operation'] ?? null)) {
32+
return $this->normalizer->normalize($object, $format, $context);
33+
}
34+
35+
if ($operation instanceof Get && '/custom_normalizer_relation_group_impact_on_collection' === $operation->getUriTemplate()) {
36+
$context['groups'] = ['related'];
37+
}
38+
39+
return $this->normalizer->normalize($object, $format, $context);
40+
}
41+
42+
public function supportsNormalization($data, $format = null, array $context = []): bool
43+
{
44+
// Make sure we're not called twice
45+
if (isset($context[self::ALREADY_CALLED])) {
46+
return false;
47+
}
48+
49+
return $data instanceof RelationGroupImpactOnCollection;
50+
}
51+
}

tests/Fixtures/app/config/config_common.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,7 @@ services:
415415
tags:
416416
- { name: 'api_platform.state_processor' }
417417

418+
ApiPlatform\Tests\Fixtures\TestBundle\Serializer\Normalizer\AddGroupNormalizer:
419+
tags:
420+
- { name: 'serializer.normalizer' }
421+

0 commit comments

Comments
 (0)