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

2022-08-30 19:09:23

我正在Symfony2中创建一个表单。表单仅包含一个字段,允许用户在实体列表之间进行选择。我需要检查所选内容是否属于我在控制器中的某个。bookBooksBookAuthor

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');
    }

    // ...
}

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

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

        // ...
    }
}

不幸的是,我找不到任何方法来做到这一点。我尝试创建自定义验证程序约束,如说明书中所述,但是虽然我可以通过将验证程序定义为服务来传递 as 参数,但我无法将 从控制器传递到验证程序约束。EntityManager$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(...);
        }
    }
}

此解决方案可能正是我正在寻找的解决方案,但我的窗体未绑定到实体,也不打算绑定到实体(我从该方法获取数据)。getData()

我的问题有解决方案吗?这一定是一个常见的情况,但我真的不知道如何解决它。


答案 1

在Cerad的帮助下,我终于想通了。要注入需要从方法访问的自定义参数,需要将它们作为选项传递到 .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;
    }
}

而且,在 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(...);
        }
    }
}

最后但并非最不重要的一点是,您必须将参数传递给验证器:

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
            ))
        )
    ));
}

答案 2

首先将 setAuthor 方法添加到约束中,然后调整验证方法。诀窍是确定调用它的最佳位置。

目前尚不清楚您如何将验证器绑定到您的图书。您是在使用 validation.yml 还是在表单中执行某些操作?


推荐