2013-03-25 154 views
16

我在Symfony2中创建表单。该表格仅包含一个book字段,该字段允许用户在Books实体列表中进行选择。我需要检查所选的Book是否属于我的控制器中的Author将自定义参数传递给Symfony2中的自定义ValidationConstraint

​​

我要检查,提交表单后,所选择的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()方法中的数据)。

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

回答

22

我终于在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 
      )) 
     ) 
    )); 
} 
+0

请注意,在Symfony 2.7中,自定义参数不是直接在$ options数组中找到的,而是在“值”键内。所以对于这个例子,你会从$ options ['value'] ['author']得到作者。如果您使用注释声明断言,您可以编写如下内容: @CustomAssert \ CustomDateTime({“dateFormat”:Enum :: DATE_FORMAT}) – 2016-09-28 07:07:24

1

嗯,我不与窗体/验证组件,熟悉并且,但是你可以使用一个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(), 
      )) 
     ; 
    } 

    // ... 
} 
+1

感谢您的回答,但我不认为我会因安全原因做到这一点。事实上,用户可以改变表单中的“作者”字段以匹配任何其他作者,从而绕过限制。 – Phen 2013-03-25 19:15:08

+0

并感谢您编辑我的问题,我不知道关于Markdown语法突出显示:) – Phen 2013-03-25 19:17:20

3

开始加入一个setAuthor方法到你的约束,然后调整验证方法。接下来的诀窍就是确定最合适的地方。

你不清楚你是如何将验证器绑定到你的书上的。你是使用validation.yml还是在表单内部做些什么?

+0

感谢您的回答,将作者注入约束做到了诀窍!我正在尝试将作者注入ValidatorConstraint中,该作品无效! – Phen 2013-03-26 16:01:14

-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)) 
       ) 
     )); 
    } 
} 
相关问题