Symfony2的:成立多对多 - 数据库prevent复制数据库、prevent

2023-09-10 16:15:07 作者:演不完的人间戏一场ゞ

我工作的餐厅的网站上一回办公室。当我加一个菜,我可以通过两种方式添加成分。 在我的表单模板,我手动添加一个文本输入框。我申请这个领域的jQuery UI的自动完成的方法,使:

选择现有的配料(previsously加) 添加新的成分

然而,当我提交表单,每个成分都插入到数据库中(正常的行为,你会告诉我的)。 对于成分,不存在这是件好事,但我不希望再次插入已经插入成分。

后来我想过主义活动,如'prePersist()。但我不明白怎么办。

我想知道,如果你有任何想法的方式来做到这一点。

下面是我DishType的buildForm方式:

 < PHP
公共职能buildForm(FormBuilderInterface $建设者,数组$选项)
{
    $建设者
     - >添加(类,实体,阵列(类=>'PrototypeAdminBundle:DishCategory,
                                      财产=> '名称',
                                      '多'=>假 ))
     - >添加('标题','文字')
     - >添加(描述,文本区域)
     - >添加(价格,文本)
     - >添加('成分','收藏',阵列('类型'=>新建IngredientType()
                                             allow_add'=>真正,
                                             allow_delete'=>真正,
                                            ))

     - >添加('形象',将ImageType新(),数组('标签'=> FALSE));
}
 

和在我的控制器的方法,其中我处理的形式:

 < PHP
公共职能addDishAction()
{

    $菜=新菜();
    $形式= $这个 - >的CreateForm(新DishType,$碟);

    $请求= $这个 - >获得(请求);

    如果($请求 - >实现getMethod()=='POST'){
        $形式 - >绑定($请求);

        如果($形式 - >的isValid()){
            $ EM = $这个 - > getDoctrine() - > getManager();
            $的EM>坚持($碟);
            $的EM>的flush();

            返回$这 - >重定向($这 - > generateUrl('prototype_admin_get_dish',阵列('蛞蝓'=> $ dish-> getSlug())));
        }
    }

    返回$这个 - >渲染('PrototypeAdminBundle:管理员:addDish.html.twig,阵列(
        '形式'=> $形式 - > CreateView的()
        ));
}
 
TCGA数据库挖掘之CNV拷贝数变异分析生信视频课程

解决方案

我有同样的问题。我的实体是项目(菜你的情况)和标签(成分)。

我解决了它添加一个事件侦听器,如这里解释

 服务:
    my.doctrine.listener:
        类:尖端\ AdminBundle \事件监听\ UniqueIngredient
        标签:
             -  {名称:doctrine.event_listener,事件:preUpdate}
             -  {名称:doctrine.event_listener,事件:prePersist}
 

监听器触发两个prePersist(新添加的菜),以及现有的菜肴更新preUpdate。

如果该成分已经存在的code检查。如果存在该成分它用于和新的项被丢弃。

在code如下:

 < PHP

命名空间的Acme \ AdminBundle \事件监听器;

使用Doctrine \ ORM \事件\ LifecycleEventArgs;

使用尖端\ AdminBundle \实体\盘;
使用尖端\ AdminBundle \实体\成份;

