![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 219 Pomógł: 5 Dołączył: 18.07.2006 Skąd: Piekary Śląskie Ostrzeżenie: (0%) ![]() ![]() |
Człowiek uczy się całe życie.
Od kilku lat wszystkie prace, które wykonuję bazują na szkielecie, który rozbudowuję przez cały ten czas. Szkielet ten polega na tym, że mam moduły (jeden moduł - jedna klasa), w których zdefiniowane są poszczególne zadania wykonywane przez moduł (jedno zadanie - jedna metoda). Na przykład za dodanie artykułu do bazy odpowiedzialna jest jedna z metod odpowiedniej klasy. Jedna z zasad OOP mówi, że jeżeli moduł A chce żeby było zrobione coś co dotyczy modułu B to najlepiej niech moduł B zrobi to sam bo on wie najlepiej jak to zrobić. Przykład ilustrjący tę zasade w moim przypadku: Jest moduł do zarządzania grupami użytkowników. Jednym z jego zadań jest definiowanie praw dostępu. Prawa są wyswietlane dla każdego zainstalowanego modułu w formie rozwijanego drzewka, w którym użytkownik zaznacza odpowiednie checkboxy. Aby skonstruować to drzewko moduł zarządzajacy grupami includuje każdy moduł. Każdy z includowanych modułów zawiera metodę, która otzrymuje referencę do obiektu symblizującego generowane drzewko. Zadaniem tej metody jest dodanie do drzewka checkboxów konkretnego modułu. Wszystko działa pięknie, chuczy, buczy, lata i gada. Tylko jest jeden problem. Każdy z modułów zawiera 500 - 1000 linijek kodu. jeżeli modułów jest powiedzmy 20 to aby wygenerować to drzewko potrzeba przeparsować całą masękodu po to aby w ażdym dołączonym module skorzystać z jednej metody zawierającej pięć linijek. Masakra! I oto myślę sobie: "Kurcze MVC pomoże. Każdy moduł rozbiję na szereg akcji, widoków i elementów modułu i będzie fajnie. Przy każdym żądaniu będę includował tylko to co trzeba." No i faktycznie rozbiłem kilka przykładowych modułów zgodnie z paradygmatem MVC i jest super. Tylko natrafiłem na problem, z którym nie bardzo umiem dać sobie radę. Chodzi o formularze w panelu administracyjnym np. do dodawania użytkowników, artykułów etc.) Generalnie zasada jest taka: 1. Trzeba dodać użytkownika - ładuje się widok z formularzem. 2. User wypełnia formularz, klika guzik 3. uruchamiana jest akcja dodajaca usera. Jęzli formularz był wypełniony dobrze to dane są zapisywane i ładowany jest widok z listą użytkowników. Jeśli zaś dane zostały wpisane źle to ładowany jest ponownie widok z formularzem. Teoria piękna (jak to zwykle z teoriami bywa), natomiast z praktyką trohe gorzej. Przy okazji budowania dotychczasowych stron stworzyłem sobie piekny zestaw klas służący do generowania i walidacji formlarzy. Z perspektywy OOP aż miło mi sie na to patrzy bo to jedna z lepszych rzeczy jaka zobiłem. Mam zestaw klas Form_Select, Form_TextBox itd. (co robią nie będę tłumaczył bo to oczywste). Służą one do tego aby do obiektu klasy Form_Form (reprezentującej formularz) dodać odpowiednie pola. Form_Form jest kontenerem dla obiektów klas dziedziczących po klasie Form_Pole (takich jak wymieniony wcześniej Form_Select etc.). Każda klasa reprezentująca pole formularza przyjmuje też obiekt odpowiadający za walidację pola, np. Waidacja_IntegerDodatnie, Walidacja_StringWymagane, Walidacja_Godzina. Te obiekty są odpowiedzialne za to aby to co user wpisze w pole było tym co ma wpisać. Następnie formularz jest wyświetlany przez wywołanie jego metody construct(). Tworzy ona podstawowy szkielet html i wywołuje metodę construct() dla wszystkich obiektów reprezentujących pola tak aby się wyświetliły w formularzu. Kiedy user wypełni formularz i go wyśle tworzony jest znowu jego obiekt aby go zwalidować metodą waliduj(). Zwraca ona true jęli formularz był wypełniony prawidłowo. Jak widać obiekt formularza jest tworzony dwukrotnie (raz aby go wyświetliś i drugi aby zwalidować). Stworzyłem więc metodę prywatną w module aby generowała odpowiedni obiekt klasy Form_Form (bo po co kod kopiować). I teraz niech mi ktoś powie gdzie ja mam ja umieścić uwzględniając wzorzec MVC? a) czemu nie w akcji? bo pomimo że Form_Form zawiera metodę waliduj(), która jest odpowiednia dla akcji to zawiera metodę construct(), która wyświetla formularz. (IMG:http://forum.php.pl/style_emoticons/default/cool.gif) czemu nie w widoku? bo pomimo że Form_Form zawiera metodę construct(), która jest odpowiednia dla widoku to zawiera metodę waliduj(), która waliduje formularz. c) czemu nie w modelu? bo pomimo, że do wygenerowania formularza potrzebne są informacje z bazy danych (np. lista kategorii, do których może należeć dodawany artykuł) to są tez tam metody construct() i waliduj(), które są odpowiednie dla widoku i akcji. I co z tym fantem zrobić? Wszystko spełnia zasady dotyczące tego co mówią podręczniki uczące OOP. Wszystko jest zgodne ze zdrowym rozsądkiem (przynajmniej moim) i wszystkiego sie wygodnie używa. Tylko do MVC jakoś tak daleko... no i to, że praktycznie za każdym wywołaniem skryptu trzeba includować dużo tysięcy linii kodu. Gdyby ktoś miał pomysł jak rozwiązać mój dylemat z formularzami to bardzo prosze o pomoc. Tym, którzy doczytali do końca gratuluję. |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 2 262 Pomógł: 21 Dołączył: 3.05.2004 Skąd: Sopot, Krakow, W-wa Ostrzeżenie: (0%) ![]() ![]() |
Przepraszam za krotko odpowiedziec na php PRO ;-)
A moze by tak kazda akcja to pojedyncza klasa, modul to katalog - i tyle (IMG:http://forum.php.pl/style_emoticons/default/smile.gif) |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 219 Pomógł: 5 Dołączył: 18.07.2006 Skąd: Piekary Śląskie Ostrzeżenie: (0%) ![]() ![]() |
Przepraszam za krotko odpowiedziec na php PRO ;-) A moze by tak kazda akcja to pojedyncza klasa, modul to katalog - i tyle (IMG:http://forum.php.pl/style_emoticons/default/smile.gif) No właśnie do tego dążę rozpoczynając zabawę z MVC i nie mam z tym najmniejszego problemu. Jest to rozwiązanie problemu includowania jak najmniejszej ilości kodu. Jednak mam problem, o którym pisałem, z przyporządkowaniem metody generującej formularz do odpowiedniej warstwy gdyż potrzebuję jej we wszystkich trzech warstwach, a raczej to ta metoda zawiera elementy wszystkich trzec warstw. Takiego czegoś MVC nie przewiduje. |
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 68 Pomógł: 1 Dołączył: 27.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
Jednak mam problem, o którym pisałem, z przyporządkowaniem metody generującej formularz do odpowiedniej warstwy gdyż potrzebuję jej we wszystkich trzech warstwach, a raczej to ta metoda zawiera elementy wszystkich trzec warstw. Takiego czegoś MVC nie przewiduje. Powinna ona należeć do warstwy kontrolera, powinna być jedną z jego akcji. W tym przypadku kontroler formularza powinien pobrać z modelu strukturę tabeli, wygenerować pola (np. w postaci obiektu czy tablicy) i przekazać to do widoku, aby widok ubrał to w kod html. |
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 219 Pomógł: 5 Dołączył: 18.07.2006 Skąd: Piekary Śląskie Ostrzeżenie: (0%) ![]() ![]() |
Powinna ona należeć do warstwy kontrolera, powinna być jedną z jego akcji. W tym przypadku kontroler formularza powinien pobrać z modelu strukturę tabeli, wygenerować pola (np. w postaci obiektu czy tablicy) i przekazać to do widoku, aby widok ubrał to w kod html. Po pierwsze formularze wcale nie odzwierciedlają pól w tabeli. A po drugie gdybym zrobił tak jak mówisz to otrzymał bym coś o czym pisałem już wcześniej: W widoku wyświetlającym formularz miałbym: echo("<input ...>"); ... echo('<select ...>'); A w akcji walidującej: if(!empty($dana1) && $dana2 >0 && ...) Nie przekonacie mnie, że taka walidacja jest dobra. W ten sposób kod odpowiedzialny za zachowanie formularza miałbym rozwalony po kilku klasach a coś takiego nie ma nic wspólnego z OOP i reusability. Zasada jest prosta: chcesz aby formularz sie zwalidował to każ mu się zwalidować, chcesz aby się wyświetlił to każ mu się wyświetlić. Jeżeli kod walidujący będzie inny od wyświetlającego to aby dodać nowe pole do formularza będę musiał modyfikować dwa pliki, jeżeli będzie to w jednej klasie to wystarczy dodać do obiektu formularza kolejne pole. Według mnie zasady inżynierii programowania wymagają aby kod zamykać w funkcjonalne moduły. Formularz i jego zachowanie jest pewnym modułem. Nie da się oddzielić od siebie dwóch zachowań formularza - jego "walidowalności" i "konstruowalności". Te dwie czynności można oczywiście robic w różnych opcjach ale bezsensem według mnie jest implementowanie tych dwóch zachowań jako czegoś nie związanego ze sobą. |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 68 Pomógł: 1 Dołączył: 27.03.2006 Ostrzeżenie: (0%) ![]() ![]() |
Możesz przechowywać w module listę pól formularza np. w postaci tablicy (przykład w uproszczeniu):
Cytat Po pierwsze formularze wcale nie odzwierciedlają pól w tabeli. A po drugie gdybym zrobił tak jak mówisz to otrzymał bym coś o czym pisałem już wcześniej: W widoku wyświetlającym formularz miałbym: echo("<input ...>"); ... echo('<select ...>'); I teraz w widoku wyświetlającym generowałbyś w jakiejś pętli widok formularza, czyli jego kod HTML, na podstawie listy w takiej postaci jak wyżej. Dla tego przykładowego pola mógłby być wygenerowany kod <input type="text" name="imie" value='' maxlenth='20' />. Cytat A w akcji walidującej: if(!empty($dana1) && $dana2 >0 && ...) Tu walidowałbyś dane w pętli na podstawie listy pól formularza. W tym przypadku trzeba by sprawdzić czy pole ma wartość typu 'string' i czy długość tekstu jest mniejsza niż 20 znaków. Cytat Nie przekonacie mnie, że taka walidacja jest dobra. W ten sposób kod odpowiedzialny za zachowanie formularza miałbym rozwalony po kilku klasach a coś takiego nie ma nic wspólnego z OOP i reusability. Zasada jest prosta: chcesz aby formularz sie zwalidował to każ mu się zwalidować, chcesz aby się wyświetlił to każ mu się wyświetlić. Jeśli chesz aby kontroler formularza zwalidował dane to niech je zwaliduje, możesz to zrobić bezpośrednio w kontrolerze używając funkcji strlen(), is_string() itp. albo napisać do tego jakąś klasę walidująca dane przychodzące. Jak kontroler ma wyświetlić formularz to przekazuje opis jego struktury do widoku i widok generuje na jej podstawie kod HTML formularza. Cytat Jeżeli kod walidujący będzie inny od wyświetlającego to aby dodać nowe pole do formularza będę musiał modyfikować dwa pliki, jeżeli będzie to w jednej klasie to wystarczy dodać do obiektu formularza kolejne pole. Modyfikowałbyś jeden plik, a ściślej to listę pół formularza. Cytat Według mnie zasady inżynierii programowania wymagają aby kod zamykać w funkcjonalne moduły. Formularz i jego zachowanie jest pewnym modułem. Nie da się oddzielić od siebie dwóch zachowań formularza - jego "walidowalności" i "konstruowalności". Jak to się nie da? Walidowanie i konstruowanie to dwa inne zachowania takiego obiektu, a jeśli modelujemy zachowanie jako metodę klasy to byłyby to dwie metody w klasie kontrolera. Cytat Te dwie czynności można oczywiście robic w różnych opcjach ale bezsensem według mnie jest implementowanie tych dwóch zachowań jako czegoś nie związanego ze sobą. Schemat działania w uproszczeniu wyglądał by tak: 1. Akcja Add kontrolera przekazuje listę pól do widoku i ten ubiera ją w kod HTML 2. Użytkownik wypełnia formularz i go wysyła. 3. Dane odbiera akcja Validate. Na podstawie listy pól sprawdza ona nadesłane dane. Jeśli są poprawne to przekazuje te dane do akcji Save. Jeśli jakieś dane nie są poprawne, to przypisuje do danego pola komunikat i listę przekazuje spowrotem do akcji Add, która wyświetla formularz wraz z komunikatami. 4. Akcja Save zapisuje dane w bazie danych. |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 219 Pomógł: 5 Dołączył: 18.07.2006 Skąd: Piekary Śląskie Ostrzeżenie: (0%) ![]() ![]() |
Możesz przechowywać w module listę pól formularza np. w postaci tablicy (przykład w uproszczeniu):
Po co mam mieć jakąś daremną tablicę skoro generowanie formularza mam zrobione 200 razy lepiej na obiektach. Poza tym takową tablicę też gdzieś trzeba generować. Pewnie jakiejś funkcji/metodzie. I wracamy do punktu wyjścia... w której warstwie tą metodę umieścić. Akurat to jak przechowywać pola formularza nie jest wogóle moim problemem. Odpowiedzi w tym temacie coraz bardziej przekonują mnie, że MVC wcale nie jest takie cudne i choć rozwiązuje problem z ładowaniem jak najmniejszej ilości kodu to prowokuje inne. Chyba zacznę opracowywać własne rozwiązanie, które zapożyczy z MVC jego najlepsze cechy a jednocześnie odrzuci ścisły rozdział na warstwy. Np. każdy formularz może być jedną klasą, w której formularz będzie w konstruktorze składany z odpowiednich klocków (pól). Będą tam metody, które go wyświetlą (widok), zwalidują (kontroler) i zapiszą (model). Wydaje się to dość rozsądne. Rozwiązanie takie pozwala na dużą przenośność takowego formularza pomiędzy projektami (wystarczy skopiować jeden plik). |
|
|
![]() ![]() |
![]() |
Aktualny czas: 14.10.2025 - 13:58 |