MVC tervezési minta a gyakorlatban
Most tervezek egy komplexebb webalkalmazást és gondoltam, hogy utánajárok az MVC tervezési mintának.
Addig megvagyok, hogy van a controller, ami lényegében megmondja, hogy mit lehet csinálni a modellel a view pedig megjeleníti az adatokat.
Vegyünk egy konkrét példát:
Adott egy modul, ami a megrendelő feladást hivatott elvégezni. Ha jól értem, akkor a user kitölti a megrendelőlapot, majd post-olja az adatokat. Ekkor a front controller (index.php) azt mondja, hogy ok, ez a kérés megy a megrendelő modulhoz. A megrendelő modul tudja, hogy a kapott adatokat checkolni kell, tehát van egy adatellenőrző funkció.
Ami jelen esetben nekem még nem tiszta, hogy az adatellenőrzést végző rész az controller vagy action? (művelet: felhasználó post-ol, adatokon formai ellenőrzés végrehajtása, ha minden ok, akkor átadja az adatokat mentésre)
Ha ellenőrizve vannak az adatok, akkor mentésre kerül a megrendelés. Ez egy SOAP kérésként valósul meg. Ebben az esetben a SAOP kérés összeállítása az action vagy view? (művelet: a formailag helyes adatok mentése)
■ Addig megvagyok, hogy van a controller, ami lényegében megmondja, hogy mit lehet csinálni a modellel a view pedig megjeleníti az adatokat.
Vegyünk egy konkrét példát:
Adott egy modul, ami a megrendelő feladást hivatott elvégezni. Ha jól értem, akkor a user kitölti a megrendelőlapot, majd post-olja az adatokat. Ekkor a front controller (index.php) azt mondja, hogy ok, ez a kérés megy a megrendelő modulhoz. A megrendelő modul tudja, hogy a kapott adatokat checkolni kell, tehát van egy adatellenőrző funkció.
Ami jelen esetben nekem még nem tiszta, hogy az adatellenőrzést végző rész az controller vagy action? (művelet: felhasználó post-ol, adatokon formai ellenőrzés végrehajtása, ha minden ok, akkor átadja az adatokat mentésre)
Ha ellenőrizve vannak az adatok, akkor mentésre kerül a megrendelés. Ez egy SOAP kérésként valósul meg. Ebben az esetben a SAOP kérés összeállítása az action vagy view? (művelet: a formailag helyes adatok mentése)
MVC
action, view
Az action mint olyan, a controller része, vagyis a controller hajtja végre az action-t. A view semmi más, csak egy minta az oldal felépítésére, ebben nem történik semmi feldolgozás, csak kiírás a felhasználó felé. A model pedig a háttérben van, ilyen pl egy adatbázis absztrakciós réteg, de ezt igazából a controllerben használod fel (a modern mvc framework-ök már adatbázisból generálják a modelt, illetve tartalmaznak a legismertebb adatbázisokhoz valamilyen egyszerűsítő rendszert, pl. ORM-t, így itt semmit nem kell programozni). Nagyon leegyszerűsítve a dolgot, amibe programozni kell, adatbázist lekérdezéseket, fájl írásokat, stb végrehajtani, az mind a controller része, a megjelenítés pedig a view része (ez az adatokkal nem operál, mindent a controllertől kap, pl a lekérdezés eredményét egy tömbben).
Tudom ajánlani az elte php speciének oldalát, illetve ugyanitt egy egyszerű mvc rendszer felépítését bemutató példa.
Mielőtt az ember MVC tervezési mintával kezdene el dolgozni, szerintem érdemes ránézni a népszerű MVC-s keretrendszerekre, mint amilyen a Symfony és a CakePHP.
Az elvet értem, de a konkrétumokat nem
Nem igazán tudom eldönteni, hogy adott esetben mi hova tartozik. A view ugye az adatok megjelenítése. Egy megrendelő adataiból pdf készítése, az most view vagy action?
Az adatok validálása egy action vagy a model feladata? És a model egyáltalán micsoda, az adat amit DB-ből lekérek vagy egy egész DB kezelő réteg és a model kimenete az adat?
Az adatok mentése a controller vagy a model feladata? Tehát egy action végzi a mentést (sql_query) vagy a model-nek van egy olyan metódusa, ami a mentést végzi? A model egy adatcsokorként fogható fel vagy egy objektumként, aminek vannak tulajdonságai és metódusai. És ebből következően a tulajdonságokhoz a metódusokon keresztül fér hozzá a controller?
Szóval nem igazán tiszta, hogy a model az most csak az adat, vagy az adat és az adat elérését megvalósító műveletek együttese? Mert ha az utóbbi, akkor a model nem pusztán az amin műveletet végzünk, hanem a művelet már maga (ezt most jól megaszontam, de remélem érthető, hogy mit akarok mondani) amit elvileg a controllernek kellene csinálni, mivel ő végzi a feladatokat az adatokon.
A controller valójában micsoda? Mert ha az action a controller része - adott esetben egy metódusa -, akkor hogyan kerül meghívásra a controller? Vagy a controller, az csak egy osztály és az action-ök a metódusok? De akkor minek nevezzük azt a részt ami meghívja az action-öket, ha a controller valójában csak egy tároló?
konkrétumok
A view csak és kizárólag a felhasználó böngészője felé küldött megjelenési minta. A pdf készítés így a controller feladata (pl. Symfony DomPDF).
Az adatok validálása megintcsak a controller feladata, még akkor is ha a framework mondjuk a model definiálásánál ad lehetőséget ennek beállítására (ekkor hozzágenerálja a control-hoz a megfelelő validáló függvényeket).
Egyébként szerintem akkor könnyű megérteni, ha egy egyszerű (egyszerűsített) példát nézünk Symfony-ban:
Help oldal lekérdezése (máshol mondjuk help.php-nak felel meg :))
1. index.php-nak megy a kérés a help oldal meghívására
2. index.php futtatja a controller executeHelp() függvényét
3. executeHelp() függvény lekérdez az adatbázisból néhány infót (az adatbázisból lekérdezéshez a model adatbázislekérdező függvényeit használja, a biztonsággal, pl. injection-ök elleni védelemmel, nem foglalkozik, a modelbe ez szépen be van építve)
4. executeHelp() a lekérdezett információt beteszi néhány változóba, fogadja mondjuk a post és get adatokat, ezeket is változókba teszi és az egészet átdobja a viewnak, ami az átadott változók segítségével megjeleníti az oldalt
5. ha az oldalon van mondjuk egy "pdf generálása a helpből" link, akkor az egy másik action-re mutat (máshol mondjuk pdf.php?out=help")
6. erre kattintva megint az index.php kapja el a kérést, átirányítja az executePdf() action felé az egészet
7. executePdf() legyártja a pdf-et és pdf kimenettel tér vissza (a pdf tartalmát megkaphatta mondjuk postolt adatként a help oldalról; vagy újra lekérdezhette maga is az adatokat; esetleg egy view sémája alapján gyártja)
Szerintem segíthet az ha megnézed a Symfony book model-ről és view-ról szóló fejezeteit, akár csak a főcímeket. Ez sokat elárul, hogy mi van az egyes rétegekben. Minden más a controllerben van, arra a könyv több fejezetben tér ki külön.
Alakul
Jól látom a helyzetet?
mvc
Hat,
Ezen kivul meg ezeknek a rendszereknek lenyeges kulonbsege a klasszikus mvc-hez kepest, hogy mig utobbi egy haromszoget kepez a kapcsolatokbol (m - v, v - c, c - m), addig az elobbiek nem (jellemzoen: m - c - v).
A tapasztalat, es szokas alapjan a kovetkezoket lehet javasolni:
A view egyeduli feladata - ahogy masok is irtak - , hogy a kapott adatokbol (fontos, hogy kapott, nem pedig szerzett) keszitsen valamilyen kimenetet (html, pdf, jpg, xml, fustjel, stb).
Az controller dolga a felhasznalo keres fogadasa, a keres validalasa (rossz adatok eseten hibajelzes), esetleg az adatokat olyan formara hozni, hogy az uzleti retegnek megfelelo legyen, a keres alapjan az uzleti reteg utasitasa a muvelet vegrehajtasara (az esetleges hibak kezelese, visszajelzes a felhasznalo fele), es vegul az uzleti retegtol kapott adatokat tovabbitani a view fele. Osszegezve: adat ellenorzes, es keres delegalas a dolga.
Vegul a model dolga a rendszer megvalositasa, magyaran o az uzleti reteg, az uzleti logika. Nincs semmi eloiras, hogy milyen formaban kell adatokat prezentalnia, lehet az valami eredmeny halmaz szeru dolog, de lehet objektum is. Fontos megjegyezni, hogy az uzleti logikaban nem szerencses olyan kodot elhelyezni, ami arra szamit, hogy weben lesz hasznalva (gyk: semmi request objektum, v hasonlok). Majd a controller szepen transzformalja a keresek adatait olyan formara, ami az uzleti retegnek jo. Meg egy gondolat a modelhez: celszeru funkcionalis egysegeket kepezni, amiket egy objektummal (uzleti homlokzat) prezentalunk. Mindenki (akar mas ilyen funkcionalis egyseg is) csak ezen a homlokzaton keresztul kommunikalhat ezzel a funkcionalis egyseggel. Ezzel egyreszt elerjuk azt, hogy a controller kodja tiszta lesz, masreszt lazulnak a kotesek a programban, ami konnyebb modosithatosagot, konnyebb hibajavitast vonz magaval.
Bonyolódunk :-)
Ezzel szemben - azt mondod - a mai keretrendszerekben a controller lesz a legvastagabb réteg, mert az egyes alfunkciókat action-ök személyében valósítja meg és a model-t csak adathozzáférésként használja.
Nos a kettő közül melyik a jobb? Melyiket érdemes használni? Eldönthető-e, hogy jobb-e egyik a másiknál vagy ez a programozó hozzáállásán múlik, hogy neki mi a szimpatikusabb?
A különbség ott látszik, hogy Drawain megoldásában a PDF-generálás action, míg a klasszikus MVC szerint (ha jól értettem) ez view, mert adatmegjelenítés.
UpDate:
Ha jól értem a két megközelítés között a különbséget, akkor:
Klasszikus MVC:
A SOAP kérés küldése a felhasználó által megadott adatok alapján (megrendelő feladás) a model feladata.
Front controller:
A SOAP kérés a controller egy action-je.
Nos,
Publikus oldal
Adminisztrativ oldal:
A pelda nyilvan nem torekszik a tokeletessegre, csak a mogottes mentalitast probalja bemutatni. Lathato, hogy az actionok relative egyszeruek (csak 1-1 fuggveny hivas talalhato forummal kapcsolatban), a tenyleges munkat a Forum vegzi.
Termeszetesen nincs jobb. A ketto kozott nincs olyan eles hatar, mint amit en sugalltam, ugy latszik itt egy kicsit felrevezeto voltam. Mindig azt kell csinalni, amit a jozan esz megkovetel.
Igen, en azon a velemenyen vagyok, hogy a PDF kimenet letrehozasa kizarolag a view feladata, a controllernek ehhez semmi koze. Latvanyos pelda erre a Spring MVC, aminel csupan konfiguracio segitsegevel valtogathatom a kulonbozo view megvalositasok. Ehhez a rugalmassaghoz viszont szukseges, hogy a controller a view-al kapcsolatban csak annyit varjon el, hogy a megadott adatokat fogadja.
A SOAP kérés küldése a felhasználó által megadott adatok alapján (megrendelő feladás) a model feladata.
Front controller:
A SOAP kérés a controller egy action-je.
Nem, asszem altalaban a model feladata lehet egy SOAP keres elkuldese, bar egyertelmu kijelentest nem szeretnek tennek. Lehet olyan faramuci megoldas, hogy az akcio fogad egy valamilyen kerest, es azt a kerest SOAP-al tovabbitja valahova mashova.
Ajanlom figyelmedbe a kovetkezo ket linket:
Ahogy korabban irtam, nincs olyan eles hatar, mint amit te sejtesz.
Publikus vs adminisztratív
Hat,
nem elég precíz
Itt, a view réteg gyakorlatilag template fájlokból áll, így nem végez konkrét számítási feladatot, ami pl egy pdf generálásnál jóljön - itt a controller action-jében valósítjuk meg.
A model pedig egy absztrakciós réteg, hátteret és alapfüggvényeket képez a feldolgozás során a web-alkalmazás teljes adatállományához (itt pl olyan függvények adhatóak meg, hogy az adatbázisból kiolvasott Vezeték- és Keresztnév páros a Név függvényhívásra Vezeték+Keresztnév formában adódjon át a controllernek).
A SOAP kérés megvalósítása, mivel egy adatcseréről van szó, a model feladata.
Összefoglalnám
VIEW
- Adatokat vár
- A kapott adatokat megjeleníti
Van egy bemenete és egy kimenete, de a dobozban semmi művelet nem történik (csak az adat megjelenítéséhez szükséges műveletek, a model-nek közvetlenül nem ad parancsot adatmanipulációra).
CONTROLLER
- User-től adatokat kap
- User-től "parancsot" kap (public action)
- Ha szükséges, a kapott adatokat validálja (private action)
- MODEL-nek megmondja, hogy mi a parancs (az adatokat átadja megfelelő formában) (private action)
- MODEL-től kérhet adatokat (private action)
- VIEW-nak odaadja a MODEL által szolgálltatott (és egyéb) adatokat (private action)
Van egy bemenete, ahol adatokat és parancsot kap. Kétirányú kommunikáció a MODEL-lel. Egyirányú kommunikáció a VIEW-val.
MODEL
- Közvetlen hozzáférése van az adatokhoz
- Rendelkezik műveletekkel, melyeket az adatokon hajt végre
- Adatokat szolgáltat megfelelő formában
- Van egy fix interface-e, amin keresztül kommunikál vele a CONTROLLER
Közvetlenül hozzáfér az adatokhoz (DB kezelés, stb.), oda-vissza kommunikál a CONTROLLER-rel.
Legvastagabb réteg a MODEL, ő dolgozik a CONTROLLER dirigál a VIEW pedig infót ad a munkáról.
Kis pontositas
Az adatfolyam kétirányú
BBCode értelmezőt hova?
UpDate: Én a helper-re szavazok. Kinek mi a véleménye?
Nézet
Tényleg nem
A PDF esetében a vezérlőnek csak annyit szabad tennie, hogy kiolvassa a modellből az adatot és azt továbbadja a nézetnek, legyen az bármi is. Ha egy PDF nézetről van szó, akkor az – minden szükséges számítással együtt – létrehoz egy kimenetet.
Én most Zend Frameworkben úgy dolgozok, hogy elég létrehoznom egy új nézet fájlt pdf kiterjesztéssel és máris elérhető az adott művelet PDF kimenettel.
Megjelenítési logika
Hol vastag
Több view
Mivel
Az oldal összeállítása, de hol?
A probléma itt kezdődik. Tegyük fel, hogy egy felhasználói kérésre adandó az oldal tartalmi részére egy táblázat.
Ekkor:
Ez mindaddig ok, amíg az adatokat HTML-ként kell visszaadni. A gond akkor van, ha pl. egy XML-t kell adni a user-nek és csak azt, nem kell layout generálás.
Ha nem egy HTML kimenet lesz a view eredménye, hanem egy XML, PDF, CSV, stb. akkor én jelen pillanatban két megoldást látok:
Ennek hátránya, hogy ha változik pl. a layout generálást végző osztály (változó) neve, akkor minden egyes modulban át kell írni. Előnye, hogy csak azon felhasználói kéréseknél adom ki a layout-ot ahol tényleg az oldalt kell megjeleníteni.
Tehát a kérdésem az, hogy a kettő közül melyik a jobb megközelítés, esetleg van-e egy (vagy több) jó (jobb) alternatíva?
Kimenet, templatezés
Nyilván, nem tudod egy nagy MVC-vel lefedni az egész programlogikát. Én úgy képzelem el, hogy elsőként ki kell találnod, mit is szeretnél pontosan. Azaz, az URL alapján elő kell vadásznod, melyik controllert is szeretnéd Te most használni (blog, nyitólap, stb. vagy ahogy tetszik). Ez a controller (kis MVC) találja majd ki, hogy milyen kimenetet kell adni a viewnak és vadássza össze a megfelelő model-eket.
Tovább is bonthatod, betöltesz egy konfigurációs állományt, ami meghatározza, milyen még kissebb MVC-ket kell berántani (legújabb fórum hozzászólások, legújabb bejegyzések, szöveges tartalom, stb.) és ezeknek megint csak lehet egy kis V-jük, hogy a saját megjelenésüket szabályozzák. Innentől kezdve pedig egy struktúraként kezeled az egészet, nem egy nagy monolitikus rendszerként. Azaz, földaraboltad ehető részekre a problémát.
Elképezlés
Ez eddig tiszta sor.
Ezt csinálja a Front Controller az index.php-ben, ami behúzza a megfelelő modul-t (amiben az MVC logika van).
Ez is tiszta sor, mert az felhasználói kéréstől függően lesz kiválasztva a view (a felhasználói kéréshez kapcsolódó view, pl. egy táblázat generálása).
Viszont a fent említett probléma él, tehát a program végén állítsam össze az oldalt, ha kell (a modul view-ja egy változóba tolja a kimenetet, ami aztán a layout-ba kerül behelyettesítésre), vagy az egyes modulokban és akkor tudom szabályozni, hogy most kell html layout-ot megjeleníteni vagy sem (az egyes action-ökben). Az exit()-es megoldása azért nem tűnik barátságosnak, mert ha az action végén megszakítom a script futását, akkor adott esetben a program végén található kód nem fut le.
Nézetben vagy különböző elrendezések
Azonban sokkal inkább követi a minta szellemiségét, ha elrendezésből is többfélét gyártasz – ebben az esetben lesz egy layout.html-ed és egy layout.xml-ed, és ezt is a paraméter alapján szolgálod ki. Ha pedig adott típusú nézethez nincs elrendezés, akkor nem szolgálsz ki.
Kikapcs
Ez nem teljesen tiszta.
Az elképzelésem az, hogy van egy template engine (ez jelen esetben saját megoldás lesz), amivel megvalósítom a layout kezelést. Tehát indul a script, inicializálja a layout objektumot, majd beilleszti az oldal egyes részeit (html head, menü, stb.) a template-be (tpl változó hozzárendelések). Ezután a vezérlés átkerül az adott modulhoz. Ott a controller dirigál, adatokat kér a model-től, majd odaadja a view-nak. A view visszaad egy string-et (html generálás esetén), amit megkap a script végén a layout objektum és végül megjeleníti az oldalt. A fenti layout kikapcs fonalon elindulva, ha XML-t kell generálni, akkor
Konkrétabban
MVC V nélkül
Hogy konkrét legyek, egy Session Manager-t csinálnok, de nem igazán van szükség VIEW-ra, mert ami a felhasználó felé megy infó, azt a Session Manager-t használó modul generálja (már amikor szükség van infó küldésre).
Re: MVC V nélkül
Na, sok a rizsa a lenyeg: nem kovetsz el eretnekseget, ha csak nincs view.
Miért nem MVDC?
Mondok egy példát:
Vannak júzerek, ezeket listázzuk. Bizonyos júzereken módosításokat végzünk. Ezeket a módosított elemeket összegyűjtük egy tömbbe, és továbbítjuk a hozzájuk tartozó dao-nak, ami elvégzi a módosításokat.
Ehhez van egy Controller, ami továbbítja a Model-nek a módosítandókra vonatkozó adatokat. A Model ezek alapján lekéri a Data-tól a megfelelő sorokat, az egyes sorokból pedig user objektumokat készít, vagy csinálsz egy users objektumot, kinek hogy tetszik. Utána a Model meghívja az users objektumon a módosításért felelős függvényt, és átadja neki a módosítással kapcsolatos adatokat, amiket a Controllertől kapott. Az userek módosulnak, ezután a Model hívja a Data-t a módosítások mentésére.
A Data és a Model között is van egy réteg. Egyrészt erre azért van szükség, mert a Modelben használt formája és a tárolási formája az adatnak eltérő, ezért nyilván konvertálni kell. Ez úgy megy, hogy mondjuk egy user lekérésnél a Data létrehoz egy user objektumot, és ennek a setter függvényeivel beállítja a megfelelő értékeket.
Egyébként ti hova raknátok az oldalak kesselését.
Itt arra gondolok, hogy mondjuk mi van, ha a View generál egy oldalt, és azt lementitek adatbázisban, aztán a következő lekérésre már az adatbázisból olvassa ki az oldal. Ezt a cache kódot ti hova sorolnátok?
A kérdés érdekessége, hogy adatbázis lekérés(Data) mellett nincsen üzleti logika (Model), a megjelenítéshez tartozik (View), és elvileg a Controllernek kéne ellenőrizni, hogy van e az adatbázisban cache bejegyzés.
Persze erre is rá lehet erőltetni egy MVC mintát, de elvileg a kesselésnek semmi köze nincs az üzleti logikához. Szerintem úgy több értelme van, ha a Model dolgát a Controller veszi át, és ő kéri le a Data-tól az adatot, a View pedig csak egy sima echo.
Erről mi a véleményetek?
Best MVC Practices
Best MVC Practices
5 évvel később
Az MVC-t nagyjából úgy kell kezelni, mintha azt mondanánk, hogy autó. Az autónak is vannak jól elkülönülő részei, de hogy ki miként valósítja meg, tesz-e hozzá, vesz-e el belőle, az csakis a készítő egyedi gondolkodás(módj)ának és a megvalósítandó célnak (pl. városi, kis fogasztású autó, offroad járgány, stb.) a függvénye.
Az MVC egy laza elv, aminek
Egy link