类UniqueIngredient
{

    / **
     *这将被要求新建的实体
     * /
    公共职能prePersist(LifecycleEventArgs $参数)
    {

        $实体= $ args-> getEntity();

        //我们感兴趣的菜只
        如果($实体的instanceof菜){

            $的EntityManager = $ args-> getEntityManager();
            $成分= $实体 - > getIngredients();

            的foreach($成分为$关键=> $成分){

                //让我们来检查该成分的实存
                $结果= $ entityManager-> getRepository('尖端\ AdminBundle \实体\成分') - > findBy(阵列(名称=> $ ingredient->的getName()),阵列('身份证'=&GT ;ASC'));

                //如果成分存在使用现有的成分
                如果(计数($结果)大于0){

                    $成分[$关键] = $结果[0];

                }

            }

        }

    }

    / **
     *叫上存在的​​实体更新
     *
     *已经创造了新的成分和持久化(虽然没有刷新)
     *所以我们现在据此决定是否将它们添加到菜肴或删除重复的那些
     * /
    公共职能preUpdate(LifecycleEventArgs $参数)
    {

        $实体= $ args-> getEntity();

        //我们感兴趣的菜只
        如果($实体的instanceof菜){

            $的EntityManager = $ args-> getEntityManager();
            $成分= $实体 - > getIngredients();

            的foreach($成分为$成分){

                //让我们来检查该成分的实存
                //通过名称查找和排序ID保持老成分第一
                $结果= $ entityManager-> getRepository('尖端\ AdminBundle \实体\成分') - > findBy(阵列(名称=> $ ingredient->的getName()),阵列('身份证'=&GT ;ASC'));

                //如果存在成分至少两列将被返回
                //保持第一和丢弃所述第二
                如果(计数($结果)→1){

                    $ knownIngredient = $结果[0];
                    $实体 - > addIngredient($ knownIngredient);

                    //删除重复的成分
                    $ duplicatedIngredient = $结果[1];
                    $ entityManager->删除($ duplicatedIngredient);

                }其他{

                    //成分还不存在,加关系
                    $实体 - > addIngredient($成分);

                }

            }

        }

    }

}
 

注意:这似乎是工作,但我不是一个Symfony的/学说专家,所以考验你的code认真

希望这有助于!

pcruz

I'm working on a back office of a restaurant's website. When I add a dish, I can add ingredients in two ways. In my form template, I manually added a text input field. I applied on this field the autocomplete method of jQuery UI that allows:

Select existing ingredients (previsously added) Add new ingredients

However when I submit the form, each ingredients are inserted in the database (normal behavior you will tell me ). For the ingredients that do not exist it is good but I don't want to insert again the ingredients already inserted.

Then I thought about Doctrine events, like ' PrePersist(). But I don't see how to proceed.

I would like to know if you have any idea of ​​the way to do it.

Here is the buildForm method of my DishType :

<?php 
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
    ->add('category', 'entity', array('class' => 'PrototypeAdminBundle:DishCategory',
                                      'property' => 'name',
                                      'multiple' => false ))
    ->add('title', 'text')
    ->add('description', 'textarea')
    ->add('price', 'text')
    ->add('ingredients', 'collection', array('type'        => new IngredientType(),
                                             'allow_add'    => true,
                                             'allow_delete' => true,
                                            ))

    ->add('image', new ImageType(), array( 'label' => false ) );
}

and the method in my controller where I handle the form :

<?php
public function addDishAction()
{

    $dish = new Dish();
    $form = $this->createForm(new DishType, $dish);

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

    if ($request->getMethod() == 'POST') {
        $form->bind($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($dish);
            $em->flush();

            return $this->redirect($this->generateUrl('prototype_admin_get_dish', array('slug' => $dish->getSlug())));
        }
    }

    return $this->render('PrototypeAdminBundle:Admin:addDish.html.twig', array(
        'form' => $form->createView(),
        ));
}

解决方案

I was having the same problem. My entities were projects (dishes in your case) and tags (ingredients).

I solved it by adding an event listener, as explained here.

services:
    my.doctrine.listener:
        class: Acme\AdminBundle\EventListener\UniqueIngredient
        tags:
            - { name: doctrine.event_listener, event: preUpdate }
            - { name: doctrine.event_listener, event: prePersist }

The listener triggers both prePersist (for newly added dishes) and preUpdate for updates on existing dishes.

The code checks if the ingredient already exists. If the ingredient exists it is used and the new entry is discarded.

The code follows:

<?php

namespace Acme\AdminBundle\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;

use Acme\AdminBundle\Entity\Dish;
use Acme\AdminBundle\Entity\Ingredient;

class UniqueIngredient
{

    /**
     * This will be called on newly created entities
     */
    public function prePersist(LifecycleEventArgs $args)
    {

        $entity = $args->getEntity();

        // we're interested in Dishes only
        if ($entity instanceof Dish) {

            $entityManager = $args->getEntityManager();
            $ingredients = $entity->getIngredients();

            foreach($ingredients as $key => $ingredient){

                // let's check for existance of this ingredient
                $results = $entityManager->getRepository('Acme\AdminBundle\Entity\Ingredient')->findBy(array('name' => $ingredient->getName()), array('id' => 'ASC') );

                // if ingredient exists use the existing ingredient
                if (count($results) > 0){

                    $ingredients[$key] = $results[0];

                }

            }

        }

    }

    /**
     * Called on updates of existent entities
     *  
     * New ingredients were already created and persisted (although not flushed)
     * so we decide now wether to add them to Dishes or delete the duplicated ones
     */
    public function preUpdate(LifecycleEventArgs $args)
    {

        $entity = $args->getEntity();

        // we're interested in Dishes only
        if ($entity instanceof Dish) {

            $entityManager = $args->getEntityManager();
            $ingredients = $entity->getIngredients();

            foreach($ingredients as $ingredient){

                // let's check for existance of this ingredient
                // find by name and sort by id keep the older ingredient first
                $results = $entityManager->getRepository('Acme\AdminBundle\Entity\Ingredient')->findBy(array('name' => $ingredient->getName()), array('id' => 'ASC') );

                // if ingredient exists at least two rows will be returned
                // keep the first and discard the second
                if (count($results) > 1){

                    $knownIngredient = $results[0];
                    $entity->addIngredient($knownIngredient);

                    // remove the duplicated ingredient
                    $duplicatedIngredient = $results[1];
                    $entityManager->remove($duplicatedIngredient);

                }else{

                    // ingredient doesn't exist yet, add relation
                    $entity->addIngredient($ingredient);

                }

            }

        }

    }

}

NOTE: This seems to be working but I am not a Symfony / Doctrine expert so test your code carefully

Hope this helps!

pcruz