I have a custom Symfony 4 deserializer
class CardImageDecoder implements EncoderInterface, DecoderInterface { public function encode($data, $format, array $context = []) { if($format !== 'json') { throw new EncodingFormatNotSupportedException(sprintf('Format %s is not supported by encoder %s', $format, __CLASS__)); } $result = json_encode($data); if(json_last_error() !== JSON_ERROR_NONE) { // don't bother with a custom error message throw new Exception(sprintf('Unable to encode data, got error message: %s', json_last_error_msg())); } return $result; } public function supportsEncoding($format) { return 'json' === $format; } public function decode($data, $format, array $context = []) { if($format !== 'array') { throw new DecodingFormatNotSupportedException(sprintf('Format %s is not supported by encoder %s', $format, __CLASS__)); } if(!is_array($data)) { throw new UnexpectedValueException(sprintf('Expected array got %s', gettype($data))); } $cardInstance = new CardImages(); $cardInstance->setHeight($data['h'] ?? 0); $cardInstance->setPath($data['url'] ?? ''); $cardInstance->setWidth($data['w'] ?? 0); return $cardInstance; } public function supportsDecoding($format) { return 'array' === $format; } }
The way I’m deserializing is pretty straight forward:
$json = ' { "url": "some url", "h": 1004, "w": 768 }'; $encoders = [new CardImageDecoder()]; $normalizers = [new ObjectNormalizer()]; $serializer = new Serializer($normalizers, $encoders); $cardImage = $serializer->deserialize(json_decode($json, true), CardImages::class, 'array'); /** @var $cardImage CardImages */ var_dump($cardImage);
However, I get this result returned:
object(AppEntityCardImages)#158 (5) { ["id":"AppEntityCardImages":private]=> NULL ["path":"AppEntityCardImages":private]=> NULL ["height":"AppEntityCardImages":private]=> NULL ["width":"AppEntityCardImages":private]=> NULL ["movie":"AppEntityCardImages":private]=> NULL }
Now, if I were to do a dump, just before the return in the decode
part of the decoder, I’d get this:
... $cardInstance->setWidth($data['w'] ?? 0); var_dump($cardInstance); object(AppEntityCardImages)#153 (5) { ["id":"AppEntityCardImages":private]=> NULL ["path":"AppEntityCardImages":private]=> string(8) "some url" ["height":"AppEntityCardImages":private]=> int(1004) ["width":"AppEntityCardImages":private]=> int(768) ["movie":"AppEntityCardImages":private]=> NULL }
Ignoring the not set properties(which I’m fine with), it should work quite nicely, but it doesn’t.
For the life of me I can’t figure out what’s wrong.
Any help is appreciated.
Advertisement
Answer
You are thinking way to complicated.
Tested, working example:
Your entity – take a closer look at the end – we need setters with the names of your array keys:
namespace AppDomain; class CardImages { /** @var int|null */ private $id; /** @var int|null */ private $height; /** @var string|null */ private $path; /** @var int|null */ private $width; /** @var mixed */ private $movie; /** * @return int|null */ public function getId(): ?int { return $this->id; } /** * @param int|null $id * @return CardImages */ public function setId(?int $id): CardImages { $this->id = $id; return $this; } /** * @return int|null */ public function getHeight(): ?int { return $this->height; } /** * @param int|null $height * @return CardImages */ public function setHeight(?int $height): CardImages { $this->height = $height; return $this; } /** * @return string|null */ public function getPath(): ?string { return $this->path; } /** * @param string|null $path * @return CardImages */ public function setPath(?string $path): CardImages { $this->path = $path; return $this; } /** * @return int|null */ public function getWidth(): ?int { return $this->width; } /** * @param int|null $width * @return CardImages */ public function setWidth(?int $width): CardImages { $this->width = $width; return $this; } /** * @return mixed */ public function getMovie() { return $this->movie; } /** * @param mixed $movie * @return CardImages */ public function setMovie($movie) { $this->movie = $movie; return $this; } public function setH(?int $height): CardImages { $this->setHeight($height); return $this; } public function setUrl(?string $url): CardImages { $this->setPath($url); return $this; } public function setW(?int $width): CardImages { $this->setWidth($width); return $this; } }
Simple Controller to test the Output:
<?php namespace AppInfrastructureWebController; use AppDomainCardImages; use SymfonyBundleFrameworkBundleControllerAbstractController; use SymfonyComponentHttpFoundationResponse; use SymfonyComponentRoutingAnnotationRoute; use SymfonyComponentSerializerNormalizerObjectNormalizer; use SymfonyComponentSerializerSerializerInterface; /** * Class IndexController. * * @Route("/test") */ class TestController extends AbstractController { private $serializer; public function __construct(SerializerInterface $serializer) { $this->serializer = $serializer; } /** * @Route("") * * @return Response */ public function indexAction(): Response { $data = [ [ 'h' => 100, 'w' => 100, 'path' => '/asdf/asdf.png', ], [ 'h' => 50, 'w' => 150, 'path' => '/asdf/foo.png', ], [ 'h' => 100, 'w' => 200, 'path' => '/asdf/bar.png', ], [ 'h' => 300, 'w' => 400, 'path' => '/asdf/baz.png', ], ]; foreach ($data as $row) { $cardImage = $this->serializer->denormalize($row, CardImages::class, null, [ ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => false ]); $json = $this->serializer->serialize($cardImage, 'json'); dump($cardImage, $json); } return new Response('<html><head></head></html></body></html>'); } }