Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [SF][SF2][Symfony2] Walidacja danych wysłanych z niestandardowego forma.
Forum PHP.pl > Forum > PHP > Frameworki
damianooo
Witam,

Jak zwalidować w akcji kontrolera dane wyslane z formularza utworzonego manualnie ?

Moj formularz w TWIG:
  1. <form action="{{ path('typerka_types') }}" method="post">
  2. <div class="coupon_form">
  3. {% for key,match in matches %}
  4. <input type="hidden" name="match_id[]" value="{{ match.match_id }}">
  5. <div class="coupon_form_host">
  6. {{ match.host }}
  7. </div>
  8. <div class="coupon_form_host_type">
  9. <input type="text" name="hostType[]">
  10. </div>
  11. <div class="coupon_form_guest_type">
  12. <input type="text" name="guestType[]">
  13. </div>
  14. {% endfor %}
  15. </div>
  16. <input type="submit" value="Submit">
  17. </form>


Kontroler:

  1. public function typesAction(Request $request){
  2.  
  3. $repository = $this->getDoctrine()->getRepository('MyTyperkaBundle:Match');
  4. $matches = $repository->getMatchesPerMatchday(1);
  5.  
  6. if ($request->getMethod() == 'POST') {
  7. $req = $request->request->all();
  8. // ...
  9. $type = new Type();
  10. $match = new Match();
  11. // ....
  12. $em->persist($match);
  13. $em->persist($type);
  14. $em->flush();
  15. }
  16.  
  17. return $this->redirect($this->generateUrl('typerka_types'));
  18. }
  19. return array('matches' => $matches);


