将自定义参数传递给Symfony2中的自定义ValidationConstraint

Phe*_*hen 20 php validation symfony

我正在Symfony2中创建一个表单.表单只包含一个book字段,允许用户在Books实体列表中进行选择.我需要检查所选择的Book属于Author我控制器中的.

public class MyFormType extends AbstractType
{
    protected $author;

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

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('book', 'entity', array('class' => 'AcmeDemoBundle:Book', 'field' => 'title');
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

我想在提交表单后检查所选内容Book是否由$author我的控制器编写:

public class MyController
{
    public function doStuffAction() {
        $author = ...;
        $form = $this->createForm(new MyFormType($author));
        $form->bind($this->getRequest());

        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我找不到任何办法.我尝试按照Cookbook中的说明创建自定义验证器约束,但是虽然我可以通过EntityManager将验证器定义为服务来传递as参数,但我无法将$author控制器传递给验证器约束.

class HasValidAuthorConstraintValidator extends ConstraintValidator
{
    private $entityManager;

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

    public function validate($value, Constraint $constraint) {
        $book = $this->entityManager->getRepository('book')->findOneById($value);
        $author = ...; // That's the data I'm missing

        if(!$book->belongsTo($author))
        {
            $this->context->addViolation(...);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案可能正是我正在寻找的解决方案,但我的表单并没有绑定到实体,并不是意味着(我从getData()方法中获取数据).

我的问题有解决方案吗?这必须是一个常见的案例,但我真的不知道如何解决它.

Phe*_*hen 30

在塞拉德的帮助下,我终于想通了.注入需要从访问自定义参数ConstraintValidator::validate()的方法,你需要将它们传递作为选项Constraint.

public class HasValidAuthorConstraint extends Constraint
{
    protected $author;

    public function __construct($options)
    {
        if($options['author'] and $options['author'] instanceof Author)
        {
            $this->author = $options['author'];
        }
        else
        {
            throw new MissingOptionException("...");
        }
    }

    public function getAuthor()
    {
        return $this->author;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且,在ConstraintValidator中:

class HasValidAuthorConstraintValidator extends ConstraintValidator
{
    private $entityManager;

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

    public function validate($value, Constraint $constraint) {
        $book = $this->entityManager->getRepository('book')->findOneById($value);
        $author = $this->constraint->getAuthor();

        if(!$book->isAuthor($author))
        {
            $this->context->addViolation(...);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后但同样重要的是,您必须将参数传递给Validator:

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('book', 'entity', array(
        'class' => 'AcmeDemoBundle:Book',
        'field' => 'title',
        'constraints' => array(
            new HasValidAuthorConstraint(array(
                'author' => $this->author
            ))
        )
    ));
}
Run Code Online (Sandbox Code Playgroud)

  • 您应该将 $author 属性定义为 public,以便可以在构造函数中调用 `parent::__construct($options);`。 (2认同)