Reputation: 31
I've been wondering if it's possible to use the JMS Serializer to deserialize JSON into an existing object.
Usually that would be useful for updating an existing object with new data that you have in a JSON format. Symfony's standard deserializer seems to offer that, but I can't seem to find anything about this with JMS. Have to use JMS though if I want the serializedName Annotation option.
The "workaround" is to deserialize and then use Doctrine's EntityManager to merge, but that only works so well, and you can't easily discern which fields are updated if the JSON doesn't contain every single field.
Upvotes: 2
Views: 3680
Reputation: 1287
I have struggled to find the solution but finally found it and here we go:
services.yaml
jms_serializer.object_constructor:
alias: jms_serializer.initialized_object_constructor
jms_serializer.initialized_object_constructor:
class: App\Service\InitializedObjectConstructor
arguments: ["@jms_serializer.unserialize_object_constructor"]
App\Service\InitializedObjectConstructor.php
<?php
declare(strict_types=1);
namespace App\Service;
use JMS\Serializer\Construction\ObjectConstructorInterface;
use JMS\Serializer\DeserializationContext;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
class InitializedObjectConstructor implements ObjectConstructorInterface
{
private $fallbackConstructor;
/**
* @param ObjectConstructorInterface $fallbackConstructor Fallback object constructor
*/
public function __construct(ObjectConstructorInterface $fallbackConstructor)
{
$this->fallbackConstructor = $fallbackConstructor;
}
/**
* {@inheritdoc}
*/
public function construct(
DeserializationVisitorInterface $visitor,
ClassMetadata $metadata,
$data,
array $type,
DeserializationContext $context
): ?object {
if ($context->hasAttribute('target') && 1 === $context->getDepth()) {
return $context->getAttribute('target');
}
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
}
}
$object = $this->entityManager->find('YourEntityName', $id);
$context = new DeserializationContext();
$context->setAttribute('target', $object);
$data = $this->serializer->deserialize($request->getContent(), 'YourEntityClassName', 'json', $context);
Upvotes: 4
Reputation: 31
So this can be done, I haven't fully worked out how, but I switched away from JMS again, so just for reference, since I guess it's better than keeping the question open for no reason:
https://github.com/schmittjoh/serializer/issues/79 and you might find more digging around the GitHub too.
Upvotes: 1