Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MVC]Kontroler-Model-Widok
Forum PHP.pl > Forum > PHP > Object-oriented programming
MateuszS
Hey, mam pytania odnosnie MVC, zastanawiam sie czy kontroler i model ma dostep do widoku czy sam kontroler
http://athlan.pl/wp-content/uploads/mvc-model.png
czy
http://sysdm.googlecode.com/files/mvc.png

Kolejne pytanie: jak wyglada struktura folderow takiej aplikacji? I czy jest zalezna od powyzszych zaleznosci pomiedzy widokiem a kontrolerem i modelem?
I następne: takie proste sprawdzenie czy formularz zostal wyslany (nie chodzi o walidacje) czy nie ma byc obslugiwane w kontrolerze czy modelu?
No to jeszcze jedno: mam ksiazeczke i tam jest takie cos jak router i dispatcher, ale oczywiscie jest tam 100 linijek kodu i zero zrozumialego opisu, moglby ktos wyjasnik do czego sluza?

Nie sklamie jezeli powiem ze przelecialem juz wszystkie arty w naszym ukochanym polskim internecie ale procz zawilej teorii nie znalazlem odpowiedzi na te pytania, pozdrawiam
LBO
Router - tłumaczy dane wejściowe użytkownika - np. URL albo opcje z konsoli - i mapuje je na kontroler/akcję i parametry do wywołania.
Dispatcher - bierze te przetłumaczone dane i mapuje je na konkretne wywołanie klas/metod w systemie. To on w dużej mierze odpowiada za workflow. Teoretycznie podmieniając Dispatcher np. w takim ZF możesz sprawić, że akcje będą samodzielnymi klasami, a nie metodami klasy kontrolera.


c.d.

Jest jedna zasada - w żadnym wypadku model nie powinien nic wiedzieć o widoku. To dwa różne światy <kropka>.

W drugą mańkę jest trochę inaczej - są jakby 2 szkoły. Jedna twierdzi, że widok też nie powinien mieć dostępu do samego modelu, a tylko do danych z niego pobranych. Druga, że to nic nie przeszkadza stąd np. twory a'la ModelAndView w Springu (Javowy framework).

Nie podłączę się pod żaden z tych nurtów, bo zwyczajnie nie mam ochoty o tym dyskutować. Mogę jedynie stwierdzić, że im bardziej projektanci trzymają się czystego MVC (1-wsza szkoła) tym więcej pracy - duuużo więcej kodu - się z tym wiążę,a le jest to mniej elastyczne. Trzeba znaleźć złoty środek, albo kierować się głową przy doborze technologii do projektu.
MateuszS
Napisales jak goscie na kursach biggrin.gif nie wiele z tego zrozumialem, bez urazy :]

Czyli wg ciebie dobry jest schemat 2 ktory wyslalem? A jak z katalogami i ich zawartoscia?
LBO
Wg mnie 1-wszy lepiej oddaje sens MVC.

Co do katalogów to niewiele Ci powiem - przejrzyj Symfony, Agavi, ZF i np. Kohanę. Zobacz, które najlepiej Tobie pasuje etc.

P.S.

Popraw link w stopce.
Crozin
Co do różnych wariacji wzorca MVC: Temat: MVC Kontroler gdzie - jest sporo o tym jak ten MVC w "środowiskach webowych" wygląda/mógłby wyglądać.

Tutaj jest prosty i bardzo czytelny schemat działania MVC: http://upload.wikimedia.org/wikipedia/comm...llerDiagram.svg - w podlinkowanym wątku masz komentarz do tego obrazu.

Cytat
Napisales jak goscie na kursach nie wiele z tego zrozumialem, bez urazy :]
No to jeszcze raz...

Router
W dużym skrócie: pobiera jakieś dane, przetwarza je i zwraca "surowe" dane uzyskane w procesie przetwarzania. Przykładowo taki router może rozpoznawać adresy URL i na ich podstawie określać co ma być wywołane (coś jak Apatche'owy moduł rewrite).
Czyli router dostaje przykładowo dane: Temat: MVCKontroler Model Widok i na tej podstawie zwraca nam dane przykładowo:
Kod
controller: thread
action: index
lang: pl_PL
params:
  id: 4868


Dispatcher
Po edycji: Dispatcher zasadniczo odpowiedzialny jest za to by wywołać akcję (czyli korzystając z ReflectionAPI czy czegoś w stylu (niezbyt ładne)
  1. $controller = 'Abc'; $action = 'Def';
  2. $c = new $controller();
  3. $c->$action();


EDIT:
Jeszcze zapomniałem wspomnieć o strukturze katalogów. Generalnie to... jak Ci jest wygodniej. Warto tylko pamiętać by część danych była jednak jakoś rozdzielona. Czyli w miarę w jednym miejscu trzymasz sobie różne modele, gdzie indziej kontrolery, gdzie indziej jakieś biblioteki (chodzi o kod jakiś Doctrineów, Propelów, Swiftów, Symfonów, Zend Frameworków itp. itd.). Dobrze by też było by kod aplikacji był poza public_html - czyli w public_html trzymasz sobie jakieś obrazy, arkusze stylów, pliki JS. Trzymasz też jeden prosty plik PHP, który uruchamia całą aplikację - może on wyglądać nawet tak:
  1. <?
  2.  
  3. require_once '..........';
  4.  
  5. $dispatcher = new \MyProject\Dispatcher();
  6. $dispatcher->run();

MateuszS
no wlasnie, dazylem do stworzenia takiej aplikacji, ktora uruchamialbym w indexie tak jak pokazales Crozin, zwyklym wywolaniem jednej metody, jednak nie bardzo mi wychodzilo, bo musze jakos polaczyc ze soba config, widok, zeby dostep do bazy miala kazda klasa itp itp. no i zeby to mialo rece i nogi. W duzych aplikacjach MVC trzeba korzystac z routera i dispatchera?
LBO
Crozin, jak dla mnie, pomieszałeś trochę dispatcher z front controllerem. Dispatcher nie robi tylu rzeczy, nie powinien.
Zasadniczo on ma tylko wywołać akcję.
Crozin
Cytat
zeby dostep do bazy miala kazda klasa itp itp.
I wtedy byś cały sens MVC poszedł by się...
Cytat
W duzych aplikacjach MVC trzeba korzystac z routera i dispatchera?
I tak stworzysz coś co będzie pełniło rolę wspomnianego - może co najwyżej nie będzie to jawnie nazwane Routerem/Dispatcherem, ale będzie pełnić ich funkcje.

@LBO: A rzeczywiście pomyliłem... (żeby nie było: przypadek :]).
MateuszS
zaczynam kumac, zaczalem czytac tematy, ktore zapodal Crozin i sie zastanawiam czy model ma generowac odpowiedni widok czy model ma zwracac wartosci do kontrolera, ktory to bedzie generowal widok?

I rozumiem ze role kontrolera moze pelnic kilka klas, jedna np, przy wysylaniu jednego formularza, inna drugiego, jeszcze inna przejecia jakiegos GET'a?
-=Peter=-
I tak, i nie. Zazwyczaj we frameworkach jest tak, że jest jeden główny kontroler (FrontController), dyspozytor na podstawie parametrów routingu tworzy obiekt akcji (który też jest kontrolerem) i odpala jedną z metod tego obiektu.
MateuszS
Cytat
dyspozytor na podstawie parametrów routingu tworzy obiekt akcji (który też jest kontrolerem)

Nie bardzo wiem o co chodzi z tym...

a ten FrontController to ten guru, co wczytuje caly config (polaczenie z baza itp), jakos tak?
skowron-line
Masz sobie link który wygląda powiedzmy tak.
Kod
index.php?controller=users&action=edit&id=1

I dispatcher utworzy obiekt klasy users i wywoła metode edit z parametrem. To tak w wielkim skrócie.

  1. class users {
  2. public function edit($id)
  3. {
  4. //
  5. }
  6. }
LBO
Tylko, żeby było jasne - to Router (a raczej różne klasy Routera trzymające się interfejsu Routera) tłumaczy URL

Kod
index.php?controller=users&action=edit&id=1


lub pretty URL

Kod
/users/edit/1


lub nawet wywołanie z konsoli

Kod
--controller="users" --action="edit" --id=1


a dopiero z tego Routera Dispatcher pobiera wszelkie dane.

Dispatcher też może posiadać swoje wyspecjalizowane klasy i tak jeden rodzaj Dispatchera wywoła akcję tak jak podał @skowron, a inny może wywołać:

  1. /**
  2.  * Klasa edit w folderze "users"
  3.  */
  4. class Edit extend Action
  5. {
  6. public function execute()
  7. {
  8. $id = $this->getParameter('id');
  9. // reszta
  10. }
  11. }
MateuszS
Rozumiem juz chyba jak wygladaja zaleznosci pomiedzy modelem, kontrolerem i widokiem, ale router i dispatcher... troche to zamotane, heh, macie moze jakas mala aplikacje napisana w MVC, (cos malego) jakis dobry kod do analizy? Niestety na necie cienko z tym. Najwiecej sie naucze analizujac kod. Pozdrawiam
pablo89pl
Np. obadaj sobie jka to wygląda w Kohanie www.kohanaphp.com smile.gif
Powodzenia
skowron-line
http://samuelsjoberg.com/archive/2007/01/url-dispatcher <- 3 wynik w guuglu.
MateuszS
skomplikowana ta klasa dispatchera w tym co podałeś skowron-line, chyba puki co nie bede korzystal z routera/dispatchera, albo jak ktos gdzies wspomnial, bede korzystal nieswiadomie ;] pablo89pl, nie lubie frameworkow, nie lubie sobie ulatwiac w ten sposob zycia ;] To jak z jquery, mimo fajnych efektow, latwego uzycia, wole sie nauczyc od podstaw, czystego JS, a potem skorzystac z frameworkow, tak samo w PHP, choć nie wiem czy to jest podobnie z tym. Pozdro
LBO
Źle myślisz. zamiast uczyć się nowych technik i dobrych praktyk, będziesz się utrwalał w swoim programistycznym - zazwyczaj bardzo wąskim - światopoglądzie.
MateuszS
Nie wiem jak rozwiazac problem, chce metoda __autoload pobrac wszystkie klasy tak aby byl dostep do ich obiektow z innych klas, jednak ta metoda magiczna uaktywnia sie przy wywolaniu obiektu,

  1. function __autoload($filename) {
  2. require_once(CONTROLLERS . $filename . FCLASS);
  3. require_once(MODELS . $filename . FCLASS);
  4. require_once(VIEW . $filename . FCLASS);
  5. }
  6. $ob = new homePage;


tym sposobem pobierze klase z folderu kontrolerow ale potem zechce pobrac z modeli i wywali blad bo nie ma takiej samej klasy w folderze models co controllers, rozwiazalem to tym sposobem

  1. function __autoload($filename) {
  2. if(require_once(CONTROLLERS . $filename . FCLASS)) return true;
  3. if(require_once(MODELS . $filename . FCLASS)) return true;
  4. if(require_once(VIEW . $filename . FCLASS)) return true;
  5. }


No i moje pytanie, czy jest to poprawne? Mozna tak robic? Jezeli nie, to jakie jest lepsze wyjscie? Zgodnie z zalozeniem MVC musze miec dostep do klasy modeli z poziomu kontrolerow i do widoku z poziomu kontrolerow.
Crozin
1) Sugerowałbym skorzystać z przestrzeni nazw, żeby mieć chociaż trochę porządku w nazewnictwie
2) Funkcja __autoload() jest uruchamiana za każdym razem gdy próbujesz użyć klasy, która nie istnieje. Więc każdorazowo powinieneś na podstawie jakiś tam kryteriów wczytać (o ile to potrzebne) z odpowiedniego katalogu plik z definicją klasy.
MateuszS
wydaje mi sie ze z nazewnictwem nie jest zle, zrobilem sobie taki config ze stalymi

  1. /* Glowna sciezka do aplikacji */
  2. define("ROOT", realpath(dirname(__FILE__) . "/../../"));
  3.  
  4.  
  5. /* Klasy kontrolerow */
  6. define("CONTROLLERS", ROOT . "/app/controllers/");
  7.  
  8.  
  9. /* Klasy modeli */
  10. define("MODELS", ROOT . "/app/models/");
  11.  
  12.  
  13. /* Klasy widoku */
  14. define("VIEW", ROOT. "/app/view/");
  15.  
  16.  
  17. /* Koncowka pliku klasy */
  18. define("FCLASS", ".class.php");


i w sumie __autoload() dziala elegancko, moge sie teraz odwolac do dowolnej klasy w kazdej klasie ktorej chce (oczywiscie oby tylko zgodnie z MVC)

//02.03

Hey, postanowiłem coś SPRÓBOWAĆ napisać w oparciu o MVC, puki co mam VC, napisałem bardzo prosty system wybierania szablonu, ustawiania i uruchamiania aplikacji, wiadomo, teraz na nic się to nie nada, ale chodzi mi to o samą metodę a raczej metody, czy dobrze są ustawione, czy kontroler dobrze jest napisany itp. Jezeli cos jest zle, a pewnie tak, to prosze o jakies podpowiedzi jak to poprawic. Po poprawie dorzuce model. Pozdro

index.php
  1. <?php
  2.  
  3. require_once("app/config/config.php");
  4.  
  5. function __autoload($filename) {
  6. if(require_once(CONTROLLERS . $filename . FCLASS)) return true;
  7. if(require_once(MODELS . $filename . FCLASS)) return true;
  8. if(require_once(VIEW . $filename . FCLASS)) return true;
  9. }
  10.  
  11. try {
  12.  
  13. $ob = new Controller();
  14. $ob->run();
  15.  
  16.  
  17. } catch(Exception $e) {
  18. echo "Blad: ".$e->getMessage();
  19. }
  20. ?>


app/controllers/ViewController.class.php
  1. <?php
  2.  
  3. class viewController
  4. {
  5. public $themeFolder;
  6. public $themeDirectory;
  7.  
  8. public function theme($folder)
  9. {
  10. $dir = VIEW . $folder;
  11. if(@!opendir($dir))
  12. throw new Exception("Nie ma stylow w podanym folderze");
  13.  
  14. $this->themeFolder = $folder;
  15. $this->themeDirectory = $dir;
  16.  
  17. }
  18.  
  19. public function getTheme()
  20. {
  21. return $this->themeFolder;
  22. }
  23.  
  24. public function getThemeDir()
  25. {
  26. return $this->themeDirectory;
  27. }
  28.  
  29. public function display($file)
  30. {
  31. if(@!include($this->getThemeDir() . "/" . $file))
  32. throw new Exception("Nie znaleziono pliku widoku (".$file.")");
  33. }
  34.  
  35. }
  36.  
  37. ?>


app/controllers/Controller.class.php (to moglbym wrzucic do jakiegos folderu Core np. ale czekam puki co na opinie
  1. <?php
  2.  
  3. class Controller
  4. {
  5. public $model;
  6. public $view;
  7.  
  8. public function __construct()
  9. {
  10. $this->view = new viewController;
  11. // + obiekt modelu
  12. }
  13.  
  14. public function setTheme()
  15. {
  16. $this->view->theme("theme1");
  17. }
  18.  
  19. public function setHome()
  20. {
  21. $this->view->display("form.phtml");
  22. }
  23.  
  24. public function run()
  25. {
  26. $this->setTheme();
  27. $this->setHome();
  28.  
  29. }
  30.  
  31. }
  32.  
  33. ?>


app/view/theme1/form.phtml
  1. <form action="index.php" method="POST">
  2. <input type="submit" name="wyslij" value="Zaloguj" />
  3. </form>
marcio
W klasie controller masz metode run() ktora wywoluje 2 publiczne metody ale je daj na protected lub private jesli klasa ma byc "final" bo jak nie to sie mija z celem.
Modelu i widoku raczej nie ustawiaj na sztywno do jednego atrybutu jak cos daj chociac do array zebys mogl korzystac z kilku modeli jesli bedzie taka potrzeba.
MateuszS
Jak dam run() protected to chyba nie bede mogl jej wywolac z poza klasy nie? a przeciez musze ja wywolac poza klasa.
marcio
Cytat(MateuszScirka @ 3.03.2010, 18:53:54 ) *
Jak dam run() protected to chyba nie bede mogl jej wywolac z poza klasy nie? a przeciez musze ja wywolac poza klasa.

http://pl.wikipedia.org/wiki/Hermetyzacja
Czy ja mowilem o metodzie run().... nie.Poczytaj a bedziesz wiedzial o co kaman.
MateuszS
No tak, rozumiem o co chodzi, powinienem dac metodom setTheme i setHome protected. Poza tym co zmienic itp?
marcio
Cytat(MateuszScirka @ 4.03.2010, 13:02:45 ) *
No tak, rozumiem o co chodzi, powinienem dac metodom setTheme i setHome protected. Poza tym co zmienic itp?


Nom wlasnie o to mi chodzi a tak na reszte nie lukalem.
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.