我有"角色"与"项目"相关联。 我不在乎角色名称是否重复,但我想确定的是,对于每个项目,角色名称都不能重复。
以下是我认为应该有效的方法:
<?php
// src/AppBundle/Entity/Role.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass="AppBundle\Entity\RoleRepository")
* @ORM\Table(name="roles")
* @UniqueEntity(fields={"name","project"}, message="Duplicated role for this project")
*/
class Role
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=100)
*/
protected $name;
/**
* @ORM\Column(type="text")
*/
protected $description;
...
other fields
...
/**
* @ORM\ManyToOne(targetEntity="Project")
*/
protected $project;
}
根据文档here,这正是我所需要的:
此必填选项是此字段的字段(或字段列表) 实体应该是唯一的。例如,如果您同时指定了电子邮件 并在一个UniqueEntity约束中命名字段,然后它会 强制组合值在唯一的位置(例如,两个用户可以 有相同的电子邮件,只要他们也没有相同的名称。
简单地忽略约束(我的意思是,如果我尝试为同一个项目设置相同的角色名称,它会存储重复的角色名称和projectID)。
我错过了什么?
编辑:在我使用&#34; php app / console doctrine:schema:update --force&#34;更新数据库之后我试图直接用SQL生成错误,但没有抛出任何异常。现在,我不知道这个&#34; UniqueEntity&#34;验证是在DB级别或它的Doctrine验证器上完成的。
EDIT2:我试图只有一个字段(&#34;名称&#34;)并且验证工作正常(当然只在该字段上)。 我还尝试对字段进行验证&#34; name&#34;和&#34;描述&#34;它的工作原理!!!所以基本上它不会验证要验证的字段是否是指向另一个表的ID。
无论如何,这是控制器:
/**
* @Route("/role/create/{projectID}", name="role_create")
*/
public function createRoleAction(Request $request, $projectID)
{
$prj = $this->getDoctrine()->getRepository('AppBundle:Project')->findOneById($projectID);
$role = new Role();
$form = $this->createForm(new RoleFormType(), $role);
$form->handleRequest($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$role->setProject($prj);
$em->persist($role);
$em->flush();
return $this->redirect($this->generateUrl('hr_manage', array('projectID' => $projectID)));
}
return $this->render('Role/createForm.html.twig', array('projectID' => $projectID, 'form' => $form->createView(),));
}
未执行验证,并且实体持久保存在DB上,使用&#34;项目&#34;列指向正确的项目。以下是2个相关领域的快照:
这是RoleFormType(相关字段的摘录):
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RoleFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder->add('name', 'text')
->add('description', 'text')
...lots of other fields, but "project" is not present as it's passed automatically from the controller
->add('save', 'submit', array('label' => 'Create'));
}
public function getName()
{
return 'role';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'AppBundle\Entity\Role',));
}
}
答案 0 :(得分:3)
问题是您实际上并未验证实体以检查唯一约束违规。当您调用$form->isValid()
时,它会调用Role
实体的验证程序,因为您将其作为表单的数据类传递。但是,由于project
在此之后才设置,因此project
字段不会进行验证。
当您致电$em->persist($role);
和$em->flush();
时,这只是告诉Doctrine将实体插入数据库。这2次调用不自行执行验证,因此将插入重复的 。
尝试在创建表单之前设置项目:
$role = new Role();
$role->setProject($prj);
$form = $this->createForm(new RoleFormType(), $role);
现在将在实体上设置项目,因此当调用$form->isValid()
时,Symfony验证器将检查唯一性。
如果这不起作用,您还希望将project
类型作为hidden
字段添加到表单中,以便将其传回,但是我不认为这是必要的。
我要说的另一件事是你肯定想在你的数据库本身添加唯一约束 - 这种方式即使你试图插入一个副本,数据库也会向你抛出异常而不允许它,无论如何你的代码。