Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [Symfony] Transformacja danych przed zapisem
Forum PHP.pl > Forum > PHP > Frameworki
mundeck
Chciałbym przed zapisem danych z formularza w Symfony przekształcać je do odpowiedniego formatu. Przykładowo, jeśli użytkownik wpisze numer telefonu "123-123-123" to w bazie powinno być zapisane: "+48123123123". Próbowałem zastosować CallbackTransformer wg dokumentacji, ale to raczej służy formatowaniu w polach formularza, a nie w celu zapisania do bazy. Oczywiście mógłbym stworzyć sobie serwis i wrzucać sobie do niego wartość tego pola, ale czy są może jakieś lepsze, wbudowane w SF rozwiązania?
Crozin
Domyślam się, że Twój formularz pracuje bezpośrednio na obiekcie encji obsługiwanej przez Doctrine, tak? Jeżeli tak to jest to bardzo, bardzo zła praktyka.

1. Przygotuj sobie dedykowany obiekt, który reprezentuje model danych formularza.
2. Możesz wykorzystać DataTransformer dla formularza, który znormalizuje numer telefonu (123-123-123 -> +48123123123).
3. Jeżeli formularz jest prawidłowy wyciągnij sobie encję, zaktualizuj jej dane na podstawie danych z formularza i zapisz ją.
mundeck
Do każdego formularza mam przygotowany FormType i jeśli pola pokrywają się z polami encji, to ustawiam w setDefaults odpowiednią klasę.

Próbowałem zrobić tak jak w pkt. 2., tylko że efekt jest taki, że transfomer burzy mi domyślną wartość. Domyślna wartość, która pojawia się w polu "Telefon" to "+48", a transformer taką wartość powinien odrzucić (zawiera tylko 3 znaki, więc nie jest to poprawny nr).
Crozin
Tą odpowiednią klasą powinna być osobna, dedykowana klasa pod ten formularz - nie klasa-encja. To, że część pól się pokrywa, to że część będziesz traktować jako jeden-do-jeden jak w encji nie ma specjalnego znaceznia. Wtedy możesz zdecydowanie łatwiej określić sobie reguły walidacji, transformatory, a przede wszystkim specyficzną dla danego formularza logikę - logikę formularza, nie domeny, nie bazodanową.
mundeck
Pierwszy raz słyszę o takim rozwiązaniu. Nie wiedziałem, że ustawianie encji jako domyślnej klasy formularza jest niezalecane. Na ile zrozumiałem to co jest w dokumentacji (przykład z TaskType) to wlaśnie dzięki temu wszystko odbywa się szybciej i łatwiej, bo nie trzeba zapisywac osobno, ręcznie każdego pola, ani tworzyć tych dodatkowych klas. Myślałem, że taką klasą obsługującą formularz jest już po prostu Form Type.

Tymczasem jednak mam spory problem - dość skomplikowany formularz, który działał dobrze, dopóki nie wziąłem się za walidację. Jedne jego części (embedded forms) są wyświetlane lub nie w zależności od opcji wybranych we wcześniejszych polach (steruje tym jquery), tak samo niektóre dalsze pola są włączane i wyłączane w zależności od wyboru. Myślałem, że jeśli wyłącze pola tej składowej formularza, która jest chowana to ominę walidację, ale tak się nie dzieje. W efekcie schowana część formularza jest walidowana i formularz nie przechodzi, bo nic tam nie było wpisane.

Szczerze mówiąc mam wrażenie, że o ile dla prostych formularzy typu "zapisz notkę na blogu" komponent Form działa prosto, intuicyjnie i szybko można go ogarnąć, o tyle dla bardziej skomplikowanych formularzy przysparza on więcej problemów niż korzyści i szybciej bym zrealizował zakładaną funkcjonalność korzystając tylko z czystego HTML-a i logiki zawartej w kontrolerze.
ohm
Cytat(mundeck @ 20.04.2017, 17:59:29 ) *
Tymczasem jednak mam spory problem - dość skomplikowany formularz, który działał dobrze, dopóki nie wziąłem się za walidację. Jedne jego części (embedded forms) są wyświetlane lub nie w zależności od opcji wybranych we wcześniejszych polach (steruje tym jquery), tak samo niektóre dalsze pola są włączane i wyłączane w zależności od wyboru. Myślałem, że jeśli wyłącze pola tej składowej formularza, która jest chowana to ominę walidację, ale tak się nie dzieje. W efekcie schowana część formularza jest walidowana i formularz nie przechodzi, bo nic tam nie było wpisane.


A korzystasz z form eventsów?

Cytat(mundeck @ 20.04.2017, 17:59:29 ) *
Szczerze mówiąc mam wrażenie, że o ile dla prostych formularzy typu "zapisz notkę na blogu" komponent Form działa prosto, intuicyjnie i szybko można go ogarnąć, o tyle dla bardziej skomplikowanych formularzy przysparza on więcej problemów niż korzyści i szybciej bym zrealizował zakładaną funkcjonalność korzystając tylko z czystego HTML-a i logiki zawartej w kontrolerze.

Też kiedyś tak myślałem wink.gif Ale z czasem przyszła praktyka i teraz się tworzy i waliduje mi się duuużo szybciej formularze niż miałbym dłubać je ręcznie.


Co do samego transformera z domyślną wartościa, to możesz rzucić jakimś kodem?
mundeck

Na razie nie korzystam, ale czytam o nich, więc może jak przetestuję i się przekonam, to skorzystam wink.gif

Zaciekawiła mnie propozycja Crozin-a, ale nie bardzo wiem, jak taka klasa miałaby wyglądać, bo jeśli miałaby pokrywać wszystkie pola danej tabeli to czym różniłaby się od encji? I potem trzeba by było dla każdego z pól wstawiać odpowiednie wartości z tej klasy formularzowej do encji? Trochę nie kumam tego pomysłu

Kolejne pytanie: jak mam jednocześnie używać walidacji i transformerów, skoro transformery działają wcześniej niż walidacja? Istotą walidacji jest przecież to, żeby sprawdzać poprawność tych danych, które wpisał użytkownik i poinformować go o błędzie, a walidacja w Symfony następuje po transformacji, czyli dane są już "jakby" poprawne?
Pilsener
Wg mnie już kiepskim pomysłem jest zapisywanie czegoś innego niż wprowadza użytkownik, takie coś prędzej czy później źle się kończy (trudno przewidzieć wszystkie możliwości).
Czemu nie zrobić tego w JS? Do tego walidator by wymusić konkretny format (jeden lub wiele). Jak JS nie da rady sformatować to krzywdy nie ma.
A jeśli już chcemy zmieniać dane w ten sposób to w Zend było coś takiego jak Filter (może jest jakiś bundle do Symfony), w Symfony jest Data Transformer - tylko to jest dobre, jeśli chcemy używać tego wiele razy. Dla jednorazowego wyjątku lepiej użyć Form Events.
Crozin
1. Wykorzystywanie Doctrine'owskiej encji w formularzu jest o tyle złe, że nagle jedna klasa zaczyna być odpowiedzialna za wiele różnego rodzaju zadań - jedno to obsługa modelu bazodanowego, drugie to obsługa jakiegoś konkretnego formularza.
2. W przypadku encji dodatkowym niebezpieczeńtwem jest to, że nawet nieprawidłowy (z punktu widzenia waildacji) formularz zmienia właściwości encji, jeżeli gdzieś dalej będziesz przypadkiem ją aktualizować (w jakimś fragemncie niezwiązanym z samym formularzem) możesz się nieciekawie zaskoczyć.
3. Nie jesteś zmuszony korzystać z komponentu formularzy. To co potrzebujesz osiągnąć można zrobić przy jego pomocy (wspomniane form events). Jeśli jednak nie czusz się w jego ramach "na siłach" możesz sobie ręcznie wykonać obsługę takiego formularza posiłkując się np. komponentem od samej walidacji.
4. Pamiętaj, że "szybciej i łatwiej" bardzo często nie oznacza "najmniejszą ilością kodu". Utworzenie dodatkowej klasy, stricte pod reprezentację modelu formularza oraz kilka linijek na zmapowanie danych przy poprawnym wypełnieniu ów formularza to 5 minut roboty.
5. To, że klasa reprezentująca dane z formularza i klasa encji ma trochę pokrywających się pól nie sprawia, że są tożsame.
5.1. Klasa od formularza co najwyżej zawiera zapewne mały podzbiór pol encji. Na pewno nie dajesz w niej właściwości typu ID, zapewne nie wszystkie relacje można zmieniać w tym formularzu itp.
5.2. Obiekt danych z formularza nie jest w żaden sposób powiązany z EntityManagerem Doctrine'a. Nie jest przedmiotem cyklu jego pracy - tutaj patrz na punkt #2.
6. Jesteś pewien, że data transformers podpiąłeś w odpowiednim miejscu? http://symfony.com/doc/current/form/data_t...ew-transformers
7. Pomysł zaproponowany przez @Pilsener by wykorzystać JS również nie jest najgorszy. Przy czym niezgodziłbym się ze stwierdzeniem, że z DataTransformers nie możesz korzystać nawet przy jednorazowym użyciu.
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.