我正在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');
}
// ...
}
我想在提交表单后检查所选的Book
是否由我的控制器中的$author
写入:
public class MyController
{
public function doStuffAction() {
$author = ...;
$form = $this->createForm(new MyFormType($author));
$form->bind($this->getRequest());
// ...
}
}
不幸的是,我找不到任何办法。我尝试按照The Cookbook中的说明创建自定义验证器约束,但是虽然我可以通过将验证器定义为服务来传递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(...);
}
}
}
This solution可能正是我正在寻找的那个,但我的表单并没有绑定到实体,并不是意图(我从getData()
方法获取数据)
我的问题有解决方案吗?这必须是一个常见的案例,但我真的不知道如何解决它。
答案 0 :(得分:29)
在塞拉德的帮助下,我终于明白了。要注入需要从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(...);
}
}
}
最后但并非最不重要的是,您必须将参数传递给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
))
)
));
}
答案 1 :(得分:3)
首先在约束中添加setAuthor方法,然后调整validate方法。那么诀窍是确定调用它的最佳位置。
目前尚不清楚您如何将验证器绑定到您的图书上。您使用validation.yml或在表单内部执行某些操作吗?
答案 2 :(得分:1)
好吧,我不熟悉Form / Validation组件,但您可以使用Hidden field作者的名称/ ID,并检查它是否相同:
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');
->add('author_name', 'hidden', array(
'data' => $this->author->getId(),
))
;
}
// ...
}
答案 3 :(得分:0)
谢谢@JasonRoman,您的解决方案在Symfony 3.4中对我来说非常有效。
使用时,我的验证程序出现错误:
$author = $this->constraint->getAuthor();
但是当我改用它时它起作用了:
$author = $constraint->getAuthor();
答案 4 :(得分:-1)
使用Symfony Framework 版本2.1 ,接受的答案对我不起作用。这就是我解决它的方法。
class CustomConstraint extends Constraint
{
public $dependency;
public $message = 'The error message.';
}
class CustomConstraintValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!$constraint->dependency->allows($value)) {
$this->context->addViolation($constraint->message);
}
}
}
class CustomFormType extends AbstractType
{
private $dependency;
public function __construct(Dependency $dependency)
{
$this->dependency = $dependency;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field', 'type', array(
'constraints' => array(
new CustomConstraint(array('dependency' => $this->dependency))
)
));
}
}