Normalnie robi sie to tak :

  1. $form->handleRequest($Request);
  2. if($form->isValid()){



ale u siebie mnie nie tworze forma w kontrolerze.





uirapuru
jeżeli chcesz zwalidować dane, to uzyj po prostu walidatora na wynikowym (przesłanym) obiekcie. walidator to osobny komponent symfony i może działać bez formularza. musiałbyś jednak dorobić i powielić sporo istniejącej już funkcjonalności m.in. do spopulowania obiektu danymi wejściowymi. Osobiście dla kazdych danych wejściowych (nie ważne, czy pochodzących od uzytkownika, czy automatycznego klienta) staram się tworzyć formularz - czytaj to jako funkcjonalność, a nie rezultat wizualny (formularz można, ale nie trzeba wyrenderować "do widoku"). na Twoim miejscu więc wysiliłbym się i stworzył klase formularza, nawet jeżeli jego pola sa tworzone dynamicznie, to z pewnościa jest jakiś algorytm jego tworzenia smile.gif następnie skorzystał z $form->isValid() jak biały człowiek smile.gif
damianooo
ehh ... no to mnie zmartwiłeś smile.gif ...

Chciałem to zrobić jak "biały człowiek" jednak miałem problem z uzyskaniem tego co potrzebowałem zrobić, a wiec:
- pobrać dane w RepositoryClass
- wyswietlić je w Twig
- dodać do tych danych pola do wypełnienia
- zapisać dane z wypełnionych pol w bazie
uirapuru
do tego co mi sie wydaje, potrzebujesz połączyć dwie rzeczy: embedded collection oraz dynamical forms. pierwsze pozwoli Ci stworzyć podformularze dla każdej encji z kolekcji (u Ciebie chyba matches), a eventy do dynamicznego tworzenia pól jeżeli masz tam odrobinę więcej logiki potrzebnej
damianooo
ok chyba nie bede mial wyjscia i powinienem to zrobic jak "bialy czlowiek" ... i rozumiem ze najlepiej zawsze isc ta droga w Symfony ....

Podpowiedz mi tylko czy powinienem tego forma i embeded collection robic dla encji Type czy Match ?
PS. Encja Type to ta ktorej dane bede dodawal do bazy, natomiast encja Match to ta, ktorej dane chce tylko wyswietlic w Twigu i nic wiecej z nimi nie robic.

W takiej relacji jest encja Type z encja Match:

  1. /**
  2.   * @ORM\ManyToOne(
  3.   * targetEntity = "Match",
  4.   * )
  5.   *
  6.   * @ORM\JoinColumn(
  7.   * name = "match_id",
  8.   * referencedColumnName = "id",
  9.   * onDelete = "SET NULL"
  10.   * )
  11.   */
  12. private $match;



Pyton_000
Przepraszam że się wpie... między wódkę a zakonskę ale zawsze mnie mnie dziwi dlaczego w Symfony/Zend to musi być takie skomplikowane. Każda pierdoła która powinna być zrobiona na maksa prosto bez udziwnień musi być zrealizowana przy pomocy pierdylardu klas, metod, tricków, hacków wink.gif

uirapuru
to nie jest kwestia symfony, tylko zasad dobrego programowania. spaghetti możesz tworzyć w kazdym fw, w symfony również smile.gif

@damianooo:

stwórz formularz osobiście do sprawy podchodze tak, że:

- moje encje nie maja setterów, parametry podaję do konstruktora tylko przy utworzeniu, wymusza to tworzenie metod z logiką, które sprawiają, że encja nie jest "anemiczna"
- tworzę sobie klase formularza opartą o klasę DTO
- tworzę sobie prostą klasę DTO, którą wpinam w formularz; zawiera ona publiczne pola np. kolekcje itd (wiem, ze DTO nie powinno zawierac encji, tylko id's ale w moich przypadkach jest to pomijalne - nie serializuję dto i nie pcham po api)
- tworzę serwis implementujący konkretną ścieżkę działania (przypadek użycia), zapodaje jej wszystkie potrzebne zależności i w jego metodzie handle zawieram logikę - utworzenie, obrobienie i zapis do bazy. oczywiście TDD, więc mam od razu otestowany kod; na koniec działania rzucam event, że działanie wykonane lub exception
- tworzę sobie factory dla encji (jedna dla match i druga dla type), dzięki temu mam w systemie jedno centralne miejsce, gdzie encje są tworzone i nigdzie indziej nie ma czegoś takiego jak new Match itp; robie w niej metodę createEntityFromCommand, która DTO konwertuje do encji
- w kontrolerze: tworzę formularz, wciskam w niego DTO, populuje DTO requestem, robię walidację DTO a nie encji (trzymam jej zasady w validation.yml), jesli valid to na utworzonym serwisie robię po prostu ->handle($command), przekazuje formularz do widoku i np. ustawiam flash dla usera.

voila. wszystko odizolowane i otestowane, a ten sam kod moge wykorzystać na stronie, w api czy commandzie bez różnicy.

  1. /**
  2.   * @Route("/rejestracja.html", name="evento_register")
  3.   * @Template()
  4.   */
  5. public function registerAction(Request $request)
  6. {
  7. $response = new Response(null, 200);
  8. $createCommand = new CreateWorkshop();
  9. $createCommand->lessons = [new CreateLesson()];
  10. $form = $this->createForm("register_workshops_form_type", $createCommand, [
  11. "action" => $this->generateUrl("evento_register"),
  12. "method" => "POST",
  13. ]);
  14. if($request->isMethod("POST"))
  15. {
  16. $form->handleRequest($request);
  17. if($form->isValid())
  18. {
  19. $this->get("tactician.commandbus")->handle($form->getData());
  20. $this->addFlash("success", "Dziękujemy za dodanie nowej informacji, po weryfikacji przez moderatora pojawi się w bazie");
  21. return $this->redirectToRoute("evento_homepage");
  22. } else {
  23. $response->setStatusCode(400);
  24. }
  25. }
  26. return $this->render("AppBundle:Default:register.html.twig", [
  27. "form" => $form->createView(),
  28. ], $response);
  29. }


Jak chcesz sobie podejrzeć, to mam taką tu małą appkę, nie zastosowałem wydzielenia klas domeny i aplikacji ani TDD ze względu na wielkość, ale to chyba identyczny przypadek jak Twoj - formularz z jedną kolekcją

https://github.com/uirapuru/evento/tree/master/src/AppBundle
damianooo
to co piszesz to troche wyzsza szkola jazdy wiec pewnie tym razem niestety nie skorzystam bo niestety nie umiem jeszcze tyle ...
bede chcial jednak to zrobic oczywiscie tak jak zasugerowales a wiec z wykorzystniem standardowego formularza ...
i na pewno uproscic jak sie da ... mam nadzieje ze w moim problemie, ktory mam do rozwiazania to mi sie uda ...
podziałam i podziele sie rozwiazaniem tutaj na forum ...
uirapuru
nie mam ambicji bycia nauczycielem, ale myślę, że kazdy moment na naukę dobry, tymbardziej, że jeśli dobrze rozumiem dałem Ci przykład ze swojego kodu 1:1 z Twoim przypadkiem wink.gif mam nadzieję, że pomogłem.
damianooo
hmm ... mowisz ze mamy podobienstwo 1:1 ... moze ... nie widze tego na razie

Zrobilem tak w kontrolerze:

  1. public function typesAction(Request $request){
  2.  
  3. $form = $this->createForm(new TypeType(), new Type(), array(
  4. 'action' => $this->generateUrl('typerka_types'),
  5. 'method' => 'POST',
  6. ));
  7. $form->add('submit', 'submit');
  8. $form->handleRequest($request);
  9. if ($request->getMethod() == 'POST') {
  10. if ($form->isValid()) {}
  11. }
  12. // ...


Formularz encji Type:

  1. public function buildForm(FormBuilderInterface $builder, array $options)
  2. {
  3. $builder
  4. ->add('hostType' )
  5. ->add('guestType' )
  6. ;
  7. }


niestety potrzebuje jeszcze pobrac dane z encji Match z Repository class:

  1. public function getMatchesPerMatchday($matchday){
  2. $qb = $this->createQueryBuilder('m');
  3. $qb->select(
  4. 'm.id AS match_id'
  5. ,'tm1.name AS host'
  6. ,'tm2.name AS guest'
  7. ,'m.description'
  8. ,'m.term'
  9. )
  10. ->innerJoin('m.hostTeam', 'tm1')
  11. ->innerJoin('m.guestTeam', 'tm2')
  12. ->innerJoin('m.matchday', 'md')
  13. ->where('md.id = :matchday')
  14. ->orderBy('m.id')
  15. ->setParameter('matchday', $matchday)
  16. ;
  17. // ...
  18. }


nie wiem jak to wszystko powiazac ...
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.