Adr*_*n G 7 many-to-many duplicates symfony
我正在一家餐馆网站的后台工作.当我添加一道菜时,我可以通过两种方式添加成分.
在我的表单模板中,我手动添加了一个文本输入字段.我在这个字段上应用了jQuery UI的自动完成方法,它允许:
但是,当我提交表格时,每个成分都会插入数据库中(您将告诉我的正常行为).对于不存在的成分,它是好的,但我不想再插入已插入的成分.
然后我想到了Doctrine事件,比如prePersist().但我不知道如何继续.我想知道你是否知道如何做到这一点.
这是buildForm我的方法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 ) );
}
Run Code Online (Sandbox Code Playgroud)
以及我处理表单的控制器中的方法:
<?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(),
));
}
Run Code Online (Sandbox Code Playgroud)
小智 8
我遇到了同样的问题.我的实体是项目(在你的情况下的菜)和标签(成分).
我解决了它添加一个事件侦听器,如解释在这里.
services:
my.doctrine.listener:
class: Acme\AdminBundle\EventListener\UniqueIngredient
tags:
- { name: doctrine.event_listener, event: preUpdate }
- { name: doctrine.event_listener, event: prePersist }
Run Code Online (Sandbox Code Playgroud)
听众触发prePersist(用于新添加的菜肴)和preUpdate以获取现有菜肴的更新.
代码检查成分是否已存在.如果成分存在,则使用它并丢弃新条目.
代码如下:
<?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);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:这似乎有效,但我不是Symfony/Doctrine专家,所以请仔细测试您的代码
希望这可以帮助!
pcruz
| 归档时间: |
|
| 查看次数: |
3033 次 |
| 最近记录: |