Symfony/FosRestBundle et relation entre entité

a marqué ce sujet comme résolu.
Auteur du sujet

Bonjour,

Je vous remercie pour votre excellent tutoriel sur l’API Rest de Symfony ! Cependant j’ai une question car je me retrouve bloqué en voulant POST une entity qui possède une relation ManyToOne vers une autre entity.

Pour résumer, je dispose de 2 entity : "Annonce" et "Localisation". Une "Annonce" possède une relation ManyToOne vers une "Localisation". La table "localisation" contient des données de référence avec le nom des villes, code postaux, etc. Côté UI, lorsque je crée une nouvelle annonce, je récupère via un autocomplete mon objet "Localisation". Lorsque je soumets mon formulaire j’ai un objet sérialisé qui ressemble à :{ title: 'Mon annonce', description: 'Ma description', location: { id: 10, city: 'Ma ville' }}

Lorsque je récupère le body de ma requête, tout les éléments sont présents. Cependant le FormBuilder ne parvient à déserialiser l’objet. Dans le AnnonceType.php :builder->add(...)->add('location', LocationType::class)

Cependant l’attribut ’location’ de l’objet désérialisé est toujours null.

Avez-vous une idée ?

+0 -0
Auteur du sujet

Salut,

Merci pour le lien, j’ai été sur la documentation de Symfony pour tester différentes façons mais je n’ai rien trouvé de fonctionnel.

GearAdvertisementType.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<?php
class GearAdvertisementType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('price')
            ->add('location', EntityType::class, array(
                'class' => 'AppBundle:Location'
            ));
            //->add('location', LocationType::class);
    }

`

Et le LocationType.php :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
class LocationType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            //->add('id')
            ->add('city')
            ->add('postalCode')
            ->add('gpsCoordinates');
    }

Les commentaires portent à propos de ce que j’ai pu essayer. Je pense que le problème vient du fait que je possède déjà un id pour Location.

Édité par rsaenen

+0 -0

Cette réponse a aidé l’auteur du sujet

L’EntityType étend la classe ChoiceType de Symfony. Dans l’attribut location, tu ne peux pas mettre un objet mais plutôt son identifiant.

Avec un formulaire classique le payload devrait ressembler à :

1
{ title: 'Mon annonce', description: 'Ma description', location: 10}

Mais avec REST, personnellement je n’utiliserais pas cette technique.

Les commentaires portent à propos de ce que j’ai pu essayer. Je pense que le problème vient du fait que je possède déjà un id pour Location.

Donc tu ajoutes un commentaire à une location. Je partirais plus sur :

1
POST /locations/{id_de_location}/comments

Payload:

1
{ title: 'Mon annonce', description: 'Ma description'}

Dans mon contrôleur ou mon service, je lis le commentaire à la location manuellement. Dans le cours c’est comme dans la relation entre Place et Price

Édité par BestCoder

Auteur du sujet

Merci, j’ai pensé à cette solution mais cela ne posera pas problème lorsqu’une annonce dépendra d’une catégorie, sous-catégorie, type, etc. ?
Je peux me retrouver avec une route :
POST /location/{location_id}/category/{category_id}/type/{type_id}/...

Côté FO, j’utilise TypeScript et mes DTO sont identiques à mes Entities, par conséquent il me sera plus pratique de poster l’objet complet plutôt que décomposé comme dans l’exemple. Est-ce la seule solution ?

EDIT: En parlant de commentaires, je parlais du code commenté, pas d’ajouter des commentaires. J’aurais du préciser.

Édité par rsaenen

+0 -0

Est-ce la seule solution ?

D’un point de vue purement REST, ça serait la meilleure solution. Tu postes l’objet complet alors qu’en réalité, il n’y a que son identifiant qui t’intéresse.

Mais les formulaires imbriqués pourraient aussi faire l’affaire (mais ça sera très moche). Il faudra le coupler avec les data transformers.

Auteur du sujet

En optant pour la solution REST, je vais récupérer mon Annonce via le Payload et construire mon Entity à partir du FormBuilder.
Pour lier mon location_id à mon Annonce, je génère une référence de Location avec EntityManager en lui passant location_id en paramètre ? C’est peut-être mieux que de récupérer l’objet ?

Pour la validation de mon paramètre location_id, quel est le plus intéressant ?

Le lien vers le cours Place et Price me retourne une 403, mais j’ai retrouvé de quel passage il s’agissait.

+0 -0

En optant pour la solution REST, je vais récupérer mon Annonce via le Payload et construire mon Entity à partir du FormBuilder. Pour lier mon location_id à mon Annonce, je génère une référence de Location avec EntityManager en lui passant location_id en paramètre ? C’est peut-être mieux que de récupérer l’objet ?

L’idéal serait de le récupérer de la base de données. Tu pourras ainsi vérifier qu’il existe et rajouter d’autres contraintes si besoin.

Pour la validation de mon paramètre location_id, quel est le plus intéressant ?

Normalement seul son existence est important. En le récupérant depuis ta base de données, tu en auras la preuve.

Le lien vers le cours Place et Price me retourne une 403, mais j’ai retrouvé de quel passage il s’agissait.

J’ai édité mon post. J’avais mis le lien du cours pour l’édition ^^ .

Auteur du sujet

Merci pour ces éclaircissements, je vais essayer de me documenter sur les références car je pense que cela peut être couteux de systématiquement récupérer toutes les relations de mon entité. :)

+0 -0

Bonjour, j’ai lu l’ensemble de la discussion et j’avoue que je ne comprends pas totalement. En effet, j’ai un cas de figure pareil aujourd’hui. Pour ma relation (ManyToOne self-referencing je suis contraint de préciser mon entité parent (le cas avec "Location" @rsaenen).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Folder", mappedBy="topFolder")
     */
    private $subFolders;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Folder", inversedBy="subFolders", cascade={"persist"})
     * @ORM\JoinColumn(nullable=true, referencedColumnName="id")
     */
    private $topFolder = null;

Cependant, étant donné que l’entité parent est déjà existant, j’ai une erreur (évidemment). Pour faire court, c’est une gestion de dossier; et 1 dossier peut en contenir. Du coup, lors de l’enregistrement d’un dossier, je dois préciser le répertoire parent ou "null" s’il n’en possède pas. Le cas où le dossier parent vaut "null", l’enregistrement marche correct. Bien sûr, passer l’id de l’objet parent ne fonctionne pas; devrais-je procéder par un Form ? J’ai lu où BestCoder dit que la meilleure solution serait de passer l’objet entier sachant que seul l’id nous intéresse. Comment y procéder ? Merci d’avance.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte