2013-03-25 21 views
16

Ich erstelle ein Formular in Symfony2. Das Formular enthält nur ein Feld book, das dem Benutzer die Auswahl zwischen Books Entitäten ermöglicht. Ich muss überprüfen, ob der gewählte Book zu einem Author gehört, den ich in meinem Controller habe.Übergeben Sie benutzerdefinierte Parameter an benutzerdefinierte ValidationConstraint in Symfony2

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

    // ... 
} 

Ich mag überprüfen, nach dem Absenden des Formulars, dass die ausgewählten Book durch die $author in meinem Controller geschrieben:

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

     // ... 
    } 
} 

Leider kann ich keine Möglichkeit, das zu tun finden. Ich habe versucht, eine benutzerdefinierte Validator-Einschränkung wie in The Cookbook beschrieben zu erstellen, aber während ich den EntityManager als Parameter übergeben kann, indem ich den Validator als Dienst definiere, kann ich die $author vom Controller nicht an die Validator-Einschränkung übergeben.

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 könnte sein, genau die, die ich suchte, aber meine Form ist nicht auf eine Entity gebunden und nicht an seine (von der getData() Methode Ich erhalte die Daten) gemeint.

Gibt es eine Lösung für mein Problem? Das muss ein häufiger Fall sein, aber ich weiß wirklich nicht, wie ich es lösen soll.

Antwort

22

Ich fand es endlich heraus, mit der Hilfe von Cerad. Um benutzerdefinierte Parameter einzugeben, auf die über die Methode ConstraintValidator::validate() zugegriffen werden muss, müssen Sie sie als Optionen in der Constraint übergeben.

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

Und im 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(...); 
     } 
    } 
} 

Last but not least, müssen Sie die Parameter auf den Validator übergeben:

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

Beachten Sie, dass in Symfony 2.7 der benutzerdefinierte Parameter nicht direkt im $ options-Array gefunden wird, sondern innerhalb eines 'value' Schlüssels. In diesem Beispiel würden Sie den Autor von $ options ['value'] ['author'] erhalten. Und wenn Sie die Assert mit Annotationen deklariert haben, würden Sie etwas schreiben: @CustomAssert \ CustomDateTime ({"dateFormat": Enum :: DATE_FORMAT}) –

1

Nun, ich bin nicht so familier mit der Form/Validierungskomponente, aber Sie können ein Hidden field mit dem Namen/ID des Autors verwenden und überprüfen, ob es das gleiche:

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

Vielen Dank für Ihre Antwort, aber ich glaube nicht, dass ich dies aus Sicherheitsgründen tun könnte. In der Tat könnte der Benutzer das Feld "Autor" in dem Formular so ändern, dass es mit jedem anderen Autor übereinstimmt, wodurch die Beschränkung umgangen wird. – Phen

+0

Und danke für das Bearbeiten meiner Frage, ich wusste nicht über Markdown Syntaxhervorhebung :) – Phen

3

startet durch Zugabe Setzen Sie eine setAuthor-Methode auf Ihre Einschränkung und optimieren Sie dann die validate-Methode. Der Trick ist dann, den besten Ort zu bestimmen, um es zu nennen.

Es ist nicht genau ersichtlich, wie Sie den Validator an Ihr Buch binden. Verwenden Sie validation.yml oder machen Sie etwas im Formular?

+0

Vielen Dank für Ihre Antwort, injizieren den Autor in die Zwangslage hat den Trick!Ich habe versucht, den Autor in den ValidatorConstraint zu injizieren, der nicht funktioniert hat! – Phen

-1

akzeptierte Antwort nicht für mich arbeiten mit Symfony Framework Version 2.1. So habe ich es gelöst.

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