Skip to content

Change with DISABLE_TYPE_ENFORCEMENT made it impossible to use IRI as a value for an object #5773

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

Closed
bizley opened this issue Aug 25, 2023 · 6 comments

Comments

@bizley
Copy link

bizley commented Aug 25, 2023

API Platform version(s) affected: 3.1.15
It was working on 3.0

Description
When sending IRI as a reference to an object with disable_type_enforcement set to true suddenly we got serializer error.

Failed to denormalize attribute \"reportTemplate\" value for class \"App\\Entity\\Report\": Expected argument of type \"?App\\Entity\\ReportTemplate\", \"string\" given at property path \"reportTemplate\".

How to reproduce
We are sending:

{
      "reportTemplate": "/report-templates/uuid",
}

reportTemplate is a property within Report entity defined as

#[ORM\ManyToOne(targetEntity: ReportTemplate::class)]
#[Groups(['report.read', 'report.write', 'report.read.list'])]
#[Assert\NotNull]
#[Metadata\ApiProperty(required: true)]
private ?ReportTemplate $reportTemplate = null;

And resouce is defined with:

denormalizationContext: ['groups' => ['report.write'], 'disable_type_enforcement' => true]

I've tracked the problem to the change in #5593

if (null === $value && $type->isNullable() || ($context[static::DISABLE_TYPE_ENFORCEMENT] ?? false)) {
    return $value;
}

This stops processing the IRI and just returns it instead of fetching the object. Removing from the resource definition 'disable_type_enforcement' => true fixes the problem.

@soyuka
Copy link
Member

soyuka commented Aug 25, 2023

are you using application/ld+json?

We are sending:

POST ? PUT ? PATCH ?

@bizley
Copy link
Author

bizley commented Aug 25, 2023

Sorry, right. Ld+json and post

@emmanuelballery
Copy link
Contributor

I have a small reproducer with a Datetime!

composer create-project symfony/skeleton:"6.3.*" api-platform-test
cd api-platform-test
composer require api

This gives me api-platform/core v3.1.15. The last "working" version was v3.1.12.


Add this class in src/ApiResource/:

<?php declare(strict_types=1);

namespace App\ApiResource;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use DateTime;

#[ApiResource(
    operations: [new Post()],
    denormalizationContext: ['disable_type_enforcement' => true],
)]
class Dummy
{
    #[ApiProperty(identifier: true)]
    public ?int $id = null;

    public ?DateTime $date = null;
}

Add this class in src/Command/:

<?php declare(strict_types=1);

namespace App\Command;

use App\ApiResource\Dummy;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Serializer\SerializerInterface;

#[AsCommand('app:dummy', 'Dummy test!')]
class DummyCommand extends Command
{
    public function __construct(
        private readonly SerializerInterface $serializer,
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->serializer->deserialize(
            '{"date":"2022-01-01T00:00:00.000Z"}',
            Dummy::class,
            'json',
            ['disable_type_enforcement' => true],
        );

        return self::SUCCESS;
    }
}

Then run:

php bin/console app:dummy -vvv

And you'll get this:

[Symfony\Component\Serializer\Exception\NotNormalizableValueException] Failed to denormalize attribute "date" value for class "App\ApiResource\Dummy": Expected argument of type "?DateTime", "string" given at property path "date".

Exception trace:
  at /var/www/api-platform-test/vendor/symfony/serializer/Exception/NotNormalizableValueException.php:32
 Symfony\Component\Serializer\Exception\NotNormalizableValueException::createForUnexpectedDataType() at /var/www/api-platform-test/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php:392
 Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer->denormalize() at /var/www/api-platform-test/vendor/api-platform/core/src/Serializer/AbstractItemNormalizer.php:239
 ApiPlatform\Serializer\AbstractItemNormalizer->denormalize() at /var/www/api-platform-test/vendor/api-platform/core/src/Serializer/ItemNormalizer.php:72
 ApiPlatform\Serializer\ItemNormalizer->denormalize() at /var/www/api-platform-test/vendor/symfony/serializer/Serializer.php:234
 Symfony\Component\Serializer\Serializer->denormalize() at /var/www/api-platform-test/vendor/symfony/serializer/Serializer.php:152
 Symfony\Component\Serializer\Serializer->deserialize() at /var/www/api-platform-test/src/Command/DummyCommand.php:29
 App\Command\DummyCommand->execute() at /var/www/api-platform-test/vendor/symfony/console/Command/Command.php:326
 Symfony\Component\Console\Command\Command->run() at /var/www/api-platform-test/vendor/symfony/console/Application.php:1081
 Symfony\Component\Console\Application->doRunCommand() at /var/www/api-platform-test/vendor/symfony/framework-bundle/Console/Application.php:91
 Symfony\Bundle\FrameworkBundle\Console\Application->doRunCommand() at /var/www/api-platform-test/vendor/symfony/console/Application.php:320
 Symfony\Component\Console\Application->doRun() at /var/www/api-platform-test/vendor/symfony/framework-bundle/Console/Application.php:80
 Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /var/www/api-platform-test/vendor/symfony/console/Application.php:174
 Symfony\Component\Console\Application->run() at /var/www/api-platform-test/vendor/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php:54
 Symfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner->run() at /var/www/api-platform-test/vendor/autoload_runtime.php:29
 require_once() at /var/www/api-platform-test/bin/console:11

@emmanuelballery
Copy link
Contributor

emmanuelballery commented Aug 29, 2023

@soyuka there is a strange diff between 3.1 and main here :

In 3.1, parentheses are missing:

if (null === $value && $type->isNullable() || ($context[static::DISABLE_TYPE_ENFORCEMENT] ?? false)) {
return $value;
}

But in main it's ok:

if (null === $value && ($type->isNullable() || ($context[static::DISABLE_TYPE_ENFORCEMENT] ?? false))) {
return $value;
}

This fixes the issue for me.

@dannyvw
Copy link
Contributor

dannyvw commented Oct 3, 2023

We have the same issue and with the parentheses it fixes the issue.

@soyuka
Copy link
Member

soyuka commented Oct 17, 2023

thanks, this was fixed on main but we forgot to backport to 3.1

@soyuka soyuka closed this as completed Oct 17, 2023
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

No branches or pull requests

4 participants