Bonjour à tous,

Là vraiment je ne comprend pas pourquoi j'arrive pas à ajouter un lien d'une relation many to many à une entité. Surtout que je l'ai déjà fait pour une autre entité et ça avait bien fonctionné.

Là je veux ajouter un contact existant à une fiche (la création de contacts fonctionne bien et celui-ci est bien relié à la fiche de création)

A noter, j'ai commencé le site il ya plusieurs années, sous symfony 2.5, il est en prod actuellement, mais je n'avais pas eu le temps de faire la fonctionnalité permettant de lier un contact existant à une fiche (seule la création existe mais j'avais prévu de le faire d'où la liaison many to many) et je profite de la migration en symfony 3.2 pour ajouter cette fonctionnalité (je nettoierais les doublons quand ça fonctionnera)

Ce que je fais

Voici les 2 entités :

Contact

<?php

namespace Diff\eSiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * contact
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Diff\eSiteBundle\Entity\contactRepository")
 */
class contact
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="nom", type="string", length=100)
     */
    private $nom;

    /**
     * @var string
     *
     * @ORM\Column(name="prenom", type="string", length=100)
     */
    private $prenom;

    /**
     * @var string
     *
     * @ORM\Column(name="mail", type="string", length=100, nullable=true)
     */
    private $mail;

    /**
     * @var string
     *
     * @ORM\Column(name="tel", type="string", length=15)
     */
    private $tel;

     /**
     * @var string
     *
     * @ORM\Column(name="com", type="text", nullable=true)
     */
    private $com;

    /**
     * 
     * @ORM\ManyToOne(targetEntity="Diff\eSiteBundle\Entity\academie")
     * @ORM\JoinColumn(name="academie_id", nullable=false)
     */
    private $idaca;

    /**
     * @ORM\ManyToMany(targetEntity="Diff\eSiteBundle\Entity\AppliAca", inversedBy="contacts")
     * @ORM\JoinTable(name="responsable")
     */
    private $CntAppliaca;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set nom
     *
     * @param string $nom
     * @return contact
     */
    public function setNom($nom)
    {
        $this->nom = $nom;

        return $this;
    }

    /**
     * Get nom
     *
     * @return string 
     */
    public function getNom()
    {
        return $this->nom;
    }

    /**
     * Set prenom
     *
     * @param string $prenom
     * @return contact
     */
    public function setPrenom($prenom)
    {
        $this->prenom = $prenom;

        return $this;
    }

    /**
     * Get prenom
     *
     * @return string 
     */
    public function getPrenom()
    {
        return $this->prenom;
    }

    /**
     * Set mail
     *
     * @param string $mail
     * @return contact
     */
    public function setMail($mail)
    {
        $this->mail = $mail;

        return $this;
    }

    /**
     * Get mail
     *
     * @return string 
     */
    public function getMail()
    {
        return $this->mail;
    }

    /**
     * Set tel
     *
     * @param string $tel
     * @return contact
     */
    public function setTel($tel)
    {
        $this->tel = $tel;

        return $this;
    }

    /**
     * Get tel
     *
     * @return string 
     */
    public function getTel()
    {
        return $this->tel;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->CntAppliaca = new \Doctrine\Common\Collections\ArrayCollection();
        $this->idaca = new \Doctrine\Common\Collections\ArrayCollection();
     }

     /**
     * Set com
     *
     * @param string $com
     * @return contact
     */
    public function setCom($com)
    {
        $this->com = $com;

        return $this;
    }

    /**
     * Get com
     *
     * @return string 
     */
    public function getCom()
    {
        return $this->com;
    }

    /**
     * Set idaca
     *
     * @param \Diff\eSiteBundle\Entity\academie $idaca
     * @return contact
     */
    public function setIdaca(\Diff\eSiteBundle\Entity\academie $idaca)
    {
        $this->idaca = $idaca;

        return $this;
    }

    /**
     * Get idaca
     *
     * @return \Diff\eSiteBundle\Entity\academie 
     */
    public function getIdaca()
    {
        return $this->idaca;
    }

    /**
     * Add CntAppliaca
     *
     * @param \Diff\eSiteBundle\Entity\AppliAca $cntAppliaca
     * @return contact
     */
    public function addCntAppliaca(\Diff\eSiteBundle\Entity\AppliAca $cntAppliaca)
    {
        $this->CntAppliaca[] = $cntAppliaca;

        return $this;
    }

    /**
     * Remove CntAppliaca
     *
     * @param \Diff\eSiteBundle\Entity\AppliAca $cntAppliaca
     */
    public function removeCntAppliaca(\Diff\eSiteBundle\Entity\AppliAca $cntAppliaca)
    {
        $this->CntAppliaca->removeElement($cntAppliaca);
    }

    /**
     * Get CntAppliaca
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getCntAppliaca()
    {
        return $this->CntAppliaca;
    }
}

La fiche (pas entière car il y a beaucoup de relation avec d'autres entités)

<?php

namespace Diff\eSiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\ORM\Mapping\UniqueConstraint;

/**
 * AppliAca
 *
 * @ORM\Table(name="AppliAca",uniqueConstraints={@UniqueConstraint(name="fiche_unique", columns={"idAca_id", "idApp_id"})})
 * @ORM\Entity(repositoryClass="Diff\eSiteBundle\Entity\AppliAcaRepository")
 * @UniqueEntity(fields={"idAca", "idApp"})
 */
class AppliAca
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
    *
    * @ORM\ManyToOne(targetEntity="Diff\eSiteBundle\Entity\academie", cascade={"persist"}, 
    * inversedBy="fiches")
    * @ORM\JoinColumn(nullable=false)
    */
    private $idAca;

    /**
     * 
     * @ORM\ManyToOne(targetEntity="Diff\eSiteBundle\Entity\application", cascade={"persist"},
     *  inversedBy="fiches")
     *  @ORM\JoinColumn(nullable=false, referencedColumnName="id")
     */
    private $idApp;

    /**
     * @ORM\ManyToMany(targetEntity="Diff\eSiteBundle\Entity\contact", mappedBy="CntAppliaca")
     * @ORM\JoinTable(name="responsable")
     */
    private $contacts;   

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

     /**
     * Set idAca
     *
     * @param integer $idAca
     * @return AppliAca
     */
    public function setIdAca($idAca)
    {
        $this->idAca = $idAca;

        return $this;
    }

    /**
     * Get idAca
     *
     * @return integer 
     */
    public function getIdAca()
    {
        return $this->idAca;
    }

    /**
     * Set idApp
     *
     * @param integer $idApp
     * @return AppliAca
     */
    public function setIdApp($idApp)
    {
        $this->idApp = $idApp;

        return $this;
    }

    /**
     * Get idApp
     *
     * @return integer 
     */
    public function getIdApp()
    {
        return $this->idApp;
    }

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add contacts
     *
     * @param \Diff\eSiteBundle\Entity\contact $contacts
     * @return AppliAca
     */
    public function addContact(\Diff\eSiteBundle\Entity\contact $contacts)
    {
        $this->contacts[] = $contacts;

        return $this;
    }

    /**
     * Remove contacts
     *
     * @param \Diff\eSiteBundle\Entity\contact $contacts
     */
    public function removeContact(\Diff\eSiteBundle\Entity\contact $contacts)
    {
        $this->contacts->removeElement($contacts);
    }

    /**
     * Get contacts
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getContacts()
    {
        return $this->contacts;
    }

}

Dans le contrôller, sur la partie d'ajout de lien de contact voici ce que je fais

   /**
* @ParamConverter("domaine", options={"mapping": {"dom":
"id"}})
*/    
  public function creatcntAction(domaine $domaine, $num, Request $request)
  {
    $repository = $this->getDoctrine()->getManager(); 
    $fiche= $repository->getRepository('DiffeSiteBundle:AppliAca')->findOneById($num);

    //création du formulaire de la liste des contacts
    $listform = $this->createForm(liensCntType::class, $fiche);

  //$request = $this->get('request');

    if ($request->getMethod() == 'POST') 
    {
        $listform->handleRequest($request);

        if ($listform->isSubmitted() && $listform->isValid()) 
        {   
            $em = $this->getDoctrine()->getManager();
            $em->persist($fiche);
            $em->flush();
            return $this->redirect($this->generateUrl('diff_esite_fiche', array('dom'=> $domaine->getId(), 'num'=>$num)));
        } 
    } 

  return $this->render('DiffeSiteBundle:form:formnewcontact.html.twig',
        array(
        'listform' => $listform->createView(),
        'fiche'=>$fiche,
    ));      
  }

Pour construire mon formulaire, voici le fichier liensCntType.php

<?php
# Diff/eSiteBundle/Form/lienscntType.php

namespace Diff\eSiteBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;

use Diff\eSiteBundle\Entity\Academie;
use Diff\eSiteBundle\Entity\AppliAca;

class liensCntType extends AbstractType
{

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
public function buildForm(FormBuilderInterface $builder, array $options)
{

$aca = $builder->getData()->getIdAca();

$builder
        ->add('contacts', EntityType::class, array(
        'class' => 'DiffeSiteBundle:contact',
        'choice_label' => function ($allChoices, $currentChoiceKey)
{
//ceci pour avoir un affichage du type  Nom Prénom (numTel)
    return $allChoices->getNom() . " " . $allChoices->getPrenom() . " (" . $allChoices->getTel() .")";
},
        'multiple'  => true,
        'expanded' =>true,
        'query_builder' => function (EntityRepository $er) use ($aca){
        return $er->createQueryBuilder('c')
            ->where('c.idaca = :aca')
            ->setParameter('aca', $aca)
            ->orderBy('c.nom', 'ASC');
    },
))     
;
}
 /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Diff\eSiteBundle\Entity\AppliAca',
        ));
    }

public function getBlockPrefix()
{
return 'diff_esitebundle_appliaca';
}
}
?>

Et pour fini voici l'affichage de mon formulaire avec twig : formnewcontact.html.twig


    {{form_start(listform)}}
     <table class="table-bordered">
        <tr>
    {% for resp in listform.contacts %}
            <td> {{ form_row(resp) }}  </td>
    {% endfor %}
            </tr>
    </table>

    <br>
    <input type="submit" value="VALIDER" class="btn btn-primary" /> 
    <a href="{{ path('diff_esite_fiche', {'dom': app.request.attributes.get('dom'), 'num': app.request.attributes.get('num')} ) }}" class="btn btn-warning" >ANNULER</a>

 {{form_end(listform)}}

Après tout cela, j'affiche bien la liste des contacts disponibles et j'ai même une coche sur celles déjà liées à la fiche.

Ce que j'obtiens

Je n'ai pas de message d'erreur, je rentre bien dans le contrôle de isSubmitted et isValid (car j'ai fait un dump pour voir le contenu de listform)

Mais il m'est impossible de lier d'autre contact, lorsque je coche une case et que je valide le formulaire je suis redirigé sur la page d'affiche de la fiche mais rien n'est fait en base.

Je ne comprend pas ce qui cloche dans mon code.

Merci pour votre aide

4 réponses


Olorin
Auteur
Réponse acceptée

J'ai trouvé !!!!
Bon ça vous fait une belle jambe mais je suis heureux.

Comme je m'en doutais c'était tout con. J'avais déclaré la relation entre contact et AppliAca comme unidirectionnelle, donc la création de contact fonctionnait mais l'ajout de contact existant ne fonctionnait pas.

Il suffisait de déclarer la relation bi-directionnelle pour que ça marche correctement.

J'ai l'impression que tu récupères pas le repository

$em = $this->getDoctrine()->getManager();
    $rep  = $em->getRepository('Bundle:Repository');
            $rep->persist($fiche);
            $rep->flush();
Olorin
Auteur

Je ne comprend pas de quel repository tu parles, j'ai déjà récupéré celui de mon entité ici :
$fiche= $repository->getRepository('DiffeSiteBundle:AppliAca')->findOneById($num);

Je fais comme ça avec tous mes autres formulaires et c'est le seul qui ne fonctionne pas.

Olorin
Auteur

Dans le doute j'ai suivi ton conseil et séparé la récupération de l'entité manager, celle du repository et celle de ma fiche.

$em = $this->getDoctrine()->getManager(); 
$rep = $em->getRepository('DiffeSiteBundle:AppliAca');
$fiche= $rep->findOneById($num);

$listform = $this->createForm(liensCntType::class, $fiche);

if ($request->getMethod() == 'POST') 
    {
        if ($request->getMethod() == 'POST') 
    {
            $em->persist($fiche);
            $em->flush();
            return $this->redirect($this->generateUrl('diff_esite_fiche', array('dom'=> $domaine->getId(), 'num'=>$num)));
        } 
    } 

  return $this->render('DiffeSiteBundle:form:formnewcontact.html.twig',
        array(
        'listform' => $listform->createView(),
        'fiche'=>$fiche,
    ));      

Par contre persist et flush doivent être appelés par une entité manager et non un repository.
Mais bon toujours est-il que ça ne fonctionne toujours pas.

Je comprend vraiment pas ce qui ne va pas dans mon code, je fais la même chose que pour les autres formulaires et juste celui-ci refuse de mettre à jour la base.

J'ai fait un dump de la $fiche avant le flush et je retrouve bien les données ajoutées, pourquoi est-ce que ce n'est pas inséré en base après le flush ?

Peut-être qu'il y a un soucis avec l'entité à l'origine ? mais je ne vois pas...