Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php][symfony] Wszystkie pola formularza jako niewymagane, required => false?
Forum PHP.pl > Forum > PHP
luis2luis
Witam.

Mam klasę formularza, w Symfony. Jest to wyszukiwarka zaawansowana. Mam problem z dwoma elementami.

1. Jak dla wszystkich pól ustawić parametr 'required' => false, aby nie były wymagane.

Pól jest ponad 20, nie chciałbym do każdego poprostu wkleić tego parametru. Myślałem, żeby w metodzie configureOptions() dodać taką opcje, w końcu jest to metoda do konfiguracji formularza, ale nie działa tak jak ja to robie .
  1. public function buildForm(FormBuilderInterface $builder, array $options): void
  2. {
  3.  
  4. $builder
  5. ->add('namne')
  6. ->add('description', TextareaType::class, ['data' => 'wpisany tekst'])
  7. ->add('deleted')
  8. ->add('prioryty')
  9. ->add('pinned')
  10. ->add('doneAt')
  11. ->add('doneByUser')
  12. ->add('remind')
  13. ->add('wontDo')
  14. .....;
  15. }
  16.  
  17. public function configureOptions(OptionsResolver $resolver): void
  18. {
  19. $resolver->setDefaults([
  20. 'data_class' => Task::class,
  21. 'required' => false, //tak nie działa
  22.  
  23. ]);
  24. }



2. Jak po wysłaniu takiego formularza, wstawić w wypełnione pola dane z requestu. Czyli jak ktos poda date kliknie "wyszukaj", żeby ta data była dalej wpisana w tym polu smile.gif

Formularz wyszukiwarki wyświetlam na roucie /tasks/list/ natomiast parametr action w formularzu odnosi się do /tasks/search/{search_phraze}

Dane te wyświetliłbym za pomocą parametru data.

Jak ten request przekazac do formularza?
  1. public function buildForm(FormBuilderInterface $builder, array $options): void
  2. {
  3.  
  4. $builder
  5. ->add('namne')
  6. ->add('description', TextareaType::class, ['data' => 'wpisany tekst'])
  7. ->add('deleted')
  8. ->add('prioryty')
  9. ->add('pinned')
  10. ->add('doneAt')
  11. ->add('doneByUser')
  12. ->add('remind')
  13. ->add('wontDo')
  14. .....;
  15. }


Będę wdzięczny za wszelkie wypowiedzi smile.gif
Salvation
Jak już dodasz wszystkie pola, to na końcu metody `buildForm()` wystarczy zwykła pętla po polach:
  1. foreach ($builder->all() as $field) {
  2. $field->setRequired(false);
  3. }
luis2luis
Cytat(Salvation @ 21.11.2022, 12:51:35 ) *
Jak już dodasz wszystkie pola, to na końcu metody `buildForm()` wystarczy zwykła pętla po polach:
  1. foreach ($builder->all() as $field) {
  2. $field->setRequired(false);
  3. }


Dziękuje, ciekawe rozwiązanie.
Symfony zwraca błąd: "Buttons cannot be required".

Dziwna sytuacja, ponieważ przekazywana jest wartość 'false' więc not reuired smile.gif

Salvation
No bo `->all()` zwróci wszystkie pola + button submit. Wrzuć przed `->setRequired()` ifa gdzie sprawdzisz typ i będzie grać.
luis2luis
Cytat(Salvation @ 21.11.2022, 21:56:24 ) *
No bo `->all()` zwróci wszystkie pola + button submit. Wrzuć przed `->setRequired()` ifa gdzie sprawdzisz typ i będzie grać.


Przeleciałem dział dokumentacji Symfony, dotyczący formularzy i nie widzę nigdzie informacji, że na obiekcie FormBuilder mogę wykonać metode all() smile.gif

PHPStorm podpowiedział mi, że istnieje metoda $field->getType() ale zwróciła spory obiekt i nie widać w nim informacji o typie pola jaki własnie jest przetwarzany w pętli.

Czy metoda getType() jest odpowiednia?

  1. foreach ($builder->all() as $field) {
  2.  
  3. dump($field->getType());
  4.  
  5.  
  6. if ($field->getType() == questionmark.gif) { // :)
  7. $field->setRequired(false);
  8. }
  9.  
  10. }

Salvation
Ten "spory obiekt", to na górze ma nazwę tego obiektu. Czyli potrzebujesz użyć operatora `instanceof` do porównania.

Czyli to będzie poprawny kod:
  1. foreach ($builder->all() as $field) {
  2. if (
  3. ($field->getType() instanceof SubmitType::class) ||
  4. ($field->getType() instanceof ButtonType::class) ||
  5. ($field->getType() instanceof ResetType::class)
  6. ) {
  7. continue;
  8. }
  9.  
  10. $field->setRequired(false);
  11. }
luis2luis
Cytat(Salvation @ 21.11.2022, 23:32:33 ) *
Ten "spory obiekt", to na górze ma nazwę tego obiektu. Czyli potrzebujesz użyć operatora `instanceof` do porównania.



Zrobiłem to troszeczke inaczej, ale dziekuje za naprowadzenie smile.gif Nie mogłem dojść, jakiej klasy jest to instancja.
Warunek zrobiłem tak:
  1. if (
  2. ($field->getName() === 'save') ||
  3. ($field->getName() === 'hide')
  4. ) {
  5. continue;
  6. }
