Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Symfony] Formularz z kolekcją ale trochę inaczej
Forum PHP.pl > Forum > PHP > Frameworki
JoShiMa
Otóż mam taki problem. Z bazy pobieram informację o pewnej grupie użytkowników. Będę te informacje wyświetlać w tabeli. W jednym z pół tabeli ma się znaleźć niewielki TextArea za pomocą którego (via AJAX) zostanie do bazy dopisany komentarz dotyczący wybranego użytkownika.

I teraz tak. Wymyśliłam sobie, że cała tabelka powinna być formularzem a te pola TextArea powinny być kolekcją. Tylko jak zrobić, żeby indeksy odpowiadały ID usera. Czyli jesli w tabelce mam userów o id 5,12 i 17 to chcę miec tam pola

  1. <textarea id="form_comment_5" name="form[comment][5]" ></textarea>
  2. <textarea id="form_comment_12" name="form[comment][12]"></textarea>
  3. <textarea id="form_comment_17" name="form[comment][17]"></textarea>


A może to bez sensu robić to za pomocą FormBuildera skoro i tak będzie obsłużone AJAX-em?
Pilsener
Cytat
Wymyśliłam sobie, że cała tabelka powinna być formularzem a te pola TextArea powinny być kolekcją
- słabo, ponieważ formularze powinny jak najbardziej odpowiadać encjom. Im bardziej odejdziemy od struktury danych tym większe problemy w implementacji, formularze w symfony są zaprojektowane pod kątem współpracy z encjami.
Najprostsze rozwiązanie to dodanie formularza "UserForm" do wysyłanej do widoku kolekcji, np. tak:
  1. foreach($users as $userEntity){
  2. $userEntity->form = $this->createForm(UserForm::class, $userEntity);
  3. }

Potem wystarczy jedynie wyrenderować i jeśli mamy akcję do edycji usera via ajax to nie musimy już prawie nic robić poza podpięciem formularza do tej akcji.
Oczywiście trzeba wziąć pod uwagę takie rzeczy jak:
- csrf
- walidacja
- obsługa błędów
- edycja?
Jeśli dodanie formularza do każdego rekordu jest z jakiś powodów (np. wydajność) problematyczne, to można formularz wygenerować znów via ajax oddzielnie dla każdego rekordu.
Kolejna opcja to wygenerowanie formularza w JS na onclick bez żadnego requestu, jednak to wiąże się z dość dużym nakładem pracy i powoduje liczne problemy (np. z różnicami w renderowaniu pomiędzy PHP a JS).
I znów na ostatnim miejscu można to zrobić całkowicie ręcznie, jednak wtedy musimy implementować wszystko sami (np. walidację). Takie rozwiązanie polecałbym w ostateczności, bo często z jakiś powodów nie da się inaczej.
JoShiMa
Powinnam generować cały formularz nawet jeśli potrzebuję z mienić w locie jedno pole (dodać komentarz do usera a w innym miejscu tj na innej podstronie zmienić wartość jakiegoś pola z 0 n 1)?
Pilsener
Generować w sensie, że renderować? Niezupełnie, nawet jeśli używamy formularza (np. UserForm), który zawiera wszystkie pola to definiujemy w nim opcję "mode", która może być np. "add", "edit", "comment" czy "changePassword", czyli parametryzujemy ten formularz. Formularz musi być zgodny z requestem, inaczej będą problemy z walidacją, nadmiarowymi polami czy też pozwolimy zmienić coś co nie powinno być zmienione.
Oczywiście jeśli logiki przybywa to formularz warto podzielić np. na oddzielne od edycji, dodawania czy komentowania - to już od nas zależy.
JoShiMa
Dopiero się uczę. Jak wyrenderować poprawnie w widoku taki formularz podpięty do poszczególnych elementów kolekcji w sposób jaki pokazałeś w pierwszym poście?


kiedy próbuję renderować poszczególne formularze w pętli w szablonie dostaję komunikat:

Type error: Argument 1 passed to Symfony\Component\Form\FormRenderer::renderBlock() must be an instance of Symfony\Component\Form\FormView, null given, called in

  1. {% for item in newcooperations %}
  2. jakiś kod
  3. {{ form_start(item.form) }}
  4.  
  5. {{ form_end(item.form) }}
  6.  
  7. {% endfor %}
Pilsener
Trzeba sprawdzić:
  1. dump(item.form);


Z jakiś powodów jest null, a ma być FormView, który tworzymy z form poprzez proste wywołanie metody ->createView()
JoShiMa
Rzeczywiście mój błąd. chciałabym Cię jeszcze poprosić o pomoc w jednej sprawie.

Mam dwie encje połączone taką relacją:

  1. class User extends BaseUser
  2. {
  3. ...
  4. /**
  5.   * @var Article[]|ArrayCollection
  6.   *
  7.   * @ORM\OneToMany(targetEntity="Cooperation", mappedBy="patient", cascade={"ALL"})
  8.   */
  9. private $therapists;
  10.  
  11. /**
  12.   * @var Article[]|ArrayCollection
  13.   *
  14.   * @ORM\OneToMany(targetEntity="Cooperation", mappedBy="therapist", cascade={"ALL"})
  15.   */
  16. private $patients;
  17. }
  18.  


  1. class Cooperation
  2. {
  3. /**
  4.   * @ORM\Id
  5.   * @ORM\ManyToOne(targetEntity="User", inversedBy="therapists")
  6.   * @ORM\JoinColumn(name="patient", referencedColumnName="id")
  7.   */
  8. private $patient;
  9.  
  10. /** @ORM\Id
  11.   * @ORM\ManyToOne(targetEntity="User", inversedBy="patients")
  12.   * @ORM\JoinColumn(name="therapist", referencedColumnName="id")
  13.   */
  14. private $therapist;
  15.  
  16. ...


Próbuję zrobić do tego pewien formularz.

Jeśli zrobię to tak:

  1. public function buildForm(FormBuilderInterface $builder, array $options)
  2. {
  3. $builder
  4. ->add('patient', HiddenType::class)
  5. ->add('therapist', HiddenType::class)
  6. ->add('comment', TextareaType::class, [
  7. 'label' => false,
  8. 'attr' => [
  9. 'class' => 'form-control add-comment',
  10. 'rows' => '4',
  11. 'cols' => '20',
  12. ],
  13. ]);
  14.  


to wtedy mam po wygenerowaniu formularza w tych polach mam w wartości 'username' zamiast 'id'. Jeśli taki formularz wyślę ajaxem to nijak nie umiem go zwalidować.
Pilsener
Jeśli w encji jest relacja to w formularzu pole powinno być np. EntityType. HiddenType można mapować string lub int. Jeśli potrzebujemy zamiast np. selecta wpisać id to trzeba skorzystać z data transformers:
https://symfony.com/doc/current/form/data_transformers.html
ale tak szczerze to lepiej tego unikać, bo to prawie niczego nie rozwiązuje a stwarza kolejne problemy. Zresztą pisałem już chyba o tym, że im bardziej formularz przypomina encję (lub jej część) tym lepiej.
I zawsze lepiej jest najpierw zrobić tradycyjnie, a dopiero gdy wszystko działa to podpinamy pod AJAX, modale etc.
JoShiMa
Sądziłam, że EntityType służy wyłącznie do tworzenia pola wyboru :/

Rozwiązałam problem, ale połowicznie v konstrukcji formularza użyłam. property_path

  1. public function buildForm(FormBuilderInterface $builder, array $options)
  2. {
  3. $builder
  4. ->add('patient', HiddenType::class,['property_path'=>'patient.id'])
  5. ->add('therapist', HiddenType::class,['property_path'=>'patient.id'])
  6. ->add('comment', TextareaType::class, [
  7. 'label' => false,
  8. 'attr' => [
  9. 'class' => 'form-control add-comment',
  10. 'rows' => '4',
  11. 'cols' => '20',
  12. ],
  13. ]);


I to działa jeśli idzie o edycję encji. Jednak jesli chcę stworzyć encję i w tym celu wyprodukować pusty formularz:

  1. $cooperation = new Cooperation();
  2. $form = $this->createForm(CooperationType::class,$cooperation);


To dostaję błąd: PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "patient.id" at property "id".

Co jest zrozumiałe, bo ne ma żadnego obiektu patient z którego możnaby pobrać id.
Pilsener
Zacząć należało od tego, czy naprawdę potrzebny jest w formularzu ten "terapist" i "patient"?
Bo nie rozumiem, czemu to mają być pola typu hidden a nie np. selecty czy radia gdzie użytkownik może wybrać?
I w tego typu problemach zazwyczaj trzeba albo sparametryzować formularz (by działał w trybie "add" lub "edit") albo stworzyć dwa oddzielne formularze.
JoShiMa
Rzeczywiście ostatecznie po przemyśleniu okazało się, że te pola nie są potrzebne. Bo id user to id zalogowanego a id terapeuty to można przekazać w linku.
StevDefs
Purchasing Viagra Online For Cheap Propecia Generic Drug Pharmacy Gel Kamagra Francia priligy in sri lanka How Can I Get Viagra

Bentyl Tab Saturday Delivery Nursing Dogs And Amoxicillin Macrobid Saturday Delivery buy viagra online Bentyl Mastercard Canada Mixing Amoxicillin Wine Together Difference Between Amoxicillin And Penicillin

Walmart Propecia Price cheapest cialis Viagra Alle Donne Keflex And Stomach Bentyl Internet

Hydrochlorothiazide Best Website Keflex Recovery Acheter Du Cialis En Suisse generic cialis Wirkung Viagra 100mg

Dutasteride Vs Finasteride 2014 How To Last Longer During Why Discard Amoxil After Expire cialis overnight shipping from usa Photos De Pilules Amoxil
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-2024 Invision Power Services, Inc.