web-dev-qa-db-fra.com

Symfony - Désérialiser json en un tableau d'entités

J'ai un objet JSON que j'ai reçu en effectuant un appel API. Je fais cet appel pour recevoir une liste d'objets. C'est une liste de publications ... J'ai donc un tableau d'objets de publication. 

Voici la sortie:

{
    "total":2,
    "data":[
      {
        "id":2,
        "user":{
          "id":1,
          "username":"sandro.tchikovani"             
        },
        "description":"cool",
        "nb_comments":0,
        "nb_likes":0,
        "date_creation":"2014-04-13T20:07:34-0700"
      },
      {
        "id":1,
        "user":{
           "id":1,
           "username":"sandro.tchikovani",
         },
        "description":"Premier pooooste #lol",
        "nb_comments":0,
        "nb_likes":0,
        "date_creation":"2014-04-13T15:15:35-0700"
      }
    ]
 }

Je voudrais désérialiser la partie données ... Le problème est que le sérialiseur de Symfony me donne une erreur ...

L'erreur que j'ai:

Class array<Moodress\Bundle\PosteBundle\Entity\Poste> does not exist

Comment je désérialise:

$lastPosts = $serializer->deserialize($data['data'], 'array<Moodress\Bundle\PosteBundle\Entity\Poste>', 'json');

Comment puis-je désérialiser le tableau de données ... Pour avoir un tableau de Postes. Je veux donner à ma vue .twig un tableau Poste ... J'ai précisé le type quand je désérialise ... Je ne peux donc pas trouver le problème 

Merci.

12
manonthemoon

L'erreur est assez claire. Votre chaîne ne correspond à aucune classe existante.

L'exemple dans la documentation officielle dit:

$person = $serializer->deserialize($data,'Acme\Person','xml');

Dans votre cas, cela devrait ressembler davantage à:

$person = $serializer->deserialize($data['data'],'Moodress\Bundle\PosteBundle\Entity\Poste','json');

Mettre à jour:

Alors ok.

Tout d’abord, votre fichier json ne semble pas être valide (utilisez http://jsonlint.com/ pour le tester). Attention à ça.

Deuxièmement, vous devrez récupérer votre json sous forme de tableau avec

$data = json_decode($yourJsonFile, true);

et alors vous pouvez accéder à chaque tableau 'data' avec

foreach($data['data'] as $result)
{
    /* Here you can hydrate your object manually like:
    $person = new Person();
    $person->setId($user['id']);
    $person->setDescription($user['description']);

    Or you can use a denormalizer. */
}
7
Einenlum

Je pense que la meilleure solution ici est de créer une nouvelle classe PosteResponse, comme celle-ci:

namespace Moodress\Bundle\PosteBundle\Response;

use JMS\Serializer\Annotation\Type;

class PosteResponse
{
    /**
     * @Type("integer")
     */
    private $total;

    /**
     * @Type("array<Moodress\Bundle\PosteBundle\Entity\Poste>")
     */
    private $data;

    // Getters and setters here...
}

et désérialisez votre réponse à cette classe:

$response = $serializer->deserialize(
    $json,
    'Moodress\Bundle\PosteBundle\Response\PosteResponse',
    'json'
);
$posts = $response->getData();

Cela fera l'affaire, et cela ne vous oblige pas à décoder et à encoder votre json manuellement, ce qui est ridicule à mon avis.

17
Mikz

Une solution moins qu'idéale que j'ai trouvée consistait tout d'abord à décoder puis à coder à nouveau les données JSON au niveau du nœud qui représente le tableau de données. Par exemple dans votre cas:

$json = json_decode($json);
$json = json_encode($json->data);
$serializer->deserialize($json, 'array<Moodress\Bundle\PosteBundle\Entity\Poste>', 'json');

Il doit y avoir une meilleure solution que cela, mais cela semble plus élégant que la solution ci-dessus de déssérialisation de JSON.

12
Malachi

Depuis Symfony Serializer Component 2.8 pour désérialiser un tableau d'objets:

$persons = $serializer->deserialize($data, 'Acme\Person[]', 'json');

https://symfony.com/doc/master/components/serializer.html#handling-arrays

2
user6863579

Je ferais quelque chose comme ça

class PostsModel
{
    /**
     * @var int
     */
    private $total;

    /**
     * @var PostModel[]
     */
    private $data;
}

class PostModel
{
    /**
     * @var int
     */
    private $id;

    /**
     * @var UserModel
     */
    private $user;

    /**
     * @var string
     */
    private $description;

    /**
     * @var  int
     */
    private $nb_comments;

    /**
     * @var int
     */
    private $nb_likes;

    /**
     * @var \DateTime
     */
    private $date_creation;
}

class UserModel
{
    /**
     * @var int
     */
    private $id;

    /**
     * @var string
     */
    private $username;
}

Et dans le contrôleur 

            $posts = $this->serializer->deserialize($data, PostsModel::class, 'json');

Et cela retournera $ postsModel avec la propriété $ data qui aura votre tableau d'entités

1
Ruslan Kovalov