Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: MVC - wcale nie takie cudne?
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
cicik
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.

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ę.
cyphelf
Można tak:

1. AkcjaAdd - inicjalizacja formularza

2. AkcjaForm - budowanie i wyświetlanie formularza

2. AkcjaValidate - sprawdzanie poprawności danych

3. AkcjaSave - zapisywanie do bazy

I teraz tak. Użytkownik otwiera stronę dodawania elementu czyli w tym przypadku uruchomi akcję Add, która uruchomi akcję Form. Użytkownik wypełni formularz, wyśle go i dane trafią do akcji Validate. Gdy dane okażą się poprawne to zostaną przekazane do akcji Save. Jeśli nie będą poprawne to z odpowiednimi komunikatami zostaną przekazane spowrotem do akcji Form.

Edycja będzie wyglądała podobnie, tylko zamiast akcji Add będziemy mieć akcję Edit, ktora zainicjalizuje dane do edycji (np. wyciągnie je z bazy).

Akcja Save zaktualizuje lub wstawi dane, zależenie od tego czy jest określony numer ID rekordu czy nie.
cicik
Cytat(cyphelf @ 17.09.2006, 18:55:53 ) *
Można tak:

1. AkcjaAdd - inicjalizacja formularza

2. AkcjaForm - budowanie i wyświetlanie formularza

2. AkcjaValidate - sprawdzanie poprawności danych

3. AkcjaSave - zapisywanie do bazy


Można tak tylko w tym przypadku:

Ad2. Bedzie to wygladalo mnie wiecej tak:
echo("<input ...>");

Ad3. a to tak:
if(!is_null($dana1) && ...)

Takie rozwiazania sa w niektorych enginach ale mi sie to nie podoba bo za duzo roboty przy tym jest.
Ja mam obiekt klasy Form_Form posiadajacy dwie metody: construct() i waliduj().
Poniewaz obiekt ten jest potrzebny w dwoch przypadkach (wyswilanie i walidacja) wiec napisalem prosta metode, ktora buduje taki obiekt i go zwraca. I pytanie, w ktorej czesci MVC taka metoda ma byc umieszczona? Formularz jest generowany na podstawie danych z bazy (model), jest walidowany (akcja/kontroler), jest wyswietlany (widok).
NuLL
Przepraszam za krotko odpowiedziec na php PRO ;-)

A moze by tak kazda akcja to pojedyncza klasa, modul to katalog - i tyle smile.gif
cicik
Cytat(NuLL @ 17.09.2006, 20:10:30 ) *
Przepraszam za krotko odpowiedziec na php PRO ;-)

A moze by tak kazda akcja to pojedyncza klasa, modul to katalog - i tyle 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.
cyphelf
Cytat(cicik @ 17.09.2006, 18:35:10 ) *
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.
cicik
Cytat(cyphelf @ 17.09.2006, 20:44:40 ) *
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ą.
060156
W pelni podzielam Twoje uwagi o problemie, ktory opisales ..
Dlatego zastosowalem inne podjescie troche. Polega ono
na tym, ze dla kazdej zmiennej formularza mam druga zmienna
session ktora zawiera informacje o jego walidacji ...
Czyli robie submit formularza a service, ktory go processuje
ustawia zmienne walidacji oraz informacje ze jest blad
i formularze nie moze byc sprocessowany.
Na podstawie tych zmiennych sa wyswietlane informacje
o blednych polach w formularzu ...
pozdrawiam ..
cyphelf
Możesz przechowywać w module listę pól formularza np. w postaci tablicy (przykład w uproszczeniu):
  1. <?php 
  2. $form[] = array(
  3. 'nazwa_pola' => 'imie',
  4. 'typ_pola' => 'input_text',
  5. 'format_danych' => 'string',
  6. 'dlugosc' => 20,
  7. 'wartosc_pola' => '',
  8. );
  9. ?>



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.
cicik
Cytat(cyphelf @ 18.09.2006, 13:53:19 ) *
Możesz przechowywać w module listę pól formularza np. w postaci tablicy (przykład w uproszczeniu):
  1. <?php 
  2. $form[] = array(
  3. 'nazwa_pola' => 'imie',
  4. 'typ_pola' => 'input_text',
  5. 'format_danych' => 'string',
  6. 'dlugosc' => 20,
  7. 'wartosc_pola' => '',
  8. );
  9. ?>


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).
bela
Cytat(NuLL @ 17.09.2006, 20:10:30 ) *
Przepraszam za krotko odpowiedziec na php PRO ;-)

A moze by tak kazda akcja to pojedyncza klasa, modul to katalog - i tyle smile.gif

Ja preferuję rozwiązanie, że klasa to moduł, metoda to akcja. Wg mnie jest wygodniej bo nie trzeba za kazdym razem tworzyc pliku. A mówienie tu o wydajności jest po prostu smieszne, bo to groszowa sprawa. Mam w projekcie kontrolery po kilkaset linijek i nie zauwazylem zadnego wplywu dlugosci na szybkosc aplikacji, za to na szybkosc tworzenie widac wyraznie.

A co do głownego watku, chodzi o to gdzie umiejscowic walidowanie formularzy? Ja bym zaimplementował to jako intercepting filter, szczegolnie wersje implementacji jako dekorator jest bardzo sensowna. Temat o tym wzorcu kilka razy sie pojawial, sa w nim linki do blue printow suna i msdn. Zreszta po wpisaniu 'intercepting filter' w googlu dostaniesz te wyniki na samym początku.
cicik
Cytat(bela @ 18.09.2006, 17:48:36 ) *
A co do głownego watku, chodzi o to gdzie umiejscowic walidowanie formularzy?


Nie nie chodzilo o to.
Chodzi o to gdzie umiescic metode generujaca obiekt formularza.
Wydawalo mi sie, ze dosyc doglebnie to wyjasnilem.
hawk
Po co w ogóle metoda generująca obiekt formularza?
  1. <?php
  2. $form = new AddUserForm();
  3. ?>

Skoro formularz musi być używany w kilku miejscach aplikacji (wyświetlanie i walidacja), to zgodnie z OOP należy funkcjonalność zamknąć nie w osobną metodę, ale w osobną klasę.

Takie podejście jest również jak najbardziej zgodne z MVC. Przykład: Struts.
NuLL
@hawk - ty zyjesz smile.gif

@cinek - nie lepiej napisac wtyczke do szablonu - generowanie formularza to sprawa widoku wg mnie :-)
cicik
Cytat(NuLL @ 20.09.2006, 00:21:16 ) *
@cinek - nie lepiej napisac wtyczke do szablonu - generowanie formularza to sprawa widoku wg mnie :-)


Ale jego walidacja juz nie, a niektorzy lubia miec takie rzeczy kompleksowo zalatwione jednyhm obiekcie.
jezoo
jezeli chodzi o formularze to moze sie podepne, bo mam metode w sowjej klasie nastepujaca:
  1. <?php
  2. class JakasTam {
  3.  var $f = array();
  4.  
  5. public function Form() {
  6. ?>
  7. <form action="sm_install.php" method="post" onSubmit="return checkForm();" name="fI0">
  8. <input type="hidden" name="location" value="<?=$this->f[5]?>" />
  9.  
  10. <div class="InstHeader">Proszę podać wymagane dane do kontynuacji instalacji</div><br /><br />
  11.  
  12. <table align="center">
  13. <tr><th><?=$this->f[1];?></th><td align="center"><input type="text" name="<?=$this->f[1];?>" align="right"></td></tr>
  14. <tr><th><?=$this->f[2];?></th><td align="center"><input type="text" name="<?=$this->f[2];?>" align="right"></td></tr>
  15. <? if($this->f[3]==NULL || $this->f[3]==" "){
  16.  
  17. }else{?>
  18. <tr><th><?=$this->f[3];?></th><td align="center"><input type="text" name="<?=$this->f[3];?>" align="right"></td></tr>
  19. <? } ?>
  20. <tr><th><?=$this->f[4];?></th><td align="center"><input type="password" name="<?=$this->f[4];?>" align="right"></td></tr>
  21. <tr><td align="center" colspan="2"><input type="submit" value="Dalej"></td></tr>
  22. </table>
  23. </form>
  24. <?
  25. }
  26. }


i moj problem jest taki, ze moge jedynie wyswietlic tyle pol ile mam zdefiniowanych w metodzie, a wiec jezeli bede mial np:
  1. <?php
  2. $obiekt = new JakasTam();
  3.  
  4. $obiekt->f[1]="Costam1";
  5.  
  6. $obiekt->f[2]="Costam2";
  7. $obiekt->f[4]="Costam3";
  8. $obiekt->Form();
  9. ?>


to sila rzeczy wyswietli mi 3 pola, jak chce miec 4 to tylko uzupelniam f[3] i jes ok, i bul jest mianowicie taki, ze jak chce miec wiecej niz 4 pola to musze kolejne pola dopisywac w metodzie.

