SYMFONY custom CONSTRAINT - >将变量传递给自定义CONSTRAINT /如何将CONSTRAINT绑定到表单字段可以在注释中覆盖约束

时间:2016-05-27 09:06:24

标签: forms annotations symfony-forms symfony

我的目标:我在SYMFONY中构建了一个自定义约束,我需要将一个变量传递给该约束。

上下文:约束检查数据库中的值是否唯一,如果不是,则会引发CONSTRAINT警报。当FORM用于在DB 中创建新元组时,这可以正常工作,但如果它是一个编辑,它会引发一个异常,应该通过检查已存在的值来绕过该异常,对于正在编辑的元组Id存在

因此我需要将正在编辑的元组的Id传递给我的约束检查。

首先,我在我的实体中实现了自定义约束:

class MyEntity{

    /**
    * @MyBundleAssert\CheckValueAlreadyInDB(
    *     message = "already_exists_in_db",
    *     fieldToSearch = "my_value",
    *     tableToSearch = "my_table"
    *)
    */
    private myValue;

} 

正如我所看到的,我没有找到一种方法来实现一种使用ANNOTATION约束传递VARIABLE的方法。通过搜索,我知道我可以通过使用我的自定义约束类的__construct()来做到这一点:

/**
 * @Annotation
 */
class CheckValueAlreadyInDB extends Constraint{
public $message;
public $fieldToSearch;
public $tableToSearch;
public $idToCheck;
public $idToCheckFieldName;

public function __construct($options){
    if(count($options)>0){
        $this->idToCheck = $options['idToCheck'];
        $this->idToCheckFieldName = $options['idToCheckFieldName'];
        $this->fieldToSearch = $options['fieldToSearch'];
        $this->tableToSearch = $options['tableToSearch'];
        $this->message = $options['message'];
    }
}

public function validatedBy()
{
    return 'validator_check_value_already_in_db';
}
}

并且,与之链接的ConstraintValidator扩展类:

class CheckValueAlreadyInDBValidator extends ConstraintValidator
{
    private $con;

    public function __construct($con){
        $this->con = $con;
    }

    public function validate($value, Constraint $constraint)
    {
        ////My stuff to get a record from the DB////
        $sel = new PdoSelect($this->con);
        $search = $sel->returnRecordsInTableForSpecificKey([$constraint->fieldToSearch],[$value],  $constraint->tableToSearch,false);
       //////////////////////////////////////////////

        $sameId = false;
        if($constraint->idToCheck!==null){
            $idToCheckInRetrieveRecord = $search->{$constraint->idToCheckFieldName};            
            $sameId = ($idToCheckInRetrieveRecord==$constraint->idToCheck)?true:false;
        }

        if($search!=null&&!$sameId){
            $this->context->buildViolation($constraint->message)
                ->setParameter('%string%', $value)
                ->addViolation();
        }
    }
}

服务:

validator.unique.check_value_already_in_db:
    class: MyBundle\Form\CustomConstraints\CheckValueAlreadyInDBValidator
    arguments: ['@doctrine.dbal.default_connection']
    tags:
        - { name: validator.constraint_validator, alias: validator_check_value_already_in_db }

我是关于myValue的字段的FORM(AbstractType扩展类),我确实编辑了constraints属性。

class MyEntityType extends AbstractType {     
public function buildForm(FormBuilderInterface $builder, array $options)
      {

    ....
        $builder->add('myValue',****Type::class,array(
          'constraints' => array(
              new CheckValueAlreadyInDB(array(
                'idToCheck'=>$options['data']->getId(),
                'idToCheckFieldName'=>'id',
                'fieldToSearch'=>'my_value',
                'tableToSearch'=>'my_table',
                'message' => "value_already_exists_in_db"))
            )
          ));

    ...
    }
}

我认为buildForm()中定义的CONSTRAINT会覆盖MyEntity类的* @MyBundleAssert\CheckValueAlreadyInDB(..)中定义的那个(这应该是默认行为)。但它没有! 我必须删除MyEntity上方的注释,以使约束按buildForm()中的定义工作。

有没有人知道是否有一个设置可以允许在buildForm()中覆盖一个约束覆盖MyEntity中作为ANNOTATION存在的约束,但是仍然让MyEntity中的字段上方的ANNOTATION成为默认行为?或者有没有办法将VARIABLE传递给ANNOTATIONS?

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。

我的错误是尝试在类MyEntityType中使用约束扩展AbstractType:

 $builder->add('myValue',****Type::class,array(
  'constraints' => array(
      new CheckValueAlreadyInDB(array(
        'idToCheck'=>$options['data']->getId(),
        'idToCheckFieldName'=>'id',
        'fieldToSearch'=>'my_value',
        'tableToSearch'=>'my_table',
        'message' => "value_already_exists_in_db"))
    )
  ));

不要在这里使用

请查看文档中的class-constraint-validator部分。

在实体的类上方实现ConstraintValidator扩展类,验证者必须执行其检查,而不是在Entity类的一个属性之上。这样,您就可以访问实体的其他属性,并将其用作ConstraintValidator扩展类中的条件。