Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MVC][PHP]Jak to powinno wyglądać w MVC
Forum PHP.pl > Forum > PHP > Object-oriented programming
marekc12
Hej,

dajmy na to, że mam 3 tabele w bazie:

tabela "tytuly": id -- tytul
tabela "tytul_gatunek": id -- tytul_id -- gatunek_id
tabela "gatunki": id -- gatunek

Jak widać druga tabela wiąże poszczególne rekordy z 1. i 2. tabeli ze sobą (relacja wiele do wielu).

Teraz chciałbym wyświetlić listę utworów i przy każdym wypisać do jakich gatunków należy.

Mogę to zrobić np. tak:

W modelu mogę stworzyć klasy dla tabel "tytuly" i "gatunki".

Widok poprosi klasę modelu "tytuly" o listę np. pierwszych 20 tytułów. Widok dostanie tę listę wraz z ich numerami id. Następnie widok poprosi klasę modelu "gatunki" (wysyłając jej numery id tytułów) o tablicę: z listą gatunków dla każdego id tytułu. Widok ją dostanie. Następnie wszystko poskłada i wyświetli.

Wydaje mi się to trochę zagmatwane za bardzo, bo jeśli bym to wszystko zrobił w jeden klasie modelu "tytuły" to zajmowałoby to mniej kodu.

pozdrawiam i z góry dzięki za wyjaśnienie problemu smile.gif

Jak jest poprawnie zgodnie z modelem MVC, czyli jak powinno się to robić?
md1988
Model MVC wyglada ciutke inaczej niż to co powiedziałeś. Przede wszystkim o ile czasami łączy się kontroler z modelem to nigdy nie należy stosować połączenia widok+kontroler.

Zacznijmy może od definicji każdej z warstw składowych MVC:
1.Model - w przypadku który opisujesz byłaby nim klasa zajmująca się komunikacją z bazą danych i umożliwiająca operacje na danych za pomocą odpowiednio abstrakcyjnych metod. Klasa modelu przekazuje przygotowane dane(np. w formie tablicy asocjacyjnej) do kontrolera.
2.Widok - to co zobaczy użytkownik strony, coś co nie jest związane bezpośrednio z przetwarzaniem danych lecz ich wyświetleniem. Przykładowo np. szablon tabeli listy gatunków
2.Kontroler - jądro aplikacji, zajmuje się obsługa logiki aplikacji. Reaguje na zapytania użytkownika wykonując określone akcje na modelu takie jak dodanie danych, ich aktualizacja czy usunięcie.

Przykładowo więc:
Użytkownik wywołuje stronę na której ma być wyświetlonych 20 pierwszych gatunków. Kontroler odbiera to żądanie i posługując się klasą modelu pobiera odpowiednie dane. Następnie używając widoków(w tym choćby szablonu tablicy) buduje stronę z wyświetloną zawartością i wysyła ją użytkownikowi.


Cytat
Wydaje mi się to trochę zagmatwane za bardzo, bo jeśli bym to wszystko zrobił w jeden klasie modelu "tytuły" to zajmowałoby to mniej kodu.

Wzorzec MVC powoduje, że kod który tworzysz jest dużo bardziej elastyczny. Przykładowo chciałbyś by twoja aplikacja korzystała z plików a nie bazy danych. W MVC musisz zmienić jedynie klasę modelu, reszta aplikacji nie powinna wymagać jakichkolwiek zmian. Podobnie zmienić możesz wygląd strony bez grzebania w jej logice. To właśnie jest siła MVC smile.gif I choć fakt więcej się nakodzisz by osiągnąć efekt to potem nie będziesz tego żałował, ten wzorzec znacznie ułatwia utrzymanie porządku w kodzie.

marekc12
Cytat(md1988 @ 27.11.2010, 03:20:47 ) *
Przede wszystkim o ile czasami łączy się kontroler z modelem to nigdy nie należy stosować połączenia widok+kontroler.

Z widoku nigdy nie łączyłem się z kontrolerem. Kontroler u mnie nic nie zrobił oprócz wywołania widoku, a wywołany widok sam sobie pobierał dane z modelu.

W każdym razie, po poprawkach wyglądałoby to chyba tak:

Kontroler poprosi klasę modelu "tytuly" o listę np. pierwszych 20 tytułów.
Kontroler dostanie tę listę wraz z ich numerami id.
Następnie kontroler poprosi klasę modelu "gatunki" (wysyłając jej numery id tytułów) o tablicę: z listą gatunków dla każdego id tytułu.
Kontroler ją dostanie. Następnie wszystko poskłada i wywoła widok aby to wyświetlił.


Jeszcze interesuje mnie budowa samego modelu: czy w tym przypadku dobrze zrobiłem używając dwóch klas w modelu: "tytuly" i "gatunki" ? Jeśli np. oprócz gatunków utwory miałyby relację jeszcze do autorów, postaci, komentarzy do utworów, itd. W momencie wyświetlania listy utworów musiałbym, wywoływać po kolei te wszystkie klasy.
Zyx
md1988 -> można łączyć widok z kontrolerem, ale:

1. W aplikacjach GUI nie było to specjalnie do niczego potrzebne.
2. W aplikacjach WWW nie jest w ogóle do niczego potrzebne smile.gif.

marekc12 -> to, co piszesz, nazywa się Object-Relational Mapping i są specjalne biblioteki do tego (np. Doctrine). W MVC biblioteka ORM, jako związana na stałe z bazą danych, powinna siedzieć pod modelem, a nie go zastępować, bo inaczej później powstają różne dziwne patologie typu "nie można zaimplementować jako model niczego, co nie korzysta z bazy danych".
quality
marekc12 mylisz pojecie MVC. Widok nie ma nic wspolnego z modelem, a bynajmniej nie powinien miec. Kontroler - jak sama nazwa wskazuje - kontroluje dzialanie aplikacji. Ani widok ani model nie odwoluja sie nigdy do kontrolera. To kontroler odwoluje sie do nich. Kontroler pobiera dane z get i w zaleznosci od nich kieruje cala aplikacja, czyli pobiera dane zadania, odwoluje sie do modelu po dane, a na koncu przekazuje dane do widoku. To wlasnie jest idea MVC.
Spawnm
W MVC model i widok jak najbardziej mogą się łączyć.
marcio
ten pan myli mvc z mvp
magnus
Zazwyczaj robi się właśnie tak, że kontroler pobiera odpowiednie dane z modelu i przekazuje je do widoku. Ale wzorzec MVC pozwala również na to, żeby widok sam sobie pobierał potrzebne dane z modelu.
W wielu frameworkach zmienne kontrolera nie są automatycznie widoczne w widokach, trzeba je wprost przekazać do widoku.
Z punktu widzenia osoby piszącej widok łatwiej jest dostać np. tablicę o określonej strukturze niż pobierać z odpowiedniego modelu odpowiednią metodą (jeszcze z parametrami), dlatego zrzuca się to na kontroler.
Crozin
Frameworki MVC PHP mają tyle wspólnego z MVC co PO z liberalizmem - nic. One nawet widoków nie mają (szablon to nie widok), a model pełni ma bardzo często charakter repozytoriów.

Frameworki MVC PHP mają tyle wspólnego z MVC co PO z liberalizmem - nic. One nawet widoków nie mają (szablon to nie widok), a model pełni ma bardzo często charakter repozytoriów.
lukaskolista
Cytat
Widok poprosi klasę modelu "tytuly" o listę np. pierwszych 20 tytułów. Widok dostanie tę listę wraz z ich numerami id. Następnie widok poprosi klasę modelu "gatunki" (wysyłając jej numery id tytułów) o tablicę: z listą gatunków dla każdego id tytułu. Widok ją dostanie. Następnie wszystko poskłada i wyświetli.
A gdzie ty kontroler? MVC to Model-View-Controler. Poczytaj o tych gdziekolwiek.

Kontroler - steruje cala aplikacja.
Model - pobiera, przetwarza itp., czyli wykonuje to, co kaze mu kontroler
Widok - wyswietla to, co kaze kontroler.

Napisales, ze widok prosi model - nigdy w zyciu!

Przepisze Twoj opis po mojemu

Kontroler poprosi model "tytuly" o listę np. pierwszych 20 tytułów. Kontroler dostaje tę listę wraz z ich numerami id. Kontroler przekazuje ta liste do widoku a widok ja wyswietla. Następnie kontroler poprosi model "gatunki" (wysyłając jej numery id tytułów) o tablicę: z listą gatunków dla każdego id tytułu. Kontroler ją dostaje i przekazuje do widoku. Przy prostych skrytpach takie operacje moga wydawac sie bezcelowe, ale jezeli aplikacja jest rozbudowana to porzadek ulatwia prace nad nia, bo wiadomo gdzie co jest.

Ponad to MVC to wzorzec, a z definicji slowa wzorzec wynika, ze nie jest to scisle okreslona regula, czyli kazdy kto mowi "To nie jest w MVC" niekoniecznie ma racje. Tutaj chodzi o rozwarstwienie aplikacji, a nie jakis sztywny schemat. Oczywiscie jak ktos wyswietla html w modelu czy kontrolerze to nie jest to zgodne ze wzorcem, tak samo jak pobieranie dancy w widoku i podobne anomalia.
krzywy36
lukaskolista, jesteś w błędzie:
"...Widoki posiadają bezpośrednie referencje do modeli, z których pobierają dane, gdy otrzymują od kontrolera żądanie odświeżenia..."
źródło: MVC
Zyx
lukaskolista -> to, co piszesz, to jedna z wielu późniejszych modyfikacji zwana "pasywnym widokiem", posiadająca swoją własną definicję i właściwości. Natomiast "MVC z pasywnym widokiem" != MVC. krzywy36, Crozin i inni dobrze mówią, a podane źródło to akurat jedno z lepiej opracowanych i uźródłowionych haseł w polskiej Wikipedii bazujące m.in. na oryginalnej definicji MVC oraz pracach naukowych i publikacjach specjalistów od inżynierii oprogramowania. Tylko w świecie części frameworków WWW przyjęło się nazywać piernik wiatrakiem, robiąc gigantyczny chaos.

Cytat
Ponad to MVC to wzorzec, a z definicji slowa wzorzec wynika, ze nie jest to scisle okreslona regula, czyli kazdy kto mowi "To nie jest w MVC" niekoniecznie ma racje. Tutaj chodzi o rozwarstwienie aplikacji, a nie jakis sztywny schemat. Oczywiscie jak ktos wyswietla html w modelu czy kontrolerze to nie jest to zgodne ze wzorcem, tak samo jak pobieranie dancy w widoku i podobne anomalia.


Tak, to prawda, nie jest to ściśle określona reguła, a wzorce mają charakter ogólny i nie precyzują konkretnej implementacji. Za to posiadają pewne założenia, których modyfikacja może pociągnąć za sobą zmianę właściwości. Dlatego jeśli zmieniłeś założenia wzorca, stworzyłeś nowy wzorzec (lub antywzorzec smile.gif) o nowych właściwościach, a zatem nie powinieneś dla niego używać dotychczasowej nazwy. O tym już wielu programistów zapomina. Wzorce projektowe i architektoniczne to słownik: "jeśli architektura będzie zorganizowana tak i tak, to uzyskasz taki efekt", a tu mnóstwo programistów próbuje robić z niego burdel, powołując się na nadinterpretację pojęcia wzorca.
marekc12
widzę, że rozgorzała niezła dyskusją na temat widoku, a mi tylko chodziło o to jak rozpisać model, jeżeli mam relację wiele do wielu i wyciągam dane smile.gif.
Crozin
Zastanów się jak powinien wyglądać interfejs dla tego czegoś? Zróbmy to tak*:

Załóżmy, że mamy relację pomiędzy książkami, a ich gatunkami (bo tytuł to może być książki, piosenki, filmu - ale sam w sobie nie występuje)
  1. $book = /* pobierz skądś obiekt (jednostkę) typu Book */;
  2.  
  3. echo $book->getTitle();
  4. foreach ($book->getGenres() as $bookGenre) { // Zwraca nam tablicę obiektów typu BookGenre
  5. echo $bookGenre->getName();
  6. }
Książki i gatunki posiadają wzajemną relację. Na tym etapie nie interesuje Cię jak to będzie w bazie danych wyglądać tylko jaki to będzie miało interfejs, jakie typy możemy wyszczególnić itd. Takie projektowanie "od końca" niejednokrotnie jest najlepszą metodą.

Tak więc jakie będzie kompletny interfejs dla książek i gatunków?
Kod
Book:
  getTitle()
  setTitle(string)
  
  getGenres()
  setGenres(array[BookGenre])
  addGenre(BookGenre)
  eraseGenres()

BookGenre:
  getName()
  setName(string)

  getBooks()


* oczywiście nie jest to jedyna słuszna droga - ale jest prawdopodobnie najlepszą w tej sytuacji.
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.