doctrine-json-odm
doctrine-json-odm copied to clipboard
Can't get to work with DateTime denormalization
I've used previously the 0.1.3
version and wanted to update it to v1. I've done the setup according to the documentation, just that 3 normalizer, but somehow my dateTime is not deserialized.
I've checked it with xdebug and all 3 normalizers are registered and they have the right order.
My json string:
[{"#type": "App\\Entity\\EventSchedule", "endDate": "2020-04-11T00:00:00+02:00", "startDate": "2020-01-07T00:00:00+01:00"}]
EventSchedule
class EventSchedule
{
/**
* Start date.
*
* @var DateTimeImmutable
*/
private $startDate;
/**
* End date.
*
* @var DateTimeImmutable
*/
private $endDate;
}
Error message:
Failed to denormalize attribute "endDate" value for class "App\Entity\EventSchedule": Expected argument of type "DateTimeImmutable", "string" given at property path "endDate"
I would highly appreciate any help. I have ApiPlatform installed, but in this request, it's not used. I tried just calling the service in the controller and passing the string to the deserialize event.
Did you check the FAQ? https://github.com/dunglas/doctrine-json-odm#faq
Yes, that's what I meant with documentation. And the 3 normalizers, what are under the FAQ are registered.
Okay. So if you're using xdebug you should see if the datetime normalizer is called, right?
Yes, and that's the problem that it's not called but the DateTimeNormalizer is one of the 3 normalizers and I can't figure it out why.
I've taken a look at it again and I will try to create tomorrow an example SF app for this.
What I've found with XDebug that it finds the DateTimeDenormalizer
and when it calls in the serializer the dernormalize methode, it calls the denormalize
methode from Dunglas Serializer.
As the data is 2020-04-11T00:00:00+02:00
it skips the first if and not iterable, so skips the 2nd if and just simply returns the data, without a parent::denormalize
call.
Ok, I know what the problem is and it's connected to my previous comment. I've found no update.MD file so I thought the old serialized data should be comatible with the new. I did a serialization and that is the result:
[{"#type": "App\\Entity\\Event\\EventSchedule", "endDate":{"#type":"DateTimeImmutable","#scalar":"2020-04-11T00:00:00+02:00"}, "startDate": {"#type":"DateTimeImmutable","#scalar":"2020-01-07T00:00:00+01:00"}}]
instead of the result in the DB with version 0.1.3
[{"#type": "App\\Entity\\EventSchedule", "endDate": "2020-04-11T00:00:00+02:00", "startDate": "2020-01-07T00:00:00+01:00"}]
I think this should be documented somewhere.
Or am I doing something wrong here @Toflar ?
You can always use the compiler pass to add all the normalizers & encoders:
$container->addCompilerPass(new SerializerPass('dunglas_doctrine_json_odm.serializer'));
@dunglas i changed the Symfony SerializerPass to work with your code, this will prevent these types of issues:
<?php
namespace App\Shared\Infrastructure\Symfony\Serializer;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
class SerializerPass implements CompilerPassInterface
{
use PriorityTaggedServiceTrait;
private string $serializerService;
private string $normalizerTag;
private string $encoderTag;
public function __construct(string $serializerService = 'dunglas_doctrine_json_odm.serializer', string $normalizerTag = 'serializer.normalizer', string $encoderTag = 'serializer.encoder')
{
$this->serializerService = $serializerService;
$this->normalizerTag = $normalizerTag;
$this->encoderTag = $encoderTag;
}
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition($this->serializerService)) {
return;
}
if (!$normalizers = $this->findAndSortTaggedServices($this->normalizerTag, $container)) {
throw new RuntimeException(sprintf('You must tag at least one service as "%s" to use the "%s" service.', $this->normalizerTag, $this->serializerService));
}
array_unshift($normalizers, new Reference('dunglas_doctrine_json_odm.normalizer.array'));
$normalizers[] = new Reference('dunglas_doctrine_json_odm.normalizer.object');
$serializerDefinition = $container->getDefinition($this->serializerService);
$serializerDefinition->replaceArgument(0, $normalizers);
if (!$encoders = $this->findAndSortTaggedServices($this->encoderTag, $container)) {
throw new RuntimeException(sprintf('You must tag at least one service as "%s" to use the "%s" service.', $this->encoderTag, $this->serializerService));
}
$serializerDefinition->replaceArgument(1, $encoders);
}
}
For me it was only 20 entries in the database, I just changed it with a script, but I think it would be good to mentions this difference.