2013-03-25 13 views
16

Sto creando un modulo in Symfony2. Il modulo contiene solo un campo book che consente all'utente di scegliere tra un elenco di entità Books. Devo controllare se lo Book selezionato appartiene a un Author che ho nel mio controller.Passa i parametri personalizzati a ValidationConstraint personalizzato 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'); 
    } 

    // ... 
} 

voglio verificare, dopo l'invio del modulo, che la Book selezionato è scritto dal $author nel mio controller:

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

     // ... 
    } 
} 

Purtroppo, non riesco a trovare un modo per farlo. Ho provato a creare un vincolo di convalida personalizzato come spiegato in The Cookbook, ma mentre posso passare il parametro EntityManager definendo il validatore come un servizio, non posso passare il $author dal controller al vincolo del validatore.

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 potrebbe essere esattamente quello che stavo cercando, ma la mia forma non è vincolata ad un soggetto e non è destinata ad essere (sto ottenendo i dati dal metodo getData()).

C'è una soluzione al mio problema? Questo deve essere un caso comune, ma non so davvero come risolverlo.

risposta

22

Finalmente ho capito, con l'aiuto di Cerad. Per inserire parametri personalizzati a cui è necessario accedere dal metodo ConstraintValidator::validate(), è necessario passarli come opzioni nello 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; 
    } 
} 

E, nel 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(...); 
     } 
    } 
} 

Ultimo ma non meno importante, è necessario passare il parametro al 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 
      )) 
     ) 
    )); 
} 
+0

Si noti che in Symfony 2.7, il parametro personalizzato non si trova direttamente nell'array $ options, ma si trova all'interno di una chiave 'value'. Quindi per questo esempio, otterresti l'autore da $ options ['value'] ['author']. E se hai dichiarato l'affermazione usando annotazioni, avresti scritto qualcosa come: @ CustomSendert \ CustomDateTime ({"dateFormat": Enum :: DATE_FORMAT}) –

1

Beh, io non sono che familier con il componente Form/convalida, ma è possibile utilizzare un Hidden field con il nome/id dell'autore e verificare se è la stessa:

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

Grazie per la risposta, ma non credo che sarei stato in grado di fare questo per motivi di sicurezza. In effetti, l'utente può modificare il campo 'autore' nel modulo per corrispondere a qualsiasi altro autore, ignorando così la restrizione. – Phen

+0

E grazie per aver modificato la mia domanda, non sapevo dell'evidenziazione della sintassi di Markdown :) – Phen

3

Inizia con l'aggiunta di un metodo setAuthor per il vincolo e quindi il tweaking del metodo di convalida. Il trucco è quindi quello di determinare il posto migliore per chiamarlo.

Non è chiaro esattamente come si lega il validatore al libro. Stai usando validation.yml o stai facendo qualcosa all'interno del modulo?

+0

Grazie per la risposta, l'iniezione dell'Autore nel Vincolo ha fatto il trucco!Stavo cercando di iniettare l'Autore nel ValidatorConstraint che non ha funzionato! – Phen

-1

risposta accettata non ha funzionato per me utilizzando Symfony Framework versione 2.1. Questo è il modo in cui l'ho risolto.

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