Salvation
No spoko, tylko bazując na `name` musisz pamiętać o tym, że jak się zmieni jego nazwa, to musisz też zmienić to w pętli, a w przypadku klasy pola nie będziesz musiał tego zmieniać.
No i to co wrzuciłeś, to możesz zamienić na to:
  1. if (in_array($field->getName(), ['save', 'hide'], true)) {
  2. continue;
  3. }

Wrzuć może kod z dump jaki dostajesz po wywołaniu metody `getType`.
luis2luis
Cytat(Salvation @ 23.11.2022, 09:02:59 ) *
Wrzuć może kod z dump jaki dostajesz po wywołaniu metody `getType`.


Dump, bez rozwinięcia całości wygląda tak:
  1. ^ Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorPr
    oxy {#731 ▼
  2. -proxiedType: Symfony\Component\Form\ResolvedFormType {#732 ▼
  3. -innerType: Symfony\Component\Form\Extension\Core\Type\DateType {#723}
  4. -typeExtensions: []
  5. -parent: Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorPr
    oxy {#661 ▶}
  6. -optionsResolver: Symfony\Component\OptionsResolver\OptionsResolver {#733 ▶}
  7. }
  8. -dataCollector: Symfony\Component\Form\Extension\DataCollector\FormDataCollector {#647 ▼
  9. #data: array:3 [▶]
  10. -dataExtractor: Symfony\Component\Form\Extension\DataCollector\FormDataExtractor {#648}
  11. }
  12. }
Salvation
O widzisz, tego szukałem:
Kod
-innerType: Symfony\Component\Form\Extension\Core\Type\DateType

Nie mam jak sprawdzić teraz poprawności poniższego kodu, ale powinien za działać...
  1. foreach ($builder->all() as $child) {
  2. $fieldType = $child->getType()?->getProxiedType()?->getInnerType();
  3.  
  4. if (
  5. ($fieldType instanceof SubmitType::class) ||
  6. ($fieldType instanceof ButtonType::class) ||
  7. ($fieldType instanceof ResetType::class)
  8. ) {
  9. continue;
  10. }
  11.  
  12. $field->setRequired(false);
  13. }
luis2luis
Cytat(Salvation @ 24.11.2022, 12:44:18 ) *
O widzisz, tego szukałem:
Kod
-innerType: Symfony\Component\Form\Extension\Core\Type\DateType

Nie mam jak sprawdzić teraz poprawności poniższego kodu, ale powinien za działać...



Dziękuje bardzo za pomoc jeszcze raz smile.gif Teraz kod wygląda dużo lepiej i jest bardziej uniwersalny.

Troszeczkę zmodyfikowałem Twój kod i działa. Usunąłem "?->getProxiedType()" i przy klasach zapis "::class"

  1. foreach ($builder->all() as $field) {
  2.  
  3. $fieldType = $field->getType()?->getInnerType();
  4.  
  5. if (
  6. ($fieldType instanceof SubmitType) ||
  7. ($fieldType instanceof ButtonType) ||
  8. ($fieldType instanceof ResetType)
  9. ) {
  10. continue;
  11. }
  12.  
  13. $field->setRequired(false);
  14.  
  15. }
  16.  


Gdzie można poczytać o tych metodach np. getInnerType() to jest integralna część Symfony?

Znalazłem coś takiego np: https://symfony.com/doc/current/components/...s_resolver.html
Salvation
Cytat(luis2luis @ 24.11.2022, 13:58:07 ) *
Usunąłem "?->getProxiedType()" (...)

OK, faktycznie. Masz rację.
Tutaj cała klasa: https://github.com/symfony/symfony/blob/6.2...lectorProxy.php

Cytat(luis2luis @ 24.11.2022, 13:58:07 ) *
Gdzie można poczytać o tych metodach np. getInnerType() to jest integralna część Symfony?

Integralna część komponentu. Sam komponent możesz używać poza frameworkiem. A wyżej już podałem link do repo.

Cytat(luis2luis @ 24.11.2022, 13:58:07 ) *

OptionsResolver, to trochę inny komponent.
luis2luis
Cytat(Salvation @ 24.11.2022, 14:17:38 ) *
Przywróć `::class`, bo to przechowuje pełny namespace dla obiektu, a jak wiadomo, klasa może nazywać się tak samo, ale mieć inny namespace i możesz mieć problem...
Poczytaj o FQCN (Fully-Qualified Class Name).


po przywróceniau ::class Symfony wyrzuca błąd.

Cytat
syntax error, unexpected token "class", expecting variable or "$"
Salvation
Tak, już usunąłem głupoty co powypisywałem... wink.gif
luis2luis
Cytat(Salvation @ 24.11.2022, 14:35:44 ) *
Tak, już usunąłem głupoty co powypisywałem... wink.gif


Dziękuje za pomoc i fatygę, jestem bardzo wdzięczny smile.gif

Czy odpłatnie zgodziłbyś się poasekurować przy takim prostym treningowym projekcie Symfony "todo"? Jakieś tam drobne pytania od czasu do czasu? smile.gif
Salvation
Jesteśmy na forum, możesz zakładać tematy do woli. Nie zawsze mam czas na odpisanie pomiędzy 7:00 a 17:00.
luis2luis
Cytat(Salvation @ 24.11.2022, 15:34:59 ) *
Jesteśmy na forum, możesz zakładać tematy do woli. Nie zawsze mam czas na odpisanie pomiędzy 7:00 a 17:00.


ok rozumie smile.gif
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.