a moje pytanie jest takie, mozna zrobic w ten sposob zeby zdefiniowac ilosc tworzonych pol i ich typ, ale co z ich nazwami i etykietami?? to mnie zastanawia, w jaki sposob mozna taki problem rozwiac, bo szczerze mowiac, skrobanie <input type""> to juz mnie do oslabi a palce to mi posluszenstwa odmawiaja winksmiley.jpg
NuLL
Ja to rozwiazuje troche inaczej. Szablon wyglada tak - jest to kod XML a nie znaczniki Smarty czy cos winksmiley.jpg
  1. <form:start id='loginForm'>
  2. Login: <form:input name='login'><form:errorSpan for='login'><br/>
  3. Haslo: <form:password name='pass'><form:errorSpan for='pass'><br/>
  4. <form:checkbox name='remember'><label for='remember'>Zapamietaj mnie</label><br>
  5. <input type='submit' value='Go'>
  6. <:form:end>

Klasa akcji
  1. <?php
  2. class loginAction extends genericAction
  3. {
  4. public function perform()
  5. {
  6. if($this->input->login && $this->input->pass)
  7. {
  8.  //tu mnie zaloguj ;-]
  9. }
  10. }
  11. }
  12. ?>

I klucz programu czyli definicja danych przychodzacych z formularza
  1. <?php
  2. class loginFormInputDef extends inputDef
  3. {
  4. protected function buildIt()
  5. {
  6.  $this->setParameters('loginForm',iHttpRequest::POST);
  7.  
  8.  $this->addField('login',inputField::REQUIRED,array(inputField::STRING),array('min'=>3,'max'=>25);
  9.  $this->addField('pass',inputField::REQUIRED,array(inputField::ALPHANUMERIC),array('min'=>5);
  10.  $this->addField('remember',inputField::OPTIONAL,inputField::INTEGER,array('range'=>array(1,0));
  11. }
  12. }
  13. ?>

Klasa zwracajaca obiekt akcji zamiast samej akcji zwraca obiekt klasy actionWrapper, ktory zajmuje sie caloscia walidacji oraz przypisanie bledow oraz bylych wartosci do systemu formularzy. Calosc wykonuje sie automatycznie - jesli istnieje definicja danych forumularzowych i sa dane wyslane to nastepuje walidacja. Jesli akcja jest zdefiniowana tylko jako akcja ktora odbiera formularz actionWrapper w wypadku znalezienia bledow w walidacji wogole nie stworzy obiektu akcji ani tymbardziej nie uruchomi metody perform(). Nie wiem czy to zgodne z MVC czy nie - wg mnie blisko Rkingsmiley.png Korzystam z tego od dlugiego czasu i jest to swietna sprawa guitar.gif
macbirdie
cicik - nie wnikałem we wszystkie odpowiedzi, ale Twoje pytanie narzuca mi rozwiązanie kwestii podziału na model i widok w wykonaniu standardu XForms. W modelu jest wykaz wszystkich pól, określenie reguł walidacji, nadanie polom aliasów po których odwołujemy się w prezentacji. Prezentacja to już oczywiście opis, jak co ma na tym formularzu wyglądać i gdzie się znaleźć. Obejrzyj, przekontempluj, może Ci się coś nasunie. winksmiley.jpg
mihaup
Cytat(cyphelf @ 17.09.2006, 19:44:40 ) *
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.


Nic dodać, nic ująć:)
Sh4dow
Moje rozwiazanie działające od jakiegos czasu dosc wygodne, tylko nameczyłem sie zeby wszystko chodziło poprawnie

Dynamiczny formularz składa sie z 2 tablic w bazie danych
Pierwsza zawieraz dane o formularzu, druga zawiera dane formularza wpisane przez usera dla jakiegos ID naprzyklad dla user_id.
aby wygenerowac formularz potrzebujesz
  1. Identyfikator, wystarczy ID
  2. Opis, moze byc nazwa przy polu formularza, ale nie koniecznie, zalezy jak ci pasuje
  3. dane o validacji, string, int, select, dir() (to ostatnie to zdefiniowana funkcja do walidacji oraz do tworzenia danych dla pol np.select)
  4. default_value, czyli defaultowa wartosc pola jesli jest nie wypełnione lub aby przy dodawaniu nowego elementu przez formularz była jakaś wartość juz dodana, dla typu walidacji rexp albo date mozna wpisac wyzazenia okreslające wyrazenie regularne lub format dat, dla pola select mozna pisac poprostu uproszczona tablice z kluczami i wartosciami dla rozwijalnych menu lub radio butonów
  5. flaga określająca czy pole jest wymagane i bez jego poprawnego wypełnienia zwracamy błąd/wyjątek
  6. przy stringach lub intach mozna dodac pole o ich długości ale to zalezy jak komu wygodnie
druga tablica to proste
  1. user_id
  2. form_field_id
  3. form_field_value
sa dwie metody publiczne, jedna pobiera dane do generowania formularza dla wybranych ID lub dla wszystkich pól.
Wewnatrz metody prywatne pobieraja dane z tablic, parsuja wszystkie dane tworzac konkretna tablice. Druga metoda do pobierania danych dla danego user_id oraz dla wybranych lub wszystkich ID formularza.
Roznica miedzy tablicami jest taka ze druga ma wiecej o 2 pola, 'value' oraz 'real_value' pola roznia sie wtedy gdzi chodzi o pola typu select gdzie w tablicy łączonej mamy klucz tablicy z pola default_value, wtedy klucz 'real_value' posiada wartosc dla klucza który jest podany w polu 'default_value'. chyba zagmatwałem wiec juz tłumacze na przykładzie
dane tablicy łączonej:
Kod
user_id | form_field_id | form_field_value
       1|              1|                1

tablica z danymi formularza
Kod
id | name | validate | default_value | require | lenght
1 | 'test' | 'select' | 1 => 'test1';2 => 'test2';3 => 'test3'| 1 | null


metoda zwraca wartosci dla value => 1 a dla 'real_value' => 'test1'
oczywiscie musisz sie trzymac jakis standardów jakie sobie ustalisz, wtedy nie powinno byc problemów.

Drugą częścią jest jakiś moduł/funkcja w widoku która bedzie generowac z tej tablicy gotowy formularz. Ja wykonałem funkcje w smarty, gdzie podaje praktycznie 2 parametry, jeden to dane do wygenerowania pola, drugi parametr to flaga błędu, słuzy jedynie do graficznego zaznaczenia bledu, ktora jest nie wymagana wszedzie.

Trzeci element układanki to metoda Walidująca. Sa dwa sposoby, jeden to podac nazwe tablicy _POST w ktorej znajduja sie wysłane formularze, lub tez przekazac juz bezposrednio tablice. Podajesz tablice ID'ków ktore maja być poddane walidacji. Po walidacji otrzymujesz true lub false. Jesli true, uzywasz specjalnej metody ktora zwraca tablice ktora masz pozniej zapisac. Jesli masz false to masz metode zwracającą flagi dla ID'ków które sa błęde, oraz metode która zwróci ci tablice do generowania formularza z danymi ktore wpisal użytkownik.

To sa główne założenia całego obiektu, lub obiektów. Sposob walidacji, sprawdzania itd to kazdy ma swoje sposoby. To jest jeden, w miare uniwersalny sposob na walidacje, generowanie i ogolna obsluge takich formularzy. Odpowiedni panel moze zautomatyzowac ci do maxymum tworzenie generowanie i walidacje formularzy. Wszystko zalezy od tego kto co chce.
Zalety to mozliwosc definiowania gotowych metod walidujących, np gotowymi validacjami moga byc url, email, zip_code (jako kod pocztowy). Dodanie pola do formularza do dodanie kolejnego ID przy pobieraniu danych. Mozna tworzyc grupy pól, mozna dodac kolumne z opisem, komunikatem w przypadku błędu. Mozna generowac komunikat błędu na podstawie pola walidacji.
Wszystko w jednym. Okreslac ID'ki dla formularza, jesli akcja ma walidowac przekazujesz to do walidacji, jesli poprawnie zapis, jesli nie zrwacasz tablice do ponownego generowania. Jesli wyswietlasz formularz pobieraz dane dla formularza lub z tymi samymi idekami pobieraz dane dla danego powiedzmy user_id.

Tutaj problem nie dotyczy modelu MVC ale proby implementacji odpowiedniego rozwiązania.. Takie jest moje zdanie i sposob rozwiazanie tego powyzej. guitar.gif
ShaXbee
W swoim projekcie rozwiązałem to troszkę inaczej - jest klasa Entity posiadająca metody eupdate, insert, delete oraz mająca dekoratory - w tym Validator. Definiuję dla każdego rodzaju Entity własną klasę dziedziczącą po Validator i wszystko gra 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-2024 Invision Power Services, Inc.