IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

[Symfony 2.6] Persister des formulaires imbriqués [2.x]


Sujet :

Symfony PHP

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut [Symfony 2.6] Persister des formulaires imbriqués
    Bonjour,

    Je suis entrain de développer une application qui permet de saisir des commandes à l'aide de Symfony 2.6.
    L'idée est qu'une commande est liée obligatoirement à une personne et peut être composée de 1 ou plusieurs produits.

    4 entités pour cela :
    Order (les commandes)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    class Order
    {
        /**
         * @var integer
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
     
        /**
         * @ORM\OneToMany(targetEntity="XXXXX\OrderBundle\Entity\OrderProduct", mappedBy="order")
         */
        private $orderProducts;
     
        /**
         * @ORM\Column(type="decimal", scale=2)
         */
        private $totalPrice;
     
        /**
         * @ORM\Column(type="datetime")
         */
        private $date;
     
        /**
         * @ORM\ManyToOne(targetEntity="XXXX\RhBundle\Entity\Customer", inversedBy="orders")
         * @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
         */
        protected $customer;
     
    //Les GETTERS et SETTERS
    }
    Customer (les clients)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    class Customer
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
     
        /**
         * @ORM\Column(type="string", length=5)
         */
        protected $sexe;
     
        /**
         * @ORM\Column(type="string", length=100)
         */
        protected $nom;
     
        /**
         * @ORM\Column(type="string", length=50)
         */
        protected $prenom;
     
        /**
         * @ORM\Column(type="string", length=10)
         */
        protected $tel;
     
        /**
         * @ORM\Column(type="string", length=50)
         */
        protected $email;
     
        /**
         * @ORM\Column(type="string", length=50)
         */
        protected $address;
     
        /**
         * @ORM\Column(type="string", length=5)
         */
        protected $cp;
     
        /**
         * @ORM\Column(type="string", length=50)
         */
        protected $city;
     
        /**
         * @ORM\OneToMany(targetEntity="XXXXX\OrderBundle\Entity\Order", mappedBy="customer")
         */
        protected $orders;
    // les GETTERS et SETTERS
    }
    Product (les produits)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class Product
    {
        /**
         * @ORM\Column(name="reference", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="NONE")
         */
        protected $reference;
     
        /**
         * @ORM\Column(type="string", length=100)
         */
        protected $libelle;
     
        /**
         * @ORM\Column(type="decimal", scale=2)
         */
        protected $price;
     
        /**
         * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
         * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
         */
        protected $category;
     
        /**
         * @ORM\OneToMany(targetEntity="XXXXX\OrderBundle\Entity\OrderProduct", mappedBy="product")
         */
        private $orderProducts;
     
    // Les GETTERS et SETTERS
    }
    OrderProduct (l'entité de liaison entre Order et Product)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class OrderProduct
    {
        /**
         * @ORM\Id
         * @ORM\ManyToOne(targetEntity="XXXXX\OrderBundle\Entity\Order", inversedBy="orderProducts")
         * @ORM\JoinColumn(name="order_id", referencedColumnName="id")
         */
        private $order;
     
        /**
         * @ORM\Id
         * @ORM\ManyToOne(targetEntity="XXXXX\ProductBundle\Entity\Product", inversedBy="orderProducts")
         * @ORM\JoinColumn(name="product_reference", referencedColumnName="reference")
         */
        private $product;
     
        /**
         * @ORM\Column()
         */
        private $quantity;
     
    //Les GETTERS et SETTERS
    }
    J'ai créé deux formType:
    OrderType
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('totalPrice', 'text', array("label" => "XXXXXRhBundle.customers.page_new_edit.sexe"))
                ->add('date', 'date', array("label" => "XXXXXRhBundle.customers.page_new_edit.firstName"))
                ->add('customer','entity', array ('class' => 'XXXXX\RhBundle\Entity\Customer', 'empty_value' => 'Choisissez un client...', 'required' => true))
                ->add('orderProducts', 'collection', array('type' => new OrderProductType(),
                                                          'allow_add' => true,
                                                          'allow_delete' => true ));
        }
     
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Stanhome\OrderBundle\Entity\Order',
                'cascade_validation' => true,
            ));
        }
    OrderProductType
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('quantity', 'integer', array("label" => "XXXXXRhBundle.customers.page_new_edit.firstName"))
                ->add('product','entity', array ('class' => 'XXXXX\ProductBundle\Entity\Product', 'empty_value' => 'Choisissez un produit...', 'required' => true));
        }
    Lors de la soumission du formulaire OrderType, il faut donc dans un premier temps créer une commande dans la base de données et juste après créer des lignes dans l'entité OrderProduct afin d'avoir pour une commande, plusieurs produits et la quantité pour chacun des produits.

    Hors j'ai un soucis avec handleRequest(), il me dit :
    Neither the property "quantity" nor one of the methods "getQuantity()", "quantity()", "isQuantity()", "hasQuantity()", "__get()" exist and have public access in class "XXXXX\OrderBundle\Entity\Order".


    C'est normal car la propriété quantity est dans l'entité OrderProduct, pas dans l'entité Order ! Donc là je coince, je ne vois pas comment faire les enregistrements l'un à la suite de l'autre. Merci de votre aide !

    OrderController
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public function createAction(Request $request)
        {
            $entity = new Order();
            $form = $this->createCreateForm($entity); //fonction qui permet de générer le formulaire OrderType.
     
            $form->handleRequest($request);
     
    //Que faut-il écrire pour pouvoir enregistrer d'abord une commande ORDER et ensuite des lignes dans OrderProduct ???

  2. #2
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    dans OrderProduct je ne vois pas la definition d'ID auto
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Eh bien non il n'y a pas de définition d'un ID dans OrderProduct étant donné que la clé primaire est composée des deux clés étrangères vers Order et Product. Doctrine accepte très bien cela depuis la version 2.1
    https://doctrine-orm.readthedocs.org...mary-keys.html

    mon composer.json est configuré comme ceci (j'utilise la dernière version stable de Doctrine) :

    "doctrine/orm": "2.4.7",

    Mon soucis est celui-ci :

    Entity of type Stanhome\OrderBundle\Entity\OrderProduct is missing an assigned ID for field 'order'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.


    Et dans Order j'ai cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        /**
         * @ORM\OneToMany(targetEntity="OrderProduct", mappedBy="order", cascade={"persist"})
         */
        private $orderProducts;
    Donc normalement, lors de la soumission dans mon controller, il doit d'abord soumettre Order puis ensuite soumettre dans OrderProduct en récupérant l'ID de Order qui vient d'être soumis ! Mais non... Et apparement je ne suis pas le seul à avoir le soucis avec le cascade persist sous doctrine. C'est un soucis récurent sur internet mais je ne trouve pas de solution....

    OrderController

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public function createAction(Request $request)
        {
            $order = new Order();
            $orderProduct = new OrderProduct();
     
            $form = $this->createCreateForm($order);
            $form->handleRequest($request);
            $order->addOrderProduct($orderProduct);
     
            if ($request->isMethod('POST') &&  $form->isValid()) {
               $em = $this->getDoctrine()->getManager();
               $em->persist($order)
     
               // Je flush l'order pour l'insérer dan
               $em->flush();
                $em->persist($orderProduct);
     
                // Je flush OrderProduct qui doit normalement récupérer l'ID généré par Order mais rien.
                $em->flush();
                return $this->redirect($this->generateUrl('stanhome_order_order_show', array('id' => $order->getId())));
            }
     
            return array(
                'entity' => $entity,
                'form'   => $form->createView(),
            );
        }
    Le soucis c'est que même le premier flush de Order ne fonctionne pas, je ne vois pas d'enregistrement dans ma BDD... Je n'y comprends plus rien

  4. #4
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    j'ai déjà fait moulte fois ce genre de formulaire avec prototype et je n'ai aucun soucis en ajoutant l'ID auto (même si tu as des clés primaires).

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Eh bien en fait j'ai trouvé ma réponse dans la doc doctrine, une toute petite phrase :
    (Identity through foreign entities is only supported with Doctrine 2.1)

    Une clé primaire composée de clé étrangère, il n'est possible que dans la version 2.1 de Doctrine et c'est tout ! Ils ont supprimé cette fonctionnalité car trop gourmande en terme de ressources.
    Du coup, j'ai passé mon entité OrderProduct comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
     
        /**
         * @ORM\ManyToOne(targetEntity="Order", inversedBy="orderProducts")
         * @ORM\JoinColumn(name="order_id", referencedColumnName="id")
         */
        private $order;
     
        /**
         * @ORM\ManyToOne(targetEntity="Stanhome\ProductBundle\Entity\Product", inversedBy="orderProducts")
         * @ORM\JoinColumn(name="product_reference", referencedColumnName="reference")
         */
        private $product;
    Les deux clés étrangères ne font plus partie de la clé primaire, j'ai utilisé un auto-incrément sur un ID comme tu me l'as conseillé.

    Et dans ma fonction de sauvegarde dans OrderController :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public function createAction(Request $request)
        {
            $order = new Order();
            $orderProduct = new OrderProduct();
     
            $form = $this->createCreateForm($order);
            $form->handleRequest($request);
            $order->addOrderProduct($orderProduct);
     
            if ($request->isMethod('POST')) {
                $em = $this->getDoctrine()->getManager();
     
                if($em->persist($order)) {
                    echo ('OK persist');
     
                    $em->flush();
     
                } else {
                    echo ('KO perssit');
                }
     
                $em->persist($orderProduct);
                $em->flush();
     
               return $this->redirect($this->generateUrl('stanhome_order_order_show', array('id' => $order->getId())));
            }
     
            return array(
                'entity' => $order,
                'form'   => $form->createView(),
            );
        }
    Hors maintenant j'ia un nouveau problème, je n'arrive à sauvegarder (flush) mon entité Order !! Le persist de Order ne fonctionne pas !
    An exception occurred while executing 'INSERT INTO order (totalPrice, date, customer_id) VALUES (?, ?, ?)' with params ["14.21", "2013-01-01", 1]:

    SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order (totalPrice, date, customer_id) VALUES ('14.21', '2013-01-01', 1)' at line 1
    Les donnés qui sont dans le param proviennent du formulaire. Elles sont bien insérées dans mon objet Order mais impossible de le persist. J'ai essayé avec une commande SQL directement dans MySql et cela fonctionne bien.
    Pourquoi ? ahha;...

  6. #6
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    tu y es presque , ça doit être une connerie, une faute d'ortho minuscule/majuscule .....


    en direct, dans phpmyadmin , ça fonctionne ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    insert into (totalPrice, date, customer_id) VALUES ('14.21', '2013-01-01', 1)

    tu as bien écris tes getter et setter sans faute d'orthographe en rapport avec tes nom de colonnes en base de donnée (pour totalPrice, date, customer_id) ???

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    La grande blague de la journée !

    Le mot 'order' est un mot réservé dans MySql ! Il est impossible de l'utiliser en tant que nom de colonne ou de table ! Du coup j'ai du modifier le nom de l'entité Order en Shopping et là, tada, ça fonctionne parfaitement bien !


    Entre le coup de Doctrine qui n'accepte plus les clés primaires composées de clés étrangères et MySql avec les mots réservés... 3 jours de prog perdus....

  8. #8
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    et oui, je le savais mais ça ne m'a pas fais tilt sur le coup pour order. par contre j'avais vérifié dans ton code que le nom "date" n’étais pas un mot réservés.


    bon bah comme ça tu le sera pour la prochaine fois ..............



    n'oublie pas RESOLUE

  9. #9
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    J'ai encore un dernier détail à régler avec cette soumission de formulaire

    OrderController :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    public function createAction(Request $request)
        {
            $shopping = new Shopping();
            $shoppingProduct = new ShoppingProduct();
     
            $form = $this->createCreateForm($shopping);
     
             $shopping->addShoppingProduct($shoppingProduct);
     
            if ($request->isMethod('POST')) {
                $form->handleRequest($request);
     
                $em = $this->getDoctrine()->getManager();
                $em->persist($shopping)
                $em->flush();
     
                //Je parcours l'objet shopping pour itérer sur les produits qui sont passés par le formulaire
                foreach ($shopping->getShoppingProducts() as $i => $product) {
                    $shoppingProducts[$i] = new ShoppingProduct();
                    $shoppingProducts[$i]->setProduct($product->getProduct());
                    $shoppingProducts[$i]->setQuantity($product->getQuantity());
                    $shoppingProducts[$i]->setShopping($shopping);
     
                    $em->persist($shoppingProducts[$i]);
     
                }
                    $em->flush();
                return $this->redirect($this->generateUrl('stanhome_shopping_shopping_show', array('id' => $shopping->getId())));
            }
     
            return array(
                'entity' => $shopping,
                'form'   => $form->createView(),
            );
        }
    Lors de la soumission du formulaire, j'ai indiqué deux produits différents.
    J'itère donc sur le tableau ArrAYCollectoin de ShoppingProducts afin de persister les deux objets ShoppingProduct.
    Hors, voici les enregistrements qui sont dans la BDD
    Colonne
    Nom : bdd.png
Affichages : 1142
Taille : 26,4 Ko
    Si je fais un var_dump($shopping->getShoppingProducts() ): il y a bien que deux objets dans mon tablea ArrayCollection qui ont comme index 0 et 1. Tout va bien ici.
    Mais comme on peut le voir sur la capture d'écran, il y a quatres enregistrements en BDD !
    Les produits sont enregistrés en doublons dans la BDD et le second enregistrement sur les 4 ne dispose pas de shopping_id.
    Je n'y comprends rien, strictement rien du tout....
    Images attachées Images attachées  

  10. #10
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    ta boucle foreach est de trop non? enleve là et vois !

    puisque avec ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      $em = $this->getDoctrine()->getManager();
                $em->persist($shopping)
                $em->flush();
    ça le fait déjà automatiquement !



    à chaque test n'oublie pas de supprimer tous les enregistrement de shopping..

  11. #11
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Le fait d'enlever ma boucle foreach me permet de n'avoir que deux enregistrement dans la table ShoppingProduct. Un soucis de régler =)

    Par contren j'ai toujours le soucis de l'objet Shopping qui n'est pas attribué au second enregistrement.
    Alors qu'avant, j'avais certes 4 enregistrements mais 3 de bons.
    Nom : bdd.png
Affichages : 1093
Taille : 15,7 Ko

    Le soucis vient de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                $shopping->addShoppingProduct($shoppingProduct);
    Si je supprime cette ligne, les deux enregistrements effectués dans la BDD n'ont pas de shopping/id. En revanche si je le laisse, seul le premier dispose des informations. Donc il faut certainement trouver un moyen pour compter le nombre d'article soumis au formulaire et effectué cette ligne autant de fois qu'il y a de produits ?

  12. #12
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    verifie :


    (1) dans la vue, que toutes les infos sont bien présent

    (2) de retour dans le controlleur après la validation, tu fais un var_dump du retour du formulaire

    histoire de voir ou ça cloche !

  13. #13
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Comme expliquer dans le message précédent, le soucis provient de addShoppingProduct().

    Si je fais un var_dump($shopping->getShoppingProduct
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    object(Doctrine\Common\Collections\ArrayCollection)[470]
      private 'elements' => 
        array (size=2)
          0 => 
            object(Stanhome\ShoppingBundle\Entity\ShoppingProduct)[471]
              protected 'id' => null
              private 'shopping' => 
                object(Stanhome\ShoppingBundle\Entity\Shopping)[469]
                  ...
              private 'product' => 
                object(Stanhome\ProductBundle\Entity\Product)[933]
                  ...
              private 'quantity' => int 1
          1 => 
            object(Stanhome\ShoppingBundle\Entity\ShoppingProduct)[917]
              protected 'id' => null
              private 'shopping' => null
              private 'product' => 
                object(Stanhome\ProductBundle\Entity\Product)[977]
                  ...
              private 'quantity' => int 2
    J'ai donc bien mes deux produits, le premier est correct mais dans le second il manque shopping. Le résultat dans la BDD est celui présent dans la capture quelques message plus haut.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $shopping = new Shopping();
            $shoppingProduct = new ShoppingProduct();
     
            $form = $this->createCreateForm($shopping);
            $shopping->addShoppingProduct($shoppingProduct);
     
            if ($request->isMethod('POST')) {
                $form->handleRequest($request);
                var_dump($shopping->getShoppingProducts());
     
                $em = $this->getDoctrine()->getManager();
                $em->persist($shopping);
                $em->flush();
                die;
                return $this->redirect($this->generateUrl('stanhome_shopping_shopping_show', array('id' => $shopping->getId())));
            }

  14. #14
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    et dans la vue comment ça se passe ?

    si tu reçois des infos erronées c'est qu'à mon avis il doit y avoir un problème dans la structure du formulaire.... non ?

  15. #15
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Non les infos sont bonnes car si je fais un var_dump() de shopping, j'ai bien toutes les informations avec le produit. Le formulaire est ok.
    Si je fais un var_dump($request->request->get('shopping')['shoppingProducts']);
    j'obtiens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    array (size=3)
      0 => 
        array (size=2)
          'quantity' => string '1' (length=1)
          'product' => string '20094' (length=5)
      1 => 
        array (size=2)
          'quantity' => string '2' (length=1)
          'product' => string '20368' (length=5)
      2 => 
        array (size=2)
          'quantity' => string '3' (length=1)
          'product' => string '42266' (length=5)
    Donc le formulaire me renvoie bien toutes les informations indiquées pour les produits.

    C'est lors de l'ajout avec addShoppingProduct, il ne veut pas ajouter les informations de shopping dans le deuxième objet.
    Si j'ajoute 3 objet, seul le premier est correctement enregistré, les autres, il manque encore les infos pour la colonne shopping_id.

    Je pense que je me débrouille mal, peut-être faut-il faire une boucle qui itère sur chacun des produits passés par le formulaire. Et dans cette boucle, faire le addShoppingProduct(). Je ne sais pas là

  16. #16
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    et avec ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     if ($request->isMethod('POST')) {
                $form->handleRequest($request);
     
                var_dump($form->getData()); exit;
     
    ....

  17. #17
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    J'ai plutôt utilisere :
    var_dump($form->getData()->getShoppingProducts());
    Afin d'afficher la liste des objets.
    Résultat, comme le var-dump() de mes messages précédents :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    object(Doctrine\Common\Collections\ArrayCollection)[470]
      private 'elements' => 
        array (size=3)
          0 => 
            object(Stanhome\ShoppingBundle\Entity\ShoppingProduct)[471]
              protected 'id' => null
              private 'shopping' => 
                object(Stanhome\ShoppingBundle\Entity\Shopping)[469]
                  ...
              private 'product' => 
                object(Stanhome\ProductBundle\Entity\Product)[972]
                  ...
              private 'quantity' => int 1
          1 => 
            object(Stanhome\ShoppingBundle\Entity\ShoppingProduct)[956]
              protected 'id' => null
              private 'shopping' => null
              private 'product' => 
                object(Stanhome\ProductBundle\Entity\Product)[1016]
                  ...
              private 'quantity' => int 2
          2 => 
            object(Stanhome\ShoppingBundle\Entity\ShoppingProduct)[952]
              protected 'id' => null
              private 'shopping' => null
              private 'product' => 
                object(Stanhome\ProductBundle\Entity\Product)[1022]
                  ...
              private 'quantity' => int 3
    Il manque les informations dans shopping pour le 2éme et 3éme produits.

  18. #18
    Membre expert
    Avatar de dukoid
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2012
    Messages
    2 100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2012
    Messages : 2 100
    Points : 3 004
    Points
    3 004
    Par défaut
    c'est qu'il y a un problème avec tes formTypes, ta vue, puisque tu récupère des données incomplètes dans le controlleur....


    question con, pour ta collection tu as bien ajouté les add et remove et le new arrayCollection dans le constructeur dans les entités ?

  19. #19
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 43
    Points
    43
    Par défaut
    Ce que je ne comprends pas, c'est pourquoi dans se cas le premier produit est correctement enregistré ?
    Normalement, le champ shopping de ShoppingProduct correspond à l'objet Shopping qui vient tout juste d'être créé, et ensuite par la cascade....

    Donc je croyais que avec le handleRequest(), symfony se chargeait automatiquement comme un grand garçon de rajouter l'objet Shopping créé dans le champ shopping de ShoppingProduct.

    Sinon, voici le ShoppingType en entier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <?php
    namespace Stanhome\ShoppingBundle\Form;
     
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
     
    class ShoppingType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('totalPrice', 'text', array("label" => "StanhomeRhBundle.customers.page_new_edit.sexe"))
                ->add('dateorder', 'date', array("label" => "StanhomeRhBundle.customers.page_new_edit.firstName"))
                ->add('customer','entity', array ('class' => 'Stanhome\RhBundle\Entity\Customer', 'empty_value' => 'Choisissez un client...', 'required' => true))
                ->add('shoppingProducts', 'collection', array('type' => new ShoppingProductType(),
                                                          'allow_add' => true,
                                                          'allow_delete' => true ));
        }
     
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Stanhome\ShoppingBundle\Entity\Shopping',
                'cascade_validation' => true,
            ));
        }
     
        /**
         * Returns the name of this type.
         *
         * @return string The name of this type
         */
        public function getName()
        {
            return 'shopping';
        }
    }
    ShoppingProductType :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <?php
    namespace Stanhome\ShoppingBundle\Form;
     
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
     
    class ShoppingProductType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('quantity', 'integer', array("label" => "StanhomeRhBundle.customers.page_new_edit.firstName"))
                ->add('product','entity', array ('class' => 'Stanhome\ProductBundle\Entity\Product', 'empty_value' => 'Choisissez un produit...', 'required' => true));
        }
     
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => 'Stanhome\ShoppingBundle\Entity\ShoppingProduct'
            ));
        }
     
        /**
         * Returns the name of this type.
         *
         * @return string The name of this type
         */
        public function getName()
        {
            return 'shoppingProduct';
        }
    }
    Le constructeur et le add de Shopping:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
        /**
         * Constructor
         */
        public function __construct()
        {
            $this->shoppingProducts = new \Doctrine\Common\Collections\ArrayCollection();
        }
     
        /**
         * Add orderProducts
         *
         * @param \Stanhome\ShoppingBundle\Entity\ShoppingProduct $shoppingProducts
         * @return Shopping
         */
        public function addShoppingProduct(\Stanhome\ShoppingBundle\Entity\ShoppingProduct $shoppingProducts)
        {
            $this->shoppingProducts[] = $shoppingProducts;
            $shoppingProducts->setShopping($this);
     
            return $this;
        }
    Je n'ai pas de constructeur dans ShoppingProduct n'y de add étant donné qu'il dispose des relations en ManyToOne.

  20. #20
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    725
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 725
    Points : 1 050
    Points
    1 050
    Par défaut
    Bonjour,

    je croyais que avec le handleRequest(), symfony se chargeait automatiquement comme un grand garçon de rajouter l'objet Shopping créé dans le champ shopping de ShoppingProduct.
    Il n'y a pas de magie, comme écris dans la doc le form ajoute les ShoppingProduct à Shopping mais ne s'occupe pas de la relation inverse.
    http://symfony.com/fr/doc/current/co...llections.html section Doctrine: Relations de Cascade et sauvegarde du côté « Inverse »

    Tu as ajouté le traitement dans la méthode "addShoppingProduct" mais est-tu sur que cette méthode soit appelée?
    N'as tu pas une méthode "setShoppingProducts" dans ton entité "Shopping" ?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [2.x] [Form] Personnalisation des formulaires imbriqués
    Par FadeToBlack dans le forum Symfony
    Réponses: 10
    Dernier message: 20/03/2013, 17h55
  2. [2.x] [symfony 2] - comment forcer la regénération des formulaires
    Par altair8080 dans le forum Symfony
    Réponses: 1
    Dernier message: 24/04/2012, 11h16
  3. [1.x] [symfony 1.4.x][propel] Formulaires imbriqués
    Par Djillian dans le forum Symfony
    Réponses: 5
    Dernier message: 04/04/2011, 16h55
  4. Réponses: 4
    Dernier message: 03/12/2009, 13h39
  5. [1.x] formulaire imbriqués symfony version 1.1.6
    Par bellilo dans le forum Symfony
    Réponses: 2
    Dernier message: 30/03/2009, 02h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo