Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [SF][Symfony]Problem z mapowaniem errorów do symfony forms
Krzysztof01
post 5.03.2020, 00:31:54
Post #1





Grupa: Zarejestrowani
Postów: 1
Pomógł: 0
Dołączył: 4.03.2020

Ostrzeżenie: (0%)
-----


Witam,
kiedyś przeczytałem ten artykuł: symfony-forms-with-request-objects . Od tamtego czasu staram się używać w wszelkich formularzach właśnie modeli zamiast operować na encjach, lecz w obecnym projekcie jedna z encji jest klasą abstrakcyjną, którą wykorzystuję w kilku innych encjach. Zrobiłem też do tego modele, które działają w podobny sposób. Formularz stworzony za pomocą symfony forms wykorzystuje javascript, aby dynamicznie dodawać odpowiednie pola do formularza w zależności od tego jaki typ aktywności wybierze użytkownik. Z racji tego, że formularz ten w zależności od właśnie typu aktywności musi zwracać dane raz jednej klasy, a raz innej zostałem zmuszony do ustawienia data_class w formularzu na null. Wszystko działa jak należy, lecz mój problem pojawia się przy formularzu edycji, a raczej akcji edycji w kontrolerze, ponieważ normalnie bez używania modelu zrobiłbym to tak:

  1. /**
  2.   * @Route("/admin/activity/edit/{id}", name="admin_activity_edit", methods={"POST", "GET"})
  3.   */
  4. public function edit(AbstractActivity $activity, Request $request, EntityManagerInterface $em)
  5. {
  6.  
  7. $form = $this->createForm(ActivityFormType::class, $activity);
  8.  
  9. $form->handleRequest($request);
  10. if ($form->isSubmitted() && $form->isValid())
  11. {
  12. $activity = $form->getData();
  13.  
  14. $em->persist($activity);
  15. $em->flush();
  16. $this->addFlash('success', 'Activity is updated!');
  17.  
  18. return $this->redirectToRoute('admin_activity_edit', [
  19. 'id' => $activity->getId(),
  20. ]);
  21. }
  22. return $this->render('admin_activity/edit.html.twig', [
  23. 'activityForm' => $form->createView()
  24. ]);
  25. }


Natomiast gdy chce postępować zgodnie z regułą "1. An entity should be always valid." widzę takie oto opcje:

1. Mapować dane z encji do odpowiedniego modelu za pomocą switch ($activity->getType()), a potem to wrzucać do forma i walidować tak jakby dwa razy bo oczywiście errory z modelu nie zmapują się same do forma więc warunek if ($form->isSubmitted() && $form->isValid()) w razie erroru nie wykona się, lecz także nie wyświetli errorów w formularzu więc muszę zmodyfikować kod w taki sposób:
  1. //before I take entity Activity which user want update and by switch bind it to right Model class
  2. //of course model must implements /ArrayAccess in this case
  3. $form = $this->createForm(ActivityFormType::class, $activityFormModel);
  4.  
  5. $form->handleRequest($request);
  6. if($request->isMethod('POST'){
  7. $errors = $validator->validate($activityModel)'
  8. if (count($errors) > 0) {
  9. foreach ($errors as $error) {
  10. $formError = new FormError($error->getMessage());
  11. $form->get($error->getPropertyPath())->addError($formError);
  12. }
  13. }else {
  14.  
  15.  
  16. if ($form->isSubmitted() && $form->isValid())
  17. {
  18. $activityModel = $form->getData();
  19.  
  20. dd($activityModel);
  21.  
  22. //bind model data back to entity and flush here
  23.  
  24. return $this->redirectToRoute('admin_activity_edit', [
  25. 'id' => $activity->getId(),
  26. ]);
  27. }
  28. }
  29. return $this->render('admin_activity/edit.html.twig', [
  30. 'activityForm' => $form->createView()
  31. ]);


Co wydaje mi się ogromnym przerostem formy nad treścią. Chociaż może to ja przesadzam i takie rozwiązanie jest ok?questionmark.gif

2. Druga opcja wydaje mi się najrozsądniejsza z tych które wymyśliłem, czyli najpierw z encji przerzucić dane do najzwyklejszej tablicy (nie muszę wtedy robić żadnych switchy bo ta pierwsza opcja raczej była wymyślona z zamysłem tego, że jeśli wrzucę do forma model z danymi to errory się zmapują do odpowiednich pól w formularzu ale skoro tak się nie dzieje) i tą tablicę wrzucić do forma a następnie dopiero po submicie walidować dane:

  1. if ($form->isSubmitted() && $form->isValid()) {
  2.  
  3. $data = $form->getData();
  4.  
  5. switch ($data['type']) {
  6. case 'Movement':
  7. $dataModel = ArrayConverter::toObject($data, new MovementActivityFormModel());
  8. break;
  9. case 'Weight':
  10. $dataModel = ArrayConverter::toObject($data, new WeightActivityFormModel());
  11. break;
  12. }
  13.  
  14. $errors = $validator->validate($dataModel);
  15.  
  16. if (count($errors) > 0) {
  17. foreach ($errors as $error) {
  18. $formError = new FormError($error->getMessage());
  19. $form->get($error->getPropertyPath())->addError($formError);
  20. }
  21.  
  22. return $this->render('admin_activity/add.html.twig', [
  23. 'activityForm' => $form->createView(),
  24. ]);
  25. }


Co upraszcza troszkę kod i wydaje mi się w obecnej sytuacji najlepszym wyjściem. Oczywiście także pozostaje jeszcze opcja poprostu nie bawić się tutaj w zawsze zwalidowane encje i walidację przeprowadzać bezpośrednio na encji, chociaż akurat tej opcji chciałbym uniknąć. Tutaj do was wielka prośba o pomoc, która opcja według was jest najwłaściwsza w tej sytuacji?? Ewentualnie może znacie jakąś lepszą alternatywę, na którą nie wpadłem lub sposób by walidacja na modelu została od razu mapowana do forma jeśli ten istnieje?? Dzięki wielkie za pomoc w każdej kontruktywnej postaci.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 29.03.2024 - 13:15