2013-03-25 155 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)) 
       ) 
     )); 
    } 
} 
相關問題