Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(serializer): put replaces embed collection #5604

Merged
merged 1 commit into from
May 30, 2023

Conversation

soyuka
Copy link
Member

@soyuka soyuka commented May 29, 2023

fixes #5587 #5603

@soyuka
Copy link
Member Author

soyuka commented May 30, 2023

failure is unrelated!

@mdieudonne
Copy link

This works for me! Thanks.

@soyuka soyuka merged commit 14969aa into api-platform:3.1 May 30, 2023
18 of 27 checks passed
@soyuka soyuka deleted the fix/serializer-5587 branch May 30, 2023 12:15
@jelovac
Copy link

jelovac commented Jun 6, 2023

Hi, when can we expect a release for this fix?

@jonag
Copy link
Contributor

jonag commented Aug 4, 2023

Hello @soyuka, I have updated API Platform to the last version (v3.1.13) and I think that this PR introduced a BC Break.

In order to get arround this issue I wrote a custom Normalizer to unset the OBJECT_TO_POPULATE and thus allowing me to update a collection operation while PATCHing a resource.

Here is my custom Normalizer:
<?php

namespace App\Normalizer;

use ApiPlatform\Metadata\Patch;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

#[AsDecorator('api_platform.jsonld.normalizer.item')]
final readonly class AllowPatchEmbeddedCollectionRelationNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
    public function __construct(
        #[AutowireDecorated] private NormalizerInterface&DenormalizerInterface $decorated,
    ) {
    }

    public function supportsNormalization($data, $format = null, array $context = []): bool
    {
        return $this->decorated->supportsNormalization($data, $format);
    }

    /**
     * {@inheritdoc}
     */
    public function normalize($object, $format = null, array $context = []): float|array|\ArrayObject|bool|int|string|null
    {
        return $this->decorated->normalize($object, $format, $context);
    }

    /**
     * {@inheritdoc}
     */
    public function denormalize($data, $type, $format = null, array $context = []): mixed
    {
        if (
            ($context['operation'] ?? null) instanceof Patch
            && ($context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? null) instanceof Collection
        ) {
            unset($context[AbstractNormalizer::OBJECT_TO_POPULATE]);
        }

        return $this->decorated->denormalize($data, $type, $format, $context);
    }

    /**
     * {@inheritdoc}
     */
    public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
    {
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }

    /**
     * {@inheritdoc}
     */
    public function setSerializer(SerializerInterface $serializer): void
    {
        if ($this->decorated instanceof SerializerAwareInterface) {
            $this->decorated->setSerializer($serializer);
        }
    }
}

However this line replaces the original operation with a Get operation and therefore breaks my workaround.

Please tell me if I should rather open a new issue to discuss it (I can also upload a repo with my failing test if needed).

@Aerendir
Copy link
Contributor

Aerendir commented Aug 9, 2023

@soyuka , I confirm this change is a BC change: it broke my tests where:

  • PUT Resource with POST SubResource
  • PUT Resource with PUT SubResource
  • PUT Resource with DELETE SubResource

More, it may also be wrong: the problem reported by @mdieudonne seems to relate to the name of placeholders: all his placeholders are named "id": this causes a conflict.

Removing the child context removes the conflict, but also breaks my PR #5546 : the child context (I'm not 100% sure, but the facts seems to confirm this hypotesys) is required to get the subresources.

So, maybe that simply changing the name of the placeholders, avoiding using the same name for different placeholders, would have resolved the problem reported by @mdieudonne .

Anyway, this PR makes impossible to use, for resources IDs, placeholders that have a different name than "id" (that is exactly what I fixed with my PR - and that was something known as there was a todo comment that remembered to fix it).

WDYT?

@soyuka
Copy link
Member Author

soyuka commented Aug 10, 2023

I noted both of your comments they don't seem to have the same concerns... I'll handle these asap, please stay on the previous 3.1.12 for now if you can.

@@ -773,7 +778,6 @@ private function createAndValidateAttributeValue(string $attribute, mixed $value
&& $this->resourceClassResolver->isResourceClass($className)
) {
$resourceClass = $this->resourceClassResolver->getResourceClass(null, $className);
$context['resource_class'] = $resourceClass;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like this should be reverter

@soyuka
Copy link
Member Author

soyuka commented Aug 10, 2023

@jonag can you use root_operation ?

@Aerendir
Copy link
Contributor

I noted both of your comments they don't seem to have the same concerns... I'll handle these asap, please stay on the previous 3.1.12 for now if you can.

Yes, they are two different problems...

@jonag
Copy link
Contributor

jonag commented Aug 10, 2023

@jonag can you use root_operation ?

I should find this key in the context passed to the normalizer? Because this key is currently not set when I dump the context on my custom normalizer.

@soyuka
Copy link
Member Author

soyuka commented Aug 10, 2023

$context['root_operation'] = $context['operation'];
it should be there when using Hydra, I may add this to the SerializerContextBuilder but I'd like for you to try it first if it's possible?

@nxtpge
Copy link

nxtpge commented Nov 13, 2023

Hello @jonag and @soyuka, is the fix still ongoing?

@jonag
Copy link
Contributor

jonag commented Nov 13, 2023

Hello @nxtpge, if you are talking about the property root_operation, I forgot to answer to @soyuka but it's indeed already available in the context passed to the normalizer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants