skip to Main Content

I have 2 DTO objects and I need to convert json to it:

class SomeDTO
{
    public function __construct(
        #[SerializedName('some_property')]
        private string $someProperty,
        #[SerializedName('some_other_property')]
        private int $someOtherProperty,
    ) {
    }

    public function getSomeProperty(): string
    {
        return $this->someProperty;
    }

    public function setSomeProperty(string $someProperty): self
    {
        $this->someProperty = $someProperty;

        return $this;
    }

    public function getSomeOtherProperty(): int
    {
        return $this->someOtherProperty;
    }

    public function setSomeOtherProperty(int $someOtherProperty): self
    {
        $this->someOtherProperty = $someOtherProperty;

        return $this;
    }
}

and

class ArrDTO
{
    /**
     * @param SomeDTO[] $arr
     */
    public function __construct(
        private array $arr
    ) {
    }

    /**
     * @return SomeDTO[]
     */
    public function getArr(): array
    {
        return $this->arr;
    }

    /**
     * @param SomeDTO[] $arr
     * @return $this
     */
    public function setArr(array $arr): self
    {
        $this->arr = $arr;
        
        return $this;
    }
}

So the ArrDTO::$arr property is array of SomeDTO objects.
And I have such json which is have the same structure like ArrDTO:

$json = '{"arr":[{"some_property":"str","some_other_property":1},{"some_property":"str2","some_other_property":2}]}';

The goal – convert this $json to ArrDTO with Serializer.
This code

use SymfonyComponentSerializerSerializerInterface;
...
$arrDTO = $serializer->deserialize($json, ArrDTO::class, 'json');

gives me an ArrDTO but with array[] (array of arrays) in $this->arr property instead of SomeDTO[] (array of SomeDTO). Is there any way to achieve it with serializer?

2

Answers


  1. Force not the type in the function:

       /*
        * @return SomeDTO[]
        */
        public function getArr()
        {
            return $this->arr;
        }
    
    Login or Signup to reply.
  2. You can make your own deserializer with your own denorlizer.

    The denormalizer takes care of instantiating each SomeDTO to place them in the array of the ArrDTO

    <?php
    namespace AppNormalizer;
    
    use AppDTOSomeDTO;
    use SymfonyComponentSerializerNormalizerDenormalizerInterface;
    use AppDTOArrDTO;
    class ArrDTODenormalizer implements DenormalizerInterface
    {
        public function denormalize($data, string $type, string $format = null, array $context = []): mixed
        {
            $someDTOs = [];
    
            foreach ($data['arr'] as $item) {
                $someDTOs[] = new SomeDTO(
                    $item['some_property'],
                    $item['some_other_property']
                );
            }
            return new ArrDTO($someDTOs);
        }
    
        public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
        {
            return $type === ArrDTO::class;
        }
    
        public function getSupportedTypes(?string $format): array
        {
            return [
                ArrDTO::class => true
            ];
        }
    }
    

    and you assemble your serializer including your denormalizer

    $objectNormalizer = new ObjectNormalizer();
    $arrDTODenormalizer = new ArrDTODenormalizer($objectNormalizer);
    
    $serializer = new Serializer(
       [$arrDTODenormalizer, $objectNormalizer],
       [new JsonEncoder()]
    );
    

    and use it

    $arrDTO = $serializer->deserialize($json, ArrDTO::class, 'json');
    

    I think there are probably other solutions to play differently with the serializer

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search