2013-03-25 14 views
16

Tworzę formularz w Symfony2. Formularz zawiera tylko jedno pole book, które umożliwia użytkownikowi wybór między listą podmiotów Books. Muszę sprawdzić, czy wybrany Book należy do Author Mam w moim kontrolerze.Przekaż parametry niestandardowe do niestandardowej metody sprawdzania poprawności w 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'); 
    } 

    // ... 
} 

Chcę sprawdzić, po wysłaniu formularza, że ​​wybrany Book jest napisany przez $author w moim kontrolera:

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

     // ... 
    } 
} 

Niestety, nie mogę znaleźć jakiś sposób, aby to zrobić. Próbowałem utworzyć niestandardowe ograniczenie weryfikatora, jak wyjaśniono w The Cookbook, ale podczas gdy mogę przekazać EntityManager jako parametr, definiując walidator jako usługa, nie mogę przekazać $author z kontrolera do ograniczenia weryfikatora.

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 może być dokładnie taka, która szukałem, ale moja forma nie jest zobowiązany do jednostki i nie ma być (Dostaję danych z metody getData()).

Czy istnieje rozwiązanie mojego problemu? To musi być powszechny przypadek, ale naprawdę nie wiem, jak go rozwiązać.

Odpowiedz

22

W końcu to wymyśliłem, z pomocą Cerada. Aby wprowadzić parametry niestandardowe, które muszą być dostępne z poziomu metody ConstraintValidator::validate(), należy je przekazać jako opcje w .

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

A w 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(...); 
     } 
    } 
} 

Ostatni, ale nie najmniej, trzeba przekazać parametr do Walidatora:

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

Należy zauważyć, że w Symfony 2.7 parametr niestandardowy nie znajduje się bezpośrednio w tablicy $ options, ale znajduje się w kluczu "wartości". W tym przykładzie otrzymasz autora od $ options ['value'] ['author']. A jeśli zadeklarowałeś assert przy użyciu adnotacji, możesz napisać coś w stylu: @CustomAssert \ CustomDateTime ({"dateFormat": Enum :: DATE_FORMAT}) –

1

Cóż, nie jestem familier z komponentu Form/Validation, ale można użyć Hidden field z nazwą/ID autora i sprawdzić, czy to jest ten sam:

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

Dziękuję za odpowiedź, ale nie sądzę, że byłbym w stanie to zrobić ze względów bezpieczeństwa. Rzeczywiście, użytkownik mógłby zmienić pole "autor" w formularzu tak, aby pasowało do każdego innego autora, tym samym pomijając ograniczenie. – Phen

+0

I dziękuję za zredagowanie mojego pytania, nie wiedziałem o podświetlaniu składni Markdown :) – Phen

3

start dodając metodę setAuthor dla twojego ograniczenia, a następnie ulepszanie metody sprawdzania poprawności. Sztuczka polega wtedy na określeniu najlepszego miejsca, w którym można to nazwać.

Nie jest jasne, w jaki sposób wiążesz walidator z książką. Czy używasz validation.yml lub robisz coś wewnątrz formularza?

+0

Dziękuję za odpowiedź, wstrzyknięcie Autora w Ograniczenie załatwiło sprawę!Próbowałem wprowadzić autora do ValidatorConstraint, który nie działał! – Phen

-1

Przyjęte rozwiązanie nie działa dla mnie za pomocą Symfony Framework wersja 2.1. Tak to rozwiązałem.

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)) 
       ) 
     )); 
    } 
} 
Powiązane problemy