skip to Main Content

I receive a JSON string containing an array of objects similar to this:

{"expert": "foo", "username": "bar", "activity": [{"action": "RFDF", "count": 172}","{"action": "RETA", "count": 10},{"action": "AS", "count": 3}]}

I want to decode it into a model like this (I read in documentation to use SymfonyComponentSerializerAnnotationSerializedPath in order to create nested properties):

<?php

declare(strict_types=1);

namespace AppModel;

use SymfonyComponentSerializerAnnotationSerializedPath;

class ActivityModel
{
    private string $expert;
    private string $username;
    private array $activity;
    /**
     * @var string
     * @SerializedPath("[activity][action]")
     */
    private string $action;
    /**
     * @var string
     * @SerializedPath("[activity][count]")
     */
    private string $count;

    /**
     * @return string
     */
    public function getExpert(): string
    {
        return $this->expert;
    }

    /**
     * @param string $expert
     * @return ActivityModel
     */
    public function setExpert(string $expert): self
    {
        $this->expert = $expert;

        return $this;
    }

    /**
     * @return string
     */
    public function getUsername(): string
    {
        return $this->username;
    }

    /**
     * @param string $username
     * @return ActivityModel
     */
    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }

    /**
     * @return array
     */
    public function getActivity(): array
    {
        return $this->activity;
    }

    /**
     * @param array $activity
     * @return ActivityModel
     */
    public function setActivity(array $activity): self
    {
        $this->activity = $activity;

        return $this;
    }

    /**
     * @return string
     */
    public function getAction(): string
    {
        return $this->action;
    }

    /**
     * @param string $action
     * @return ActivityModel
     */
    public function setAction(string $action): self
    {
        $this->action = $action;

        return $this;
    }

    /**
     * @return string
     */
    public function getCount(): string
    {
        return $this->count;
    }

    /**
     * @param string $count
     * @return ActivityModel
     */
    public function setCount(string $count): self
    {
        $this->count = $count;

        return $this;
    }
}

When I execute the deserialization in my controller

$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);

return $serializer->deserialize($json, ActivityModel::class, 'json');

I get an exception Failed to denormalize attribute "activity" value for class "AppModelActivityModel": Expected argument of type "array", "string" given at property path "activity".

Does Serializer need a configuration / context to keep arrays during deserialization ? And as a fallback, how could I simply decode my JSON to an array ?

Thanks by advance.

2

Answers


  1. Chosen as BEST ANSWER

    Here is my AbstractController implementing Serializer through DI:

    class AbstractController extends BaseAbstractController // extends FrameworkBundle AbstractController
    {
        private SerializerInterface $serializer;
    
        public function __construct(SerializerInterface $serializer)
        {
            $this->serializer = $serializer;
        }
    
        public function jsonDecode(string $json): mixed
        {
            $encoders = [new JsonEncoder()];
            $normalizers = [new ObjectNormalizer(
                null,
                null,
                null,
                new ReflectionExtractor()
            )];
            $serializer = new Serializer($normalizers, $encoders);
    
            return $serializer->deserialize($json, ActivityModel::class, 'json');
        }
    
        /**
         * @param Request $request
         * @return Response
         */
        #[Route(path:'/_init_context', name:'_init_context', methods:['GET'])]
        public function contextSelector(Request $request): Response
        {
            $session = $request->getSession();
    
            if ($session->has('base')) {
                $base = $session->get('base');
            } else {
                $base = ($request->query->get('base')) ?? 1;
            }
            $session->set('base', $base);
    
            $form = $this->createForm(ContextType::class, ['base' => $base]);
    
            return $this->render('context/_selector.html.twig', [
                'contextForm' => $form
            ]);
        }
    
        /**
         * @param Request $request
         * @return Response
         */
        #[Route(path:'/_set_context', name:'_set_context', methods:['GET'])]
        public function setDatabaseContext(Request $request): Response
        {
            $session = $request->getSession();
    
            if ($request->query->has('base')) {
                $base = $request->query->get('base');
                $session->set('base', $base);
    
                return $this->json($request->query->get('base'));
            }
    
            return $this->json([], 400);
        }
    }
    

  2. There are a related question: Failed to denormalize attribute "publishedAt" value

    Why you’re not using DI to get the SerializerInterface?
    https://symfony.com/doc/current/serializer.html

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