如何验证symfony2实体集合中的唯一实体 [英] How to validate unique entities in an entity collection in symfony2

查看:20
本文介绍了如何验证symfony2实体集合中的唯一实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实体与另一个实体具有 OneToMany 关系,当我保留父实体时,我想确保子实体不包含重复项.

I have an entity with a OneToMany relation to another entity, when I persist the parent entity I want to ensure the children contain no duplicates.

这是我一直在使用的类,discounts 集合不应包含给定客户的两个同名产品.

Here's the classes I have been using, the discounts collection should not contain two products with the same name for a given client.

我有一个包含一系列折扣的客户实体:

I have a Client entity with a collection of discounts:

/**
 * @ORM\Entity
 */
class Client {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=128, nullable="true")
     */
    protected $name;

    /**
     * @ORM\OneToMany(targetEntity="Discount", mappedBy="client", cascade={"persist"}, orphanRemoval="true")
     */
    protected $discounts;

}

/**
 * @ORM\Entity
 * @UniqueEntity(fields={"product", "client"}, message="You can't create two discounts for the same product")
 */
    class Discount {
        /**
         * @ORM\Id
         * @ORM\Column(type="string", length=128, nullable="true")
         */
        protected $product;

        /**
         * @ORM\Id
         * @ORM\ManyToOne(targetEntity="Client", inversedBy="discounts")
         * @ORM\JoinColumn(name="client_id", referencedColumnName="id")
         */
        protected $client;

        /**
         * @ORM\Column(type="decimal", scale=2)
         */
        protected $percent;
    }

我尝试将 UniqueEntity 用于 Discount 类,如您所见,问题是验证器似乎只检查数据库上加载的内容(这是空的),所以当实体被持久化时,我得到一个SQLSTATE[23000]:完整性约束违规".

I tried using UniqueEntity for the Discount class as you can see, the problem is that it seems the validator only checks what's loaded on the database (which is empty), so when the entities are persisted I get a "SQLSTATE[23000]: Integrity constraint violation".

我检查了 Collection 约束购买它似乎只能处理字段的集合,而不是实体.

I have checked the Collection constraint buy it seems to handle only collections of fields, not entities.

还有 All 验证器,它允许您定义约束应用于每个实体,而不应用于整个集合.

There's also the All validator, which lets you define constraints to be applied for each entity, but not to the collection as a whole.

在持久化到数据库之前,我需要知道是否有实体集合约束作为一个整体,而不是写一个自定义验证器 或编写回调a> 每次验证器.

I need to know if there are entity collection constraints as a whole before persisting to the database, other than writing a custom validator or writing a Callback validator each time.

推荐答案

我为此创建了一个自定义约束/验证器.

I've created a custom constraint/validator for this.

它使用All"断言验证表单集合,并接受一个可选参数:用于检查实体相等性的属性的属性路径.

It validates a form collection using the "All" assertion, and takes an optional parameter : the property path of the property to check the entity equality.

(它适用于 Symfony 2.1,要使其适应 Symfony 2.0,请检查答案的结尾):

有关创建自定义验证约束的更多信息,请查看The Cookbook

For more information on creating custom validation constraints, check The Cookbook

约束:

#src/Acme/DemoBundle/Validator/constraint/UniqueInCollection.php
<?php

namespace Acme\DemoBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;

/**
* @Annotation
*/
class UniqueInCollection extends Constraint
{
    public $message = 'The error message (with %parameters%)';
    // The property path used to check wether objects are equal
    // If none is specified, it will check that objects are equal
    public $propertyPath = null;
}

和验证器:

#src/Acme/DemoBundle/Validator/constraint/UniqueInCollectionValidator.php
<?php

namespace Acme\DemoBundle\Validator\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Form\Util\PropertyPath;

class UniqueInCollectionValidator extends ConstraintValidator
{

    // We keep an array with the previously checked values of the collection
    private $collectionValues = array();

    // validate is new in Symfony 2.1, in Symfony 2.0 use "isValid" (see below)
    public function validate($value, Constraint $constraint)
    {
        // Apply the property path if specified
        if($constraint->propertyPath){
            $propertyPath = new PropertyPath($constraint->propertyPath);
            $value = $propertyPath->getValue($value);
        }

        // Check that the value is not in the array
        if(in_array($value, $this->collectionValues))
            $this->context->addViolation($constraint->message, array());

        // Add the value in the array for next items validation
        $this->collectionValues[] = $value;
    }
}

在你的情况下,你会像这样使用它:

In your case, you would use it like this :

use Acme\DemoBundle\Validator\Constraints as AcmeAssert;

// ...

/**
 * @ORM\OneToMany(targetEntity="Discount", mappedBy="client", cascade={"persist"}, orphanRemoval="true")
 * @Assert\All(constraints={
 *     @AcmeAssert\UniqueInCollection(propertyPath ="product")
 * })
 */

对于 Symfony 2.0,将 validate 函数更改为:

For Symfony 2.0, change the validate function by :

public function isValid($value, Constraint $constraint)
{
        $valid = true;

        if($constraint->propertyPath){
            $propertyPath = new PropertyPath($constraint->propertyPath);
            $value = $propertyPath->getValue($value);
        }

        if(in_array($value, $this->collectionValues)){
            $valid = false;
            $this->setMessage($constraint->message, array('%string%' => $value));
        }

        $this->collectionValues[] = $value;

        return $valid

}

这篇关于如何验证symfony2实体集合中的唯一实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