我在一家餐馆网站的后台工作。当我添加菜时,我可以通过两种方式添加成分。
在我的表单模板中,我手动添加了一个文本输入字段。我在这个字段上应用了jQuery UI的自动完成方法,允许:
然而,当我提交表格时,每个成分都会插入数据库中(您将告诉我的正常行为)。 对于不存在的成分,这是好的,但我不想再插入已插入的成分。
然后我想到了 Doctrine事件,就像prePersist()
一样。但我不知道如何继续。我想知道你是否知道如何做到这一点。
以下是buildForm
的{{1}}方法:
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 ) );
}
答案 0 :(得分:8)
我遇到了同样的问题。我的实体是项目(在你的情况下的菜肴)和标签(成分)。
我通过添加事件监听器来解决它,如here所述。
services:
my.doctrine.listener:
class: Acme\AdminBundle\EventListener\UniqueIngredient
tags:
- { name: doctrine.event_listener, event: preUpdate }
- { name: doctrine.event_listener, event: prePersist }
听众会触发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);
}
}
}
}
}
注意:这似乎有效,但我不是Symfony / Doctrine专家,因此请仔细测试您的代码
希望这有帮助!
pcruz
答案 1 :(得分:0)
由于这篇文章是2岁,我不知道这里是否还需要帮助..无论如何..
您应该在Dish实体中放置addIngredient函数,此函数会检查当前成分集合中是否存在Ingredient对象。
addIngredient(Ingredient $ingredient){
if (!$this->ingredients->contains($ingredient)) {
$this->ingredients[] = $ingredient;
}
}
希望它仍然可以帮助你。