![]() |
![]() |
![]()
Post
#1
|
|
![]() Grupa: Zarejestrowani Postów: 896 Pomógł: 76 Dołączył: 15.11.2003 Skąd: Sosnowiec/Kraków Ostrzeżenie: (0%) ![]() ![]() |
Właśnie po raz pierwszy zaimplementowałem upload obrazka + Doctrine i mam pewne wątpliwości. Chodzi o nakład pracy w kodzie potrzebny do przeprowadzenia tej operacji. Zrobiłem to w oparciu o lifecycle callbacks i musiały powstać 3 pola i 11 metod w obiekcie. Fajnie, że nie trzeba nic robić w kontrolerze i rozumiem, że część tych metod to rzeczy w stylu getWebPath i jak mi się nie podoba to nie muszę koniecznie ich używać, ale mimo wszystko to wydaje mi się trochę dziwne. Strach pomyśleć co się stanie jak będę miał 6 plików przy obiekcie.
A na koniec jeszcze czytam w cookbook, że "The PreUpdate and PostUpdate callbacks are only triggered if there is a change in one of the entity's field that are persisted" więc jak zmienię tylko awatar w profilu usera to on mi się nie zapisze :/ Trochę to załamujące, czy to podejście z cookbook jest naprawdę optymalne? Ten post edytował Foxx 17.04.2013, 13:48:09 |
|
|
![]() |
![]()
Post
#2
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Przykłady uploadu w dokumentacji formularzu Symfony są fatalne - gwałcą kilka podstawowych zasad "dobrego kodu", które sam framework mocno forsuje. Nigdy nie powinny się tam znaleźć w takiej formie.
1. Utwórz odpowiedni model: 1.1. Obiekt reprezentujący wgrywany plik: 1.2. W obiekcie, który posiada ów obraz (powiedzmy, że rozważamy klasyczny przykład użytkownika i jego awataru) najczęściej chcemy przechować jedynie ścieżkę do pliku. Ewentualnie możemy mieć kompletnie osobną tabelę w bazie danych reprezentującą obraz oraz metadane jego dotyczące (wymiary, typ itp.) złączony z inną tabelą relacją jeden-do-jednego. W obu przypadkach mechanizm jest jednak taki sam, więc omówimy jedynie ten pierwszy: Obiekt domeny nie powinien mieć absolutnie nic wspólnego z uploadem plików! 1.3. Na koniec potrzebujemy osobny obiekt, który złączy to wszystko razem, tj. wgrywany plik oraz interesujący nas obiekt sam w sobie: $object to obiekt do którego będziemy wgrywać zdjęcie, $image to samo zdjęcie, a $imagePath to ścieżka do właściwości przechowującej ścieżkę do wgrywanego pliku (patrz: komponent PropertyAccess Symfony). Czyli w tym przypadku ścieżką taką będzie "object.avatarPath" (właściwie to pierwszy człon "object." można pominąć). Jeżeli nasz obiekt byłby bardziej złożony i tak możemy bez problemu określić ścieżkę do właściwości "...path", np.: "object.image.path", "object.profile.defaultImage" itp. 1.4. Zarówno obiekt Image jak i ImageUpload mogą być wykorzystywane z dowolnym innym obiektem (User, Profile, Photo, Album itp.) 2. Model jest już przygotowany, pozostało obsłużenie samego uploadu. Właściwie to samym uploadem zajmje się symfony, my musimy jedynie zadbać o to by z wgranego pliku ("image.image") ścieżka została przepisana do interesującej nas właściwości obiektu domeny (tutaj: "object.avatarPath"). To zadanie musi wykonać się po walidacji formularza i przed pobraniem z niego danych w celu dalszej obróbki: FormEvents::POST_BIND. 2.1. Tworzymy sobie usługę, którą rejestrujemy jako listenera dla w/w zdarzenia. Ta usługa, bez problemu może w swoim konstruktorze otrzymać ścieżkę do katalogu dla uploadu czy jakąś usługę typu FilesystemUtility, która wygeneruje unikalną nazwę dla pliku. Mając już takiego listnera możemy spokojnie przerzucić dane:
3. Obsługa tego w jakimś kontrolerze:
Plusy takiego rozwiązania: 1. Jest uniwersalne, można je wykorzystać z dowolnym obiektem. 2. Wszystko jest ładnie rozdzielone, mamy czysty kod. Jeżeli chciałbyś dodać obsługę wielu plików, wystarczy że zmodyfikujesz powyższe w taki sposób by ImageUpload posiadał kolekcję obiektów Image oraz tablicę $imagePath. Ten post edytował Crozin 17.04.2013, 16:17:23 |
|
|
![]()
Post
#3
|
|
![]() Grupa: Zarejestrowani Postów: 896 Pomógł: 76 Dołączył: 15.11.2003 Skąd: Sosnowiec/Kraków Ostrzeżenie: (0%) ![]() ![]() |
O rany, Crozin, dzięki. Tamto rozwiązanie z cookbook działa i już miałem je pozostawić, ale wobec takiego wyłożenia tematu przez Ciebie zrobię to od razu na nowo.
|
|
|
![]()
Post
#4
|
|
![]() Grupa: Zarejestrowani Postów: 83 Pomógł: 1 Dołączył: 26.02.2013 Ostrzeżenie: (0%) ![]() ![]() |
3. Obsługa tego w jakimś kontrolerze:
Dedukuję, że "SomeFormType()"zawiera nie mapowane pola user,password itd., w którym miejscu mają zostać przekazane dane do atrybutów obiektu User?. |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 21 Pomógł: 0 Dołączył: 4.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
Witam.
Próbuję zrobić uploader wg tego co napisał Crozin, jednak po drodze napotkałem problem. Jestem początkujący w Symfony, stąd też mój problem. Wydaje mi się, że zgubiłem się na tworzeniu listenera. Serwis:
Listener:
Kontroler:
Błąd jaki otrzymuje: Kod ContextErrorException: Warning: Missing argument 1 for My\UserBundle\Form\Domain\ImageUpload::__construct(), called in W:\wamp\www\symfony\app\cache\dev\appDevDebugProjectContainer.php on line 2930 and defined in W:\wamp\www\symfony\src\My\UserBundle\Form\Domain\ImageUpload.php line 14 Czy może mnie ktoś nakierować co robię źle? ********************************************* Edit: Powoli wraz z dokumentacją Symfony pokonuje trudności napotkane po drodze. Jednak jednego problemu nie mogę pokonać. Kiedy uploaduje plik, otrzymuje notice Kod ContextErrorException: Runtime Notice: Only variables should be passed by reference in W:\wamp\www\symfony\src\My\UserBundle\Form\Type\ProfileAvatarFormType.php line 37 //ProfileAvatarFormType
//Kontroler
//ImageUpload
//Image
W PropertyAccessor metoda setValue posiada 3 parametry, jednak Crozin podał tylko 2 (w poprzedniej wersji symfony były 2 parametry?)
Wracając do błędu, syfony pokazuje notice gdy przekazuje obiekt w parametrze $objectOrArray, tylko dlaczego? Kolejna sprawa to jaki powinien być trzeci argument setValue()? Ten post edytował Crea17 19.02.2014, 23:28:40 |
|
|
![]()
Post
#6
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
Metoda PropertyAccessor::setValue oczekuje zawsze trzech argumentów, Ty zaś podajesz jej tylko dwa.
Co do błędu Cytat ContextErrorException: Runtime Notice: Only variables should be passed by reference in W:\wamp\www\symfony\src\My\UserBundle\Form\Type\ProfileAvatarFormType.php line 37 Prawdopodobnie chodzi o ułomność samego PHP-ca. Robisz takie coś:PHP nie potrafi ogarnąć, że chodzi o referencję do obiektu/tablicy zwróconą przez metodę getData(). Musiałbyś to zastąpić czymś takim:
|
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 21 Pomógł: 0 Dołączył: 4.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
Ok, tylko w tym momencie dostaje error: Ta wartość nie powinna być pusta.
Jeżeli mapped=>true Kod Neither the property "avatar" nor one of the methods "getAvatar()", "isAvatar()", "hasAvatar()", "__get()" exist and have public access in class "My\UserBundle\Form\Domain\ImageUpload". Z tego wynika, że powinienem mieć wymienione metody w pliku ImageUpload, ale wtedy za każdym użyciem z inną zmienną musiałbym tworzyć kolejne metody. Tak ma robić, czy coś mam źle? |
|
|
![]()
Post
#8
|
|
![]() Grupa: Zarejestrowani Postów: 2 148 Pomógł: 230 Dołączył: 26.03.2008 Ostrzeżenie: (0%) ![]() ![]() |
Niezłe farmazony. Zapomnij o tych absolutnie zbędnych komplikacjach.
W encji ustaw właściwości dla pliku (niemapowany) oraz nazwy pliku (mapowany). W setterze pliku ustawiaj wygenerowaną nazwę pliku. Następnie po sprawdzeniu poprawności formularza przeprowadź upload do katalogu sprecyzowanego choćby w parametrach Sf2. Czytelne, proste, wygodne, nie naruszające dobrych zasad. Pozdrowienia. -------------------- ET LINGUA EIUS LOQUETUR IUDICIUM
|
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 21 Pomógł: 0 Dołączył: 4.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
|
|
|
![]()
Post
#10
|
|
![]() Grupa: Zarejestrowani Postów: 2 148 Pomógł: 230 Dołączył: 26.03.2008 Ostrzeżenie: (0%) ![]() ![]() |
Nie. Zgadzam się z @Crozin, że podane tam przykłady są nienajlepsze, chociaż sam wybrał drogę umycia wieżowca szczoteczką do zębów. Przeczytaj jeszcze raz co napisałem i porównaj z Cookbookiem.
Ten post edytował pyro 24.02.2014, 23:55:17 -------------------- ET LINGUA EIUS LOQUETUR IUDICIUM
|
|
|
![]()
Post
#11
|
|
Grupa: Zarejestrowani Postów: 21 Pomógł: 0 Dołączył: 4.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
Czyli w encji:
A w kontrolerze
Dobrze zrozumiałem? Ten post edytował Crea17 25.02.2014, 09:55:43 |
|
|
![]()
Post
#12
|
|
![]() Grupa: Zarejestrowani Postów: 2 148 Pomógł: 230 Dołączył: 26.03.2008 Ostrzeżenie: (0%) ![]() ![]() |
Coś w ten deseń, tak.
// EDIT
Te 3 wymuszenia można połączyć w jedno.
$file to cały czas $file ![]() Ten post edytował pyro 25.02.2014, 09:57:39 -------------------- ET LINGUA EIUS LOQUETUR IUDICIUM
|
|
|
![]()
Post
#13
|
|
Grupa: Zarejestrowani Postów: 21 Pomógł: 0 Dołączył: 4.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
Ok. Dziękuję bardzo za pomoc
![]() |
|
|
![]()
Post
#14
|
|
![]() Grupa: Zarejestrowani Postów: 6 476 Pomógł: 1306 Dołączył: 6.08.2006 Skąd: Kraków Ostrzeżenie: (0%) ![]() ![]() |
@Crea17: Umknął mi gdzieś ten wątek.
Powinieneś mieć następujące typy dla formularza: 1. ImageType (pracujący na ...\Domain\Image) z definicjami dla właściwości "file" (typ "file") oraz "delete" (typ "boolean"). 2. ProfileAvatarFormType (pracyjący na ...\Domain\ImageUpload) z definicjami dla właściwości "object" (typ UserType) oraz "image" (typ ImageType). 3. PropertyAccess::setValue() oczekuje zawsze 3 argumentów, których Ty nie zawsze podajesz. @pyro: Gdzie Ty widzisz komplikacje w utrzymywaniu kodu w formie niezależnej od reszty, którą da się wielokrotnie wykorzystywać. Ten post edytował Crozin 28.02.2014, 17:25:27 |
|
|
![]() ![]() |
![]() |
Wersja Lo-Fi | Aktualny czas: 24.07.2025 - 15:43 |