Bonjour,

J'utilise Symfony 3.4.7 .
Je travaille avec trois entités,articles, catégories, articles_categories qui fait le lien entre un article et une catégorie.
Pour gérer un article et ses relations articles_catégories, j'utilise la classe CollectionType que j'ajoute dans le formulaire ArticlesType.
Dans mon affichage je gère l'ajout d'une relation et sa suppression.
Voici le code de mon entité articles :

/**
 * Articles
 *
 * @ORM\Table(name="articles")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ArticlesRepository")
 * @UniqueEntity("codeArticle", message="Déjà utilisé")
 */
class Articles
{

    public function __construct()
    {
        $this->articlesCategories = new ArrayCollection();
    }

    /**
     * @var string
     *
     * @ORM\Column(name="code_article", type="string", length=10)
     * @ORM\Id
     */
    private $codeArticle;

    //... autres variables

    /**
     * @var ArticlesCategories
     *
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\ArticlesCategories", mappedBy="codeArticle", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    private $articlesCategories;

    // autres getters et setters 

    /**
     * Add articlesCategorie
     *
     * @param ArticlesCategories $articleCategorie
     *
     * @return Articles
     */
    public function addArticlesCategorie(ArticlesCategories $articleCategorie){
        $this->articlesCategories[] = $articleCategorie;
        $articleCategorie->setCodeArticle($this);

        return $this;
    }

    /**
     * remove articlesCategorie
     *
     * @param ArticlesCategories $articlesCategorie
     */
    public function removeArticlesCategorie(ArticlesCategories $articlesCategorie){
        $this->articlesCategories->removeElement($articlesCategorie);
    }

    public function setArticlesCategories($articlesCategories){
        $this->articlesCategories = $articlesCategories;
        return $this;
    }

    /**
     * Get articlesCategories
     *
     * @return Collection
     */
    public function getArticlesCategories(){
        return $this->articlesCategories;
    }
 }

Voici le code de mon entité articlesCatégories :

/**
 * ArticlesCategories
 *
 * @ORM\Table(name="articles_categories", uniqueConstraints={@ORM\UniqueConstraint(name="unique_codeArticle_codeCategorie", columns={"code_article_id", "code_categorie_id"})})
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ArticlesCategoriesRepository")
 * @UniqueEntity(fields={"codeArticle", "codeCategorie"}, message="Cette relation est déjà enregistré")
 */
class ArticlesCategories
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Articles", inversedBy="articlesCategories", cascade={"remove"})
     * @ORM\JoinColumn(referencedColumnName="code_article", nullable=false)
     */
    private $codeArticle;

    /**
     * @var string
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Categories", cascade={"remove"})
     * @ORM\JoinColumn(referencedColumnName="reference", nullable=false)
     */
    private $codeCategorie;

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

    //... getters et setters
 }

Voici le code de mon formuaire ArticlesType.php :

class ArticlesType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('codeArticle')
                //...autres attributs
                ->add('articlesCategories', CollectionType::class, array(
                    'entry_type' => ArticlesCategoriesType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'prototype' => true,
                    'label' => 'categories',
                    'attr' => array('class' => 'collection-articlesCategories'),
                    'auto_initialize' => true,
                    'by_reference' => false
                ));
        }
     }

Voici l'action que j'appelle quand je veux éditer un article :

class ArticlesController extends Controller
{
/**
     * Displays a form to edit an existing article entity.
     *
     * @Route("/edit/{codeArticle}", name="articles_edit", defaults={"codeArticle" = null} )
     * @Method({"GET", "POST"})
     */
    public function editAction(Request $request, Articles $article = null)
    {
        if($article != null){
            /*$em = $this->getDoctrine()->getManager();
            $article = $em->getRepository('AppBundle:Articles')->find($id_article);*/
            $deleteForm = $this->createDeleteForm($article);
            $editForm = $this->createForm('AppBundle\Form\ArticlesType', $article);
            $editForm->handleRequest($request);

            if ($editForm->isSubmitted() && $editForm->isValid()) {
                // récupère tous les articles même ceux qui viennent d'être ajouter par la fonction JS add
                $articlesCategories = $article->getArticlesCategories();
                dump($articlesCategories);
                foreach($articlesCategories as $ac){
                    // si l'article est null
                    if($ac->getCodeArticle() == null){
                        // on attribue à la relation articleCategorie l'article que l'on modifi
                        $ac->setCodeArticle($article);
                    }

                }
                $this->getDoctrine()->getManager()->flush();
            }

            return $this->render('articles/edit.html.twig', array(
                'article' => $article,
                'edit_form' => $editForm->createView(),
                'delete_form' => $deleteForm->createView(),
            ));
        }
        else{
            return $this->forward('AppBundle:articles:new', [
                    'message' => 'Pour éditer un article il faut d\'abord l\'afficher.'
                ]
            );
        }
    }
  }

L'affichage se fait sur une vue twig. Et j'utilise jquery pour ajouter et enlever du formulaire une relation articlesCategories.

Le problème que je rencontre c'est, lorsque j'ajoute une relation et que je clique sur "Editer", je peux constater que dans ma base de donées il y a bien une relation qui a été créée. Cependant lorsque je supprime une relation et que je clique sur "Editer", je constate que la suppression de mon entité ne s'est pas réalisée dans ma base de données.
Je n'arrive pas à voir où est mon erreur, ou si cette réaction est normale.

J'espère avoir été assez claire, Je vous remercie de votre future aide !

3 réponses


Sgothan
Auteur
Réponse acceptée

Bonjour à tous,

Toujours en testant pour chercher solution à mon problème, j'ai modifié mon fichier ArticlesType.php.

J'ai enlevé dans celui-ci l'option 'by_reference' qui est rattaché à la collection articlesCategories.

class ArticlesType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('codeArticle')
                ->add('description')
                ->add('ecotaxe')
                ->add('qteMaxCde')
                ->add('publication')
                ->add('designation')
                ->add('taxonomie')
                ->add('referenceStock')
                ->add('articleRegroupement')
                ->add('articleAssocie1')
                ->add('articleAssocie2')
                ->add('articleAssocie3')
                ->add('seuilDegressif')
                ->add('tauxDegressif')
                ->add('articlesCategories', CollectionType::class, array(
                    'entry_type' => ArticlesCategoriesType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'prototype' => true,
                    'label' => 'categories',
                    'attr' => array('class' => 'collection-articlesCategories'),
                    'auto_initialize' => true,
// MODIFICATION que j'ai apportée
                    //'by_reference' => false
                ));
        }
// etc

Et donc en testant à nouveau sur mon site. Cette fois-ci quand je supprime une relation ArticlesCategories, elle est bien supprimée en BDD.
Cependant le fait d'avoir enlever 'by_reference' ma généré un autre soucis : Lorsque j'ajoute une nouvelle relation articlesCategories, j'ai cette excpetion : An exception occurred while executing 'INSERT INTO articles_categories (critere_rech_1, critere_rech_2, critere_rech_3, critere_rech_4, code_article_id, code_categorie_id) VALUES (?, ?, ?, ?, ?, ?)' with params [null, null, null, null, null, "A0016"]: SQLSTATE[23000]: Integrity constraint violation: 1048 Le champ 'code_article_id' ne peut être vide (null)

Donc visblement ma fonction addArticlesCategorie qui se trouve dans Articles.php, n'est plus appelée.

/**
     * Add articlesCategorie
     *
     * @param ArticlesCategories $articleCategorie
     *
     * @return Articles
     */
    public function addArticlesCategorie(ArticlesCategories $articleCategorie){
        $articleCategorie->setCodeArticle($this);
        $this->articlesCategories[] = $articleCategorie;
        return $this;
    }

Ne sachant pas d'où ça vient j'ai trouvé une solution parallèle, par contre ça n'est pas propre. J'ai ajouté dans editAction de mon controlleur ce morceau de code :

editAction(..){
if ($editForm->isSubmitted() && $editForm->isValid()) {
           $article->getArticlesCategories();
                foreach ($articlesCategories as $ac){
                    if($ac->getCodeArticle() == null){
                        $ac->setCodeArticle($article);
                    }
                }
// etc
}

Pour chaque relations articleCategories de la collection de l'article sélectionné, je modifie le codeArticle de cette relation en lui donnant le code de l'article en cour.

Merci pour l'attention que vous avez apporté à mon post.

Tu dois utiliser la méthode remove($OBJECT)

Sgothan
Auteur

Merci pour ta réponse,
Cette méthode je peux l'utiliser uniquement de le controlleur, non ? Parce que ici le soucis, si dans ma fonction editAction de mon controleur je voudrais l'utiliser, il faudrait que je récupère l'instance de la relation articlesCatégories à supprimer. Alors qu'ici c'est une instance d'un Articles que j'obtiens. Il faudrait que je sache quel élément de ma catégorie a été enlevé dans ma collection. Cependant je ne le sais pas.
Ou alors il faudrait que je puisse utiliser cette fonction dans mon entité Articles à la fonction removeArticlesCategorie, mais je ne sais pas si c'est possible. J'ai essayé d'écrire $this->remove($articlesCategorie) mais ça ne fonctionne pas.

public function removeArticlesCategorie(ArticlesCategories $articlesCategorie){
        $this->articlesCategories->removeElement($articlesCategorie);
        $this->remove($articlesCategorie);
    }

Il y-t-il une solution pour supprimer une entité dans la fonction d'une entité ?