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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    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
    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 extrêmement actif
    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
    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 confirmé
    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
    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 extrêmement actif
    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
    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 confirmé
    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
    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 extrêmement actif
    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
    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) ???

+ Répondre à la discussion
Cette discussion est résolue.

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