使用联接表[Symfony2]验证一对多单向的UniqueEntity


Validate UniqueEntity for One-To-Many, Unidirectional with Join Table [Symfony2]

我有两个映射的实体

盒式

class Box{
    //[...]
    /**
     * @ORM'ManyToMany(targetEntity="Candy", cascade={"remove"})
     * @ORM'OrderBy({"power" = "DESC"})
     * @ORM'JoinTable(name="box_candies",
     *      joinColumns={@ORM'JoinColumn(name="box_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM'JoinColumn(name="candy_id", referencedColumnName="id", unique=true)}
     *      )
     */
    private $candies;
}

和糖果

class Candy
{
    /**
     * @var integer
     *
     * @ORM'Column(name="id", type="integer")
     * @ORM'Id
     * @ORM'GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM'Column(name="name", type="string", length=255)
     */
    private $name;
    //[...]
}

正如您所看到的,这是一对多、单向的联接表关联。盒子可以"储存"糖果,但糖果对盒子一无所知(在哪里)。

现在我有了一个页面,我可以在那里制作糖果,并且有表格和标准isValid()以及之后的内容:

$box->addCandy($candy);
$entity_manager->persist($candy);
$entity_manager->persist($box);
$entity_manager->flush();

现在,我的问题在哪里

我希望Box只能存储独特的糖果(通过名称),这意味着Box可以存储名称为"Choco"answers"Orange"的糖果对象,但不能名为"Mayonnaise"answers"Mayonna ise"

制作糖果时,我无法使用UniqueEntity约束进行验证,因为糖果不知道盒子的情况。我考虑过Box的Callback验证器或创建自己的Constraint,但我认为最好问一下:

我该怎么做

答案很晚,但它可能会对某人有所帮助,所以这就是我实现的解决方案:

在我的情况下,我只能通过表单在一个地方创建Candy,所以最后我决定在我的控制器/服务中为该情况创建额外的特殊验证。

简单地说,我用自己的方式对名称进行了代码检查,当名称无效时,只形成trow Error以防止创建。我想强调的是,这是一个有点脏的解决方案,而且它是不可扩展的,因为如果你在其他地方创建Candy,你必须记住始终将其添加到正确的位置。

    // special unique name validation
    $candy_name = $form->get('name')->getData();
    if($candy_name){
        $found_candy = $box->getCandyByName($candy_name);
        if($found_candy){
            $error = new FormError( $this->get('translator')->trans("candy.name.exist", array(), "validators") );
            $form->get('name')->addError($error);
        }
    }

无论如何,它是有效的,但根据您的情况,回调可能是更好的解决方案,甚至是简单的UniqueEntity约束。