Ponieważ nie mam dostępu do forum DEV, a wiem, że tam po części problem MVC był poruszany, postanowiłem zadać kilka pytań.
Coraz więcej mówi/pisze się na temat MVC (Model-View-Controller) ale pomimo usilnych starań nie mogę zrozumieć pewnych mechanizmów, tymbardziej, że większość przykładów podawanych jest w Java'ie.
Może zacznę od tego co już wiem, jeśli się mylę, proszę poprawcie mnie.
Cała aplikacja składa się z trzech części:
:arrow: Kontrolera, który odbiera operacje z zewnątrz (input) i odpowiednio je przetwarza, wywołując konkretny model (modułu) i metodę tegoż modelu. Może również odwoływać się bezpośrednio do widoku.
:arrow: Modelu, który jest niejako modułem odpowiedzialnym za jakiś ułamek pracy aplikacji (menu, news, sonda itp, itd.). Także jak widać w przeciwieństwie do kontrollera istnieje wiele modeli. Jak wcześniej wspomniałem model odbiera od kontrolera odpowiednie rządania, przetwarza je i wynik może przesłać do widoku.
:arrow: Widok natomiast wszystkie dane wysłane z modelu lub kontrolera wysyła na zewnątrz (wyświetla wynik na WWW, tworzy dokument XML, PDF itp.). Tak więc może być kilka podwidoków, które wywołane przez widok głowny tworzą efekt końcowy widoczny dla użytkownika.
A teraz czas na pytania:
* w jaki sposób elementy te komunikują się?
* wiem, że najbardziej naturalnie będzie zastosować programowanie obiektowe, ale czy da się to zrobić strukutralnie?
* co jest w przypadku gdy jeden model jest zależny (potrzebuje danych) od drugiego modelu?
* czym są akcje (actions) i łańcuchy (chains)?
Jeśli coś pominąłem, proszę dopiszcie, Myślę, że dyskusja na ten temat wpłynie w jakimś stopniu na rozpowrzechnienie tego rozwiązania, a chyba na tym nam zależy, aby łatwiej tworzyć aplikacje webowe i w przyszłości korzystać z już napisanego kodu...
No wiec tak sorry ale odpowiem nie po kolei :
ad 4
Akcje sa to logicznie podzieone operacje tzn ze w akcji starasz sie zawrzec najbardziej niepodzielna operacje jaka sie da. Czyli na przyklad akcje : zaloguj, usun artykul, dodaj artykul, pokaz menu itd. Akcje dzielimy naa logiczne i widoki. Akcje logiczne sa odpowiedzialne za realizacje zadan takich jak dodaj, usun, powiarz, sprawdz itd. podczas gdy akcje widoki maja za zadanie zwrocic dane do przegladarki.
Łancuch akcji polega na tym ze jezeli wciskasz przycisk usun artykul to najpierw wlacza sie akcja potwierdzajaca wybor potem ta akcja uruchamia akcje usuwajaca artykul ktora z kolei wywluje widok pokazujacy liste artykulow, taki lancuszek.
ad 1
Kontroler dostajac odpowiednie dane uruchamia odpowiednia akcje ktora uruchamia odpowiedni model. Mozna ten schemat komplikowac ale generalnie tak to wyglada.
ad 2
Jesli udalo by ci sie to oprogramowac strukturalnie to ja chcialbym taki silnik zobaczyc
ad3
Wlasniesie spotkalem z takim problemem. No coz poprostu w akcji uruchamiam dwa modele.
ps Dodamtylko ze zadaniem modelu jest tylko i wylacznie stworzenie abstrakcji na dane tak aby jezeli sie cos zmieni np. w bazie to grzebiesz tylko w modelu a nie we wszystkich akcjach.
Specyfikacja URLa oczywiście nie ma znaczenia i zależy jedynie od wyobraźni twórcy?
Czy dane wysłane przez POST i GET oraz te, które są zawarte w SESSIONS wyciągane są bezpośrednio przez modele, czy też tym też zajmuje się kontroler?
A mógłbym zapytać gdzie to można ściagnąć jak zainstalować,jakis kurs/manual i co to jest
Jeden z dostępnych: http://phiend.sourceforge.net
Wszystko wskazuje na to, że mamy odmienne pojęcia na "abstrakcję źródła danych". Z tego, co wiem, to w typowym znaczeniu oznacza ona po prostu klasę dostępową do źródła, niezależną od implementacji na konkretnej bazie danych czy pliku - taki API, jak np. AdoDB.
Innymi słowy, w 3-warstwowym modelu aplikacji najniżej jest warstwa dostępu do danych (do której API dostępu z warstwy drugiej można określić "abstrakcją na źródło danych", jeśli takie jest zastosowane).
Warstwa druga, która jest najczęściej modelem, stanowi tymczasem zbiór klas czy funkcji tzw. "logiki biznesowej", co przede wszystkim oznacza, że ta warstwa + warstwa danych tworzy gotową aplikację - realizuje wszystkie zadane operacje na bazie danych, uwierzytelnianie użytownika, tworzy jakieś logi, wywołuje jakąś usługę SOAP, wysyła maila, cokolwiek, ale jest to kompletny, działający system, tyle, że zamiast interface'u użytkownika udostępnia API programistyczne dla warstwy jeszcze wyższej.
Warstawa kontrolera i widoku to tymczasem warstwa prezentacji, czyli jeszcze wyżej. I teraz wygląda to tak, że użytkownik się loguje, łaczy się z kontrolerem, któremu przesyła żądanie, ten czyści dane wejściowe i jeśli wszystko jest ok wywołuje funkcję zaloguj($login, $haslo) warstwy logiki biznesowej (czyli model) i sprawdza, czy to się powiodło, ale nie wie nic o szczegółach implementacji w modelu i - przede wszystkim - nie ma dostępu do bazy danych, nie może wywołać żadnego zapytania SQL. Później kontroler przekazuje sterowanie do odpowiedniego, w zależności od powodzenia operacji, widoku - ale to jest jasne.
Oczywiście 3-warstwowy model aplikacji jest tu tylko po to, żeby objaśnić zagadnienie modelu jako takie w kontekście "abstrakcji źródła danych". W rzeczywistym systemie z zastosowanym MVC mogą być z równym powodzeniem tylko 2 warstwy - sama prezentacja i model.
Jak widzisz, być może że tylko 1 pojęcie sprawiło, że myślisz, że tego nie rozumiesz, a rozumiesz - jeśli tak to sorry za zamotkę
Być może to jest OT, ale nie wiem, czy można nazwać abstrakcją na źródło danych coś, co nie koniecznie operuje na danych w bazodanowym sensie i nie koniecznie ma dostęp do źródła danych. Przecież model może np. pobrać informacje o dostępności produktu przez SOAP, sprawdzić stan rachunku bankowego, zamówić produkt i przelać kasę. I to wszystko w jednym wywołaniu modelu.
A warto też dodać, że model może być np. aplikacją w C, która ma za zadanie obliczyć symulowane odsetki, a kontroler tylko robi exec('/usr/bin/odsetki -sklada_miesieczna 3000');
Jak dla mnie takie OT mogą być, o ile mieszczą się w pewnych ramach tematu tak jak powyższa polemika. :-)
Tak na marginesie chciałem zapytać skąd czerpaliście informacje na temat MVC?
Moze troche sie wtrącam do waszej zrozmowy, ale moze powiecie mi pare rzeczy. Jako ze nie obeznany jestem tak jak Wy, nie zawsze kojaze co za skroty uzywacie, albo jakies pojecia anglojezyczne. No ale nie o oto i do konca chodzi. Jak napisal scanner ze jeden z takich MCV jest dostepny na necie oczywiscie tam zagladolem. Ale niestety moja wiedza tajemna nie byla wstanie przegrysc samego manuala, wiec o testach na phiendzie nie bylo mowy.
Ale po kolejnych postach zaczyna cos mi swiatac na temat calego tego MVC.
Bumelang napisał o 3 warstwowym poziomie aplikacji, szczerze mowiac dopiero jego post dal mi do myslenia jesli chodzi o cale zagdanienie MVC.
Jesli dobrze zrozumialem do pierwsza warstwa jest odpowiedzialna za pobranie danych, naprzyklad skrypt rozpoznaje zapytanie, np User chce zobaczyc na stronie komantarze do artykulu, wiec skrypt rozpoznaje ze chodzi o komentarze o jakies danej specyfikacji, wiec lpobiera dane dla tej specyfikacji (pliki, bazy danych, sockets itd). Procz tego apytania, sa standardowe zapytanie, powiedzy o konfiguracje strony (tytul, adres, kolor itd). Jako standardowe zapytanie przy wiekszosci odslon.
Ta warstwa teoretycznie konczy swoje zadanie i przesyła dane do drugiej warstwy, której zadaniem jest przetworzenie wszystkich otrzymanych danych. Tutaj nawołując do przykladu, skrypt powiedzmy ze w komentarzach przetwarza text (np BBcode) ustawia zapis daty i jakie pare tam innych opcji mniej waznych.
Przetworzone dane wędruja teraz do warstwy ktora zajmuje sie wyswietlanie, powiedzmy ze beda to Smarty, które generuja nam gotowy kod wysylany do przegladarki. i tutaj piszecie jeszcze o wykonaniu destruktora.
A teraz pare Pytanek:
- czy dobrze zrozumialem to zagadnienie? oczywiscie jest ono mocno uproszczone.
- czy warstwa 2(czyli przetwarzanie danych) moze czesciej pobierac dane z 1 warstwy? Np. po otrzymaniu danych, podczas przetwarzania pobrac dodatkowe informacje, czy trzeba przewidziec to w 1 warstwie i wyslac odrazu.
- czym jest destruktor, jakie jest jego działaniei i co sie stanie jesli go nie bedzie?
jak już trwa taka zaciekła rozmowa na temat MVC, to zauważę, że warto ponownie zainteresować się ciekawym systemem WACT http://www.phppatterns.com/index.php/article/articleview/85/1/9/
System ten, poza paroma ciekawymi innowacjami, pokazuje również (z tego co zdążyłem się zorientować po paru minutach przegladania) bardzo ciekawy sposób komunikacji pomiędzy modelem a widokiem, któy pozwala na przeniesienie zainicjowania procesu pobrania danych przez view, dopir0o w momencie, gdy te dane będą mu potrzebne.
Chyba nie trzeba nikogo przekonywać, jak często takie rozwiązanie może być bardzo przydatne.
Hmm, ciekawe...
Z tego co na razie widziałem, WACT ma bardzo fajny system szablonów. Wspominał o tym gdzieś Nalfein (ale o idei, nie o WACT): wyciągać dane z modelu tylko wtedy, kiedy widok naprawdę ich potrzebuje, a nie jak np. w Smarty najpierw wyciągać, a potem zobaczymy czy widok w ogóle z nich skorzysta. To jest wielki plus.
I sam język szablonów jest ładny, taki XML-owy . Czyli podobny do Struts w Javie. Albo nie do samego Struts, ale do JSP generalnie. Taka strona wygląda jak JSP i działa mniej więcej jak JSP.
Ale nie widziałem tam jeszcze samego kontrolera :? . Może dlatego że coś mi strona WACT kiepsko działała. Anyway, gdzie tam jest założenie, że mamy jeden główny skrypt (kontroler) i akcje? Gdzie rozdział między akcjami a modelem? W tutorialu widziałem SQL przemieszany z assignami do szablonu.
No ale niedokładnie szukałem, a sam WACT jest pre-alpha. Na razie wydaje mi się, że to jest świetne rozwiązanie widoku, ale nie całego MVC.
Minusów jest więcej:
- Co zrobić, jak tego pliku akurat nie ma? Kontroler sobie poradzi, Apache nie.
- Nie każda akcja musi kończyć się wyświetleniem HTMLa - patrz akcje logiki. A tak co? Robić require w tych plikach, i skończyć z taką siecią powiązań?
- Jak będziesz chciał zmienić np. lokalizację WACT, albo jakiekolwiek inne ustawienie globalne, to globalny regexp po wszystkich plikach albo z godzinka roboty...
Jest różnica pomiędzy wywaleniem w ogóle kontrolera, a eliminację routera. Chociaż pojęcie routera jest nasze autorskie i nie występuje w MVC. Hierarcha katalogów jako sposób wybierania akcji do wywołania OK, ale oni idą znacznie dalej.
BTW, trochę zabawne że oni mimo to piszą o MVC. Zrobiliśmy framework oparty o wzorzec Model-View-Controller, ale wywaliliśmy z wzorca cały kontroler . Co nie znaczy że wszystko co dobre musi być MVC. Ale jeżeli ktoś usilnie stara się przedstawić swój projekt jako MVC, to o czymś świadczy...
Nie wywalili kontrolera, ale wywalili obiekt typu FrontController. Akcje logiki to też przecież warstwa kontrolera.
Ale warstwa kontrolera bez kontrolera?
To tak jak system bazodanywy bez bazy danych. Albo aplikacja obiektowa bez obiektów.
Zresztą, u nich nie ma akcji logiki.
Chyba za dużo nad Phiendem przesiedziałeś To tak jak rozproszona baza danych (np. pliki XML) czy jak aplikacja obiektowa bez menedżera obiektów. Ja robię to tak np. w pliku /forum/view.php mam:
[php:1:17e5bd469d]
<?php
$app = CodeZone::instance();
$action = $app->create('ViewForumAction', 'actions/forum');
$app->run($action);
// albo $app->execute($request, $response, $action);
// aby realizować testy XP z obiektami FakeRequest oraz FakeResponse
?>
[/php:1:17e5bd469d]
Metoda ::run() klasy aplikacji przekazuje obiekt $action do kontrolera wraz z obiektami $request, $response, które tworzy. Kontroler obsługuje żądanie wypełniając $response, a aplikacja wyrzuca wynik na ekran. Nie wywołujemy tutaj jawnie kontrolera (FrontControllera), przez co możemy w ogóle z niego zrezygnować w prostych aplikacjach, a może za tym wszystkim siedzieć nawet Phiend2.
© Paladine Framework
To w takim razie każda aplikacja w php jest oparta o wzorzec MVC, bo w każdej występuje Apache jako kontroler. Dochodzimy do absurdu.
Hmm, tak szczerze mowiac, to kazda strona napisana w php, z wykozystaniem, bazy danych, jest juz oparta na modelu MVC.
Jesli dobrze wszystko rozumiem, to kazda strona dziala na takim założeniu. Dziwne by to chyba wygladało jak by szlo to w odwrotnym kierunku.
zeby nie zrobic gafy opieram sie na zend.com. Chyba kazda strona pobiera najpierw dane, pozniej dane sa obrabiane w tak zwanej "business logic" a na koncu sa/"moga byc" wyswietlane.
mam nadzieje ze teraz rozumiem to, jakos prawidlowo. Patrzac na to co wy mowicie, to jedyne czym moga sie roznic "wasze" strony od "moich" (mowie tutaj o sposobie pisania) to jest taka ze wy tworzycie zaawansowane klasy, a ja siedze jeszcze po czesci w procedurach.
OK
MVC itd...
Ale jak to wygląda w praktyce? - w momencie, gdy mamy zabrać się za pisanie właściwego projektu - opisać klasy itd...
czy ktoś ma jakiś gotowy wykresik prezentujący np. podział klas na MVC - w miarę dokładny?
Bo z tego co tu się pojawia to ja to widzę jakoś tak:
+KONTROLER © - max nadrzędnie
|- MODEL_a (M) - ściąga dane z bazy i operuje na nich fizycznie
|- MODEL_b (M) - inna klasa operująca na danych - np. danych usera itd..
|- MODEL_c (M) - jeszcze co innego - np. odpowiedzialnego za newsy, artukuły itd...
|- WIDOK (V) - dostaje info z kontrolera - po przetworzeniu odpowiedniego modelu i wyświetla to lub tworzy plik z wynikiem - w każdym bądź razie jest wywoływany na końcu i zajmuje się tylko prezentacją
Czy dobrze rozumuję?
http://phppatterns.com/index.php/imagecatalogue/imageview/15/?RefererURL=/article/articleview/19/1/1/
...tyle tylko, że w większości frameworków MVC masz jeden obiekt kontrolera, który wywołuje odpowiednie akcje/widoki w odpowiedzi na dane wejściowe. Model łączy się z akcjami/widokami poprzez agregację (czyli tak jak na tamtym diagramie) lub kompozycję (a nie przez dziedziczenie... bo wtedy to już masz model zagnieżdżony w akcjach/widokach.. a tego chcemy uniknąć przeważnie - inaczej to nie jest MVC ) ). Czyli jedyne co robisz w widokach/akcjach, to wywołujesz odpowiednie metody odpowiednich modelów. Przynajmniej ja tak to wszystko rozumiem ]
Diagram widziałem, napisałem sobie nawet własne MVC - dokładnie takie samo, ale dot. czego innego - żeby się nauczyć. - nauczyłem się tego.
Ale:
1) jakbym chciał zrobić usuwanie, doadawanie itd.. - to gdzie dodać odpowiedzialne za to funkcje? - chyba do modelu, ale tam model jest tak zrobiony, że nie odpowiada konkretnemu zbiorowi danych w tabeli a jedynie służy za narzędzie. Więc może do kontrolera? - ok, ale on musiałby przekazać to wszystko do modelu i patrze pkt. wyżej....
2) nigdzie tam nie ma ustalonego id dla OKREŚLONEGO odpowiednika w bazie danych!! - ja wiem, moze nie do konca rozumiem OOP itd.. ale czy to nie jest troche malo uniwersalne, jezeli tylko kontrolerowi podaje id do wyswietlenia i nie moge potem np. zrobic tak:
[php:1:a31b6f25fe]<?php
$a = new ArticleSingleController($dao,$_GET); // gdzie $_GET[id]=2
$a-> // i tu jakos podzialac zeby display wyswietlil np. 3 art.
echo $a->view->Display();
?>[/php:1:a31b6f25fe]
Da sie tak?
ad 1) poczytaj dokumentacje phienda )
http://phiend.sourceforge.net/manual/actions.html <- zwlaszcza to pomoże...
W akcjach/widokach wywolujesz jedynie odpowiednie metody modelu. np
[php:1:121515932c]<?php
$ProductModel->DeleteItem($_GET['id']); // to będzie w akcji odpowiedzialnej za usuwanie
$ProductModel->UpdateItem($_GET['id'], $_POST['data']); // a to w akcji odpowiedzialnej za update..
?>[/php:1:121515932c]
Dopiero w modelu trzymamy SQL, czy cokolwiek innego odpowiedzialnego za usuwanie, modyfikacje.. czy zwracanie danych.
ad 2) w tym przykladzie jak zobaczysz na zrodlo ( http://phppatterns.com/index.php/article/articleview/19/1/1/ ...bo chyba podałem wczesniej link przypadkiem tylko do samego diagramu..), to kontroler tak naprawde zostal zrealizowany w index.php:
[php:1:121515932c]<?php
switch ( $_GET['view'] ) {
case "product":
$controller=& new ProductItemController($dao,$_GET);
break;
default:
$controller=& new ProductTableController($dao,$_GET);
break;
}
?>[/php:1:121515932c]
Tamten przykład podałem aby pokazać zależność między widokami/akcjami a modelem.. natomiast jak dla mnie realizacja kontrolera jest całkowicie bezsensowna... Naprawdę polecam lekturę Phiend'a. Na stronie projektu ( http://sourceforge.net/project/showfiles.php?group_id=90219 ) też jest źródło aplikacji, którą masz tutaj:
http://phiend.sourceforge.net/application/
1) Czy mam w takim razie do kontrolera, oproocz $model i $view dodać np. obiekt $action , który będzie działał na modelu? czy po prostu do samego modelu dodac odpowiednie metody?
2) A moze po prostu w modelu owszem, dopisac metody usuwania itd... a potem w kontrolerze - odpowiadające im, ale juz przekazujące identyfkatory i dane? - czy tak bedzie dobrze?
3) Jeszcze jedna sprawa: Tak mi sie wydaje, ze jak robie strone w MVC to:
powinien byc 1 kontroler - ktoory by wszystko tworzyl, ustawial, usuwal itd...
modele : odpowiedzialny za baze danych, odpwiednie do newsoow itd.. ,
widoki : prezentacje kazdego z modeli do newsoow itd...
Teraz tak:
czy nie powienien byc jeszcze jeden model i odpowiadajacy mu widok : np. o nazwie SiteModel i SiteView - ktoore odpowiadaly by za cala strone?
i np: SiteView to cos takiego:
[php:1:21abc83259]<?php
Class SiteView
{
var $views;
var $model;
var $output;
function SiteView($model)
{
$this->model = $model;
}
function AddView($view)
{
$this->views[] = $view;
}
function Header()
{
// naglowek <html> itd...
}
function Footer()
{
// /html itd...
}
function Site()
{
foreach($this->views as $n => $view)
{
$this->output .= $view->Display();
}
}
function Display()
{
$this->Header();
$this->Site();
$this->Footer();
return $this->output;
}
}
?>[/php:1:21abc83259]
Czy to jest dobre rozwiązanie?
jak np. chciałbym wyswietlic newsy to tylko bym dal w kontrolerze, ze
[php:1:21abc83259]<?php
$news= new NewsModel;
$newsview = new NewsView($news);
$siteview = new SiteView;
$siteview->AddView($newsview);
// a potem juz tylko:
echo $siteview->Display();
?>[/php:1:21abc83259]
Na phppatterns jest schemacik prezentuajcy MVC 2 i do tego jest śliczny kodzik źródłowy.
Mam pytanko w sprawie modelu (ProductModel) z tego kodu:
... a raczej kilka pytań:
1) Dlaczego ten model nie odpowiada pojedynczemu produktowi (wierszowi w tabeli bazy dancyh)?
2) ... można go napisać tak, żeby odpowiadał, ale wtedy możemy się pożegnać z listProducts - czyli wysłaniem żądania o kilka wierszy.... Jak sobie z tym poradzić
3) Czy można napisać taki model (np. articleModel) - który miałby też tablicę modeli np. CommentModel - i dzięki temu jakoś mógły sobie podporządkowywać Komentarze do samego siebie, dodawać usuwać itd...
np tak:
[php:1:7db2f59b24]<?php
Class Comment
{
var $data;
var $dao;
function Comment($dao)
{
$this->dao = $dao;
// Standardowa pusta tablica na dane - czy to doby pomysł?
$this->data[title] = "";
$this->data[body] = "";
}
function GetById($id)
{
$this->dao->query("SELECT * FROM comments WHERE id=".$id);
// i tu pojawia się kwestia : czy dać tu od razu, żeby uzupełnić całą pustą tablicę $data, czy też jakoś inaczej? - jakaś rada?
}
function cośtam?()
{
// i tu by sie przydało coś co wyciąga je po np. articleid
}
function ReturnComment()
{
// i teraz nie wiem czy dać
// return $this->data;
// czy też return $this->dao->GetRow();
// w zależności od rozwiązania, jak dam $this->data to mogę się pożegnać z późniejszym wykorzystaniem while($cośtam = $CommentModel->ReturnComment())
}
}
// i do tego klasa art
Class ArticleModel
{
var $dao;
var $data;
var $comments;
function ArticleModel() // tu wszystko po staremu
{
}
// KWESTIA OPISANA PONIŻEJ:
}
?>[/php:1:7db2f59b24]
Jak zrobić, żeby dało się tak przypisać klasie ArticleModel przynależność kolejnych Komentarzy w bazie, żeby ArticleModel zarówno odpowiadał artukułowi co jest w bazie jak i komentarzom, im przypisanym?
Wie ktoś może jak to rozwiązać?
O widoki nie pytam, bo to już w miare mały problem
Mam problem. Chciałbym zapisywać i dodawać, szukać itd... dane w bazie na tej zasadzie, ze przekazuje nie Id, czy jakis jeden paramentr a cala tablice odpowiadajaca zawartosci danego modelu w bazie. czyli np:
ArticleModel i ArticleDataModel - gdzie ArticleDataModel jest obiektem generującym tablicę zawierającą dane artykułu. Później w ArticleData dodać metodę SaveByData($data), gidze $data to instancja ArticleDataModel i zawiera dane, które mają być zapisane. TAk samo z dodaniem. ArticleDataModel będzie mógł być tworzony bezpośrenio z formularza - co wy na to?
jak to rozwiązać?
Nie rozumiem :? ArticleDataModel i ArticleModel mają odpowiadać obiektowi Article i kontenerowi artykułów? Sugerowałbym wywalenie tego Model z nazwy klasy, bo ono tam nie pasuje a nikt nie powiedział że klasa należąca do Modelu musi mieć to w swojej nazwie. Nazwa klasy powinna odzwierciedlać jej przeznaczenie i być prosta, jasna i oczywista.
Więc w takim razie przedstawie ten problem tak:
[php:1:22b83270b7]<?php
Class ArticleData
{
var $data = array(
art_id => null,
art_title => null
); // i tak dalej z całą resztą
function ArticleData($data=array())
{
foreach($data as $key => $value)
{
if ($data[$key] != "")
{
// tu następuje przepisanie danych z tablicy data - np. z formularza
// do tablicy tej klasy
$this->data[$key] = $data[$key];
}
}
}
function ReturnAsString()
{
$str = array();
foreach($this->data as $key => $value)
{
if (!is_numeric($value))
{
$value = "'$value'";
}
$str[] = "$key=$value";
}
return implode(" AND ", $str);
}
}
Class Article
{
// konstruktor itd...
function GetByData($data)
{
$this->dao->query("SELECT * FROM articles WHERE ".$data->ReturnAsString());
}
}
?>[/php:1:22b83270b7]
I teraz tak:
Article i ArticleData są właściwie wogóle nie związane - ArticleData jest tworzone np. tak, że jako argument podawana jest zawartość fomularza - klasa sama wie co ma sobie wziąć ;. ArticleData będzie tworzona w widokach i przekazywana do modelu Article jako argument dodawania, wyciągania z bazy itd...
Czy to jest dobre rozwiązanie? Może zaproponuje ktoś coś lepszego?
Hmm, zaczynasz od końca... co nie jest jakąś szczególną krytyką bo to jest raczej powszechne.
Bo przedstawiasz kod, a kod dużo mówi na temat algorytmów i sposobu implementacji, a mało o projekcie i założeniach jakie system miał spełniać.
Po co są klasy Article i ArticleData? Nazwa ArticleData jest myląca, bo nie wiadomo czym to się różni od Article. Piszesz że nie są związane, a potem że ArticleData jest przekazywane do Article jako argument - to jest asocjacja, nawet jeżeli tylko <<uses>>.
Dyskusja na odpowiednio wysokim poziomie abstrakcji jest bardzo trudna i często nie kończy się niczym konkretnym. Ale dyskusja na nie zdefiniowanym poziomie abstrakcji jest jeszcze gorsza.
Jest różnica pomiędzy OOP a OOD, tak jak pomiędzy programowaniem a projektowaniem w ogólności, a wątek w końcu jest o wzorcu projektowym :wink: . Mam nadzieję że nie zamieszałem zbytnio .
"Dyskusja na odpowiednio wysokim poziomie abstrakcji jest bardzo trudna i często nie kończy się niczym konkretnym. Ale dyskusja na nie zdefiniowanym poziomie abstrakcji jest jeszcze gorsza. " - chodzi mi tylko o to, czy takie przekazywanie danych jest wogoole przyjmowane za "poprawne" ? - jeśli jest to ok - będe tak pisał całą stronę, jeśli nie to trudno... - trzeba poszukać lepszego rozwiązania
Ja mam pytanie o cos innego.
Wiadomo, ze niektore akcje moga zostac wykonane, jesli uzytkownik ma odpowiedni poziom (np. usuwanie newsow tylko przez admina) - jak to dobrze przeprowadzic w aplikacji wzorowanej na mvc ?
Czy sprawdzaniem poziomu uzytkowanika ma zajmowac sie kontroler, czy tez modul artykulow powinien zarzadac wiadomosci o poziomie usera ?
Ostatnio troche dumałem nad MVC i w związku z tym mam pytania. Zaznaczam że jestem w tym temacie poczatkujący
1. Chodzi mi o przeplyw informacji między Kontrolerem Widokiem i Modelem. Zakładam, że każdy z nich to osobna klasa z czego Kontroler jest nadrzędny. Kontroler na podstawie danych z Inputa wywołuje odpowiednie metody z Modelu. Czy Model przekazuje dane zwrotne klasie Kontrolera czy bezpośrenio Widokowi?
2. Czy Model może samodzielnie pobierać dane (np. konfiguracji) z Kontrolera czy też lepiej w trakcie tworzenia klasy Modelu przez Kontroler wysłać wszystkie niezbędne dane potrzebne do pracy (login, hasło do db itp.)?
3. Rozumiem że Widok jest typu Output i nie powinien nic wysyłać do Kontrolera.
Na pewno namieszałem
1. Z tego co ja już zdążyłem się zorientować, to np. w przypadku wyświetlania kontroler wywołuje widok, który wyciąga dane z modelu i "wyrzuca" je na wyjście.
3. Widok może wysłać do kontrolera żądanie wywołania innej akcji, ale nie powinien mieć wpływu na zmianę danych w modelu i kontrolerze.
kurcze od jakiegos czasu probuje dowiedziec jak 'to' robic w mvc;) Zaczelo sie od artykuly na php.pl. Potem napisalem nawet sporo kodu w oparciu o to co zrozumialem. Nie wiem tylko jak zweryfikowac to czy to co napisalem faktycznie mozna opatrzec etykietka mvc... Jest tak dlatego, że
każdy pisze coś innego
Jedni twierdza ze pewne rzeczy powinien robic kotroler inni ze nie; ze model(instancja) powiniene byc przekazywany jako parametr do widoku, inni ze absolutnie nie tak itd... Generalnie widze same sprzecznosci i dochodze do wniosku ze tak naprawde idea mvc jest bardzo ogolnym spojrzeniem na zagadnienie projektowania aplikacji i nie dostarcza konkretnych rozwian do wielu problemow tutaj poruszanych:/ a ew dywagacje na te tematy wprowadzaja straszne zamieszanie?
czy ktos ma podebne odczucia?
MVC jest dobre, ale....w Javie:) Przykład: Swing, widok zmienia się w zależności od platformy lub "wyglądu i wrażenia". Sterowniki przechwytuje zdarzenia, a model przechowuje dane komponentu. W takim przypadku stosowanie MVC wydaje się uzasadnione, jednak w php, gdzie każda dodatkowa klasa wydłuża czas generowania strony, próby używania MVC na siłę, tylko po to, by być "trendy" wyraźnie mija się z celem. Może niektórym nie spodoba się to co napisałem, jednak taka jest moja opinia na dzień dzisiejszy:)
Tak, tez mam takie wrazenie. Wyszedlem z zalozenia ze MVC [ model view controler ] mozna bardziej luzno potraktowac. Jesli ty piszesz swoj MVC, to zapewne bedziesz mial w planie rozszerzac jego mozliwosci, a wiec to na ogol ty bedziesz go pisal/rozszerzal. Wiec na poczatku wychodzisz z glownego zalozenia, musi byc MODEL, WIDOK , i KONTROLER tego wszystkiego. Reszta wedlug mnie to kwestja sporna. Fakt, ze Widok nie powinien edytowac danych, tylko je wyswietlac, nie ma nic wspolnego z tym, ze nie moze zarzadac zmiany danych przy Modelu. Teraz tez pisze aplikacje na podstawie zalozen MVC, najgorszy jest pomysl. Siedze juz dluzszy czas przy kontrolerze, zeby wyszedl elastyczny/latwy do edycji, modyfikacji... Dlatego skupie sie dluzej na kontrolerze... Pozniej Model, oraz glowne zalozenia, jakie maja spelniac akcje, prawa dostepu/autoryzacjia... I widok. Calosc nastepnie trzeba rozszerzac o dodatkowe moduly/akcje.
Tak sobie dumam i dumam i.... :
koncepcja 1:
1.wywolany jest index.php;
2.index uruchamia klase kontroler wraz z wszystkimi parametrami (dane z adresu URL, i inne potrzebne);
3.Kontroler przekazuje informacje do klasy modelu w celu wykonania odpowiedniej akcji z danych pobranych z kontrolera(informacje dla akcji jak i do przekazania widokowi);
4.model przesyla wynik do klasy widoku wraz z danymi niezbednymi do wyswietlenia a uzyskanymi od kontrolera;
5.widok generuje odpowiedni szablon z danymi z modelu.
koncepcja 2:
1.wywolany jest index.php;
2.index uruchamia klase kontrolera wraz z parametrami
3.Kontroler przekazuje niezbedne informacje (tylko i wylacznie dane potrzebne do uzyskania danych z modelu) klasy modela w celu wykonania odpowiedniej akcjii z danych pobranych z kontrolera;
4.model przesyla wynik do klasy kontrolera;
5.kontroler przekazuje dane do widoku (te uzyskane z modelu jak i inne wymagane do poprawnego wyswietlenia)
6.widok generuje odpowiedni szablon z danymi z modelu.
czy ktoras z tych koncepcji jest prawidlowa?? czy moze jeszcze inaczej to powinno wygladac?
wiem ze pewnie namieszalem ale czlowiek stale sie uczy ciagle sie uczy
Żadna nie jest ;>)
1. index[*] odpala kontroler
2. kontroler sprawdza sobie url, parametry itp i na tej podstawie odpala akcje (wcześniej moża wrzucić jakieś sprawdzanie autoryzacji i praw dostepu do danej akcji)
3. akcja operuje na klasach modelu niezależnych[**] od widoków, akcji, kontrolera...
4. wynik wykonania akcji przekazywany jest do widoku
5. na podstawie danych z akcji widok wypluwa wynik na ekran/ przesyla gdzies indziej xml itp
[*] nie musi być tylko jeden 'wyzwalacz' kontrolera.. można zrobić kilka wyzwalaczy, każdy będzie operował na tych samych bibliotekach itd, ale dzięki temu można zrobić kilka różnych wersji konfiguracji - rozbicie aplikacji na mniejsze, niezależne od siebie/mniej zależne od siebie
[**]dlaczego podkreśliłem niezależnych? Dzięki temu gdy w przyszłości będziemy chcieli zmienić framework obsługujący aplikację modelu nie będziemy musieli nawet ruszać.. i w drugą strone - jeżeli mamy już jakiś gotowy model, a chcemy 'ożywić' go za pomocą MVC, to właśnie ta separacja pozwala nam bezproblemowo to uczynić.
Zależności między widokami/kontrolerem/akcjami i częscią autoryzującą wykonanie akcji/widoku oraz jak odseparować to od modelu.. to już inna bajka, zostało to całkiem fajnie poruszone w temacie 'jak pisać jądro...': http://forum.php.pl/index.php?showtopic=13770
Hehe
Wiedziałem ze sie myle
W mojej koncepcji chcialem by wszystko bylo wprowadzone do kontrolera jako parametry by potem juz ani kontroler ani model ani widok nie korzystaly z tablic GLOBAL. Czy to ma sens?
Zastanawia mnie koncepcja wielu kontrolerów. Jakby to miało wyglądac?
Jeżeli chodzi o akcje to też sobie podobnie wymyśliłem, tzn.: sam model to klasa ktora jest interfejsem wywołującym konkretną akcje (każda akcja to osobna klasa w osobnym pliku).Czy tak może być?
Oczywiście że model nie powinien korzystać z żadnych globalnych tablic, bo nie ma tam nic co mogłoby być mu potrzebne. Natomiast ciekawe jak napiszesz kontroler który w ogóle nie rusza tablicy $_POST, chociażby bo to aby gdzieś przepisać jej zawartość .
Po co ci wiele kontrolerów? Chyba że mówimy o Page Controller, ale MVC raczej operuje na jednym, centralnym kontrolerze.
Jeżeli chodzi o model i akcje to ni <męski narząd moczowo-płciowy> nie mogę nic z tego wyrozumieć. "model to klasa ktora jest interfejsem wywołującym konkretną akcje"? Klasa nie jest interfejsem, to raz. Dwa, że obiekt modelu absolutnie nie powinien wywoływać metody obiektu akcji. Jak by to miało wyglądać? No chyba że mówimy o listenerze w Smalltalku/Swingu, ale to inny MVC niż w php i raczej nie o to nam chodzi .
BTW, dlaczego z MVC jest tyle zamieszania? Mi się wydaje że to bardzo naturalny sposób tworzenia aplikacji, i jakby nie był wymyślony, to i tak ludzie sami z siebie by do tego doszli .
BTW2, Marcin wyrasta nam na eksperta od MVC, który nie tylko wie co i jak ale i potrafi to łopatologicznie wyjaśnić
----------------------------------------
Grr, dlaczego nie mogę dać 2 odpowiedzi pod rząd?
@Ozzy:
IMHO to nie tak. MVC w Swingu sporo różni się od tego w php, bo inny jest model interakcji. Więcej, MVC w Swingu różni się od tego w JSP i Struts, z takich samych powodów.
Natomiast używanie MVC na siłę oczywiście jest stratą czasu. Zwłaszcza w php gdzie wczytywanie kolejnych klas jest tak popieprzone jak jest. php na ogół stosowane jest do prostych serwisów. Serwisy banków już raczej w JSP. Dlaczego? Bo php jest zbyt prymitywny do tego celu. Jeżeli php dalej ma się rozwijać do Personal Home Page, to nie ma problemu, można sobie zlać MVC, wzorce i w ogóle wszystko to co wprowadzili w PHP5 bo bez tego też się da. Ale całe te zmiany idą (chyba) w kierunku uczynienia z php dobrego języka na poziomie "enterprise". I wtedy Smarty przestaje wystarczać, i trzeba pomyśleć np. o modyfikowalności itd.
Co do wielu kontrolerow to zauwaz ze to Marcin wlasnie napisal a ja stwierdzilem ze jest to do przemyslenia
Co do modelu i akcji to chyba nie zakumalem od razu i dopiero teraz do mnie dotarlo W poprzednim rozumowaniu (dodam ze blednym ) uznalem ze kontroler wywoluje model a dopiero ten wywoluje odpowiednia akcje - zakladalem ze jest jeden model, wiele akcji. Prawidlowo to jest tylko jeden kontroler a wiele modeli i tu tkwi moj blad (zgadza sie??)
Co do zamieszania przy MVC to zauwaz ze kazdy jakos inaczej pisze i jak ktos dopiero zaczyna zabawe z tym (tak jak ja) to moze sie troche pogobic.
Z tymi wieloma kontrolerami to Marcin raczej pisał (IMHO, nie chcę nic imputować) o wielu konfiguracjach. Nie możesz odpalić na raz dwóch kontrolerów, ale możesz mieć kilka wersji konfiguracji, albo kilka aplikacji na jednym serwerze, itd.
Co do modelu, to generalnie jest takie permanentne zamieszanie. Bo co to jest model? Zbiór klas. Więc co to znaczy "wywołać model"? No nie wiadomo. O ile kontroler jest pojedynczym obiektem i może coś wywoływać, o tyle w przypadku modelu możemy mówić o konkretnym obiekcie należącym do modelu, który coś robi. A cały model to logiczna część aplikacji a nie jakaś fizyczna rzecz. Więc nawet nie ma sensu mówić że jest "jeden model" lub "wiele modeli". To tak jak jedna pamięć/wiele pamięci, jedna policja/wiele policji, itd. Bez sensu. Niepoliczalne. Klasy modelu już są policzalne.
Jak dla mnie, to w tych dyskusjach nad MVC ciągle są wątpliwości co do szczegółów, a brakuje jakby zrozumienia idei. Że chodzi o sensowne zaplanowanie aplikacji i nieważne czy jest "jeden model", czy 50, ale ważne że sterowanie idzie od kontrolera do modelu a nie w drugą stronę. Bo inaczej to nie ma sensu. Takie rzeczy jakoś mało się rzucają w oczy w php. Znacznie bardziej w zwykłych, okienkowych aplikacjach. MFC jest oparte o MVC, AWT i Swing też. Spróbuj zrobić aplikację na chociaż kilkanaście tysięcy linii kodu bez separacji dokumentu od widoku. Wychodzi z tego wielki syf który nie wiadomo jak działa i dlaczego w ogóle działa. A w php jakoś się daje sklecić system, wydajność jest ważniejsza od jakości i nie czuć tych problemów.
witam,
więc bez zbędnych wstępów parę pytań:
1. nie wiem czy dobrze rozumuje: model to czesc programu, ktora jest posrednikiem pomiedzy DB a widokiem/akcja. wykonuje ona zapytania, wstawia dane i je zwraca ( w czystej postaci). dobrze rozumuje??
2. czy dla skryptu forum (ktory wlasnie chce zaprojektowac w oparciu o MVC) cos takiego bedzie poprawne:
a) dla wyswietlenia tematow
- kontroler ustala, ze przegladarka chce zobaczyc topiki. wywoluje widok 'showforum($forumid)'
- widok wywoluje model 'showforum($forumid)' ktory zwraca dane z bazy danych w czystej postaci (tablica)
- widok obrabia te dane, i przekazuje wynik do szablonow
dla wstawienia postu
- kontroler ustala ze przegladarka chce dodac posta. wywoluje akcje 'addpost'
- akcja wywoluje model 'addpost' ktory tylko robi polecenie insert i zwraca, czy udalo sie wstawic posta
- ta sama akcja po udanym wstawieniu wywoluje widok 'showtopic($topicid)'
-widok wywoluje model 'showtopic($topicid)' ktory zwraca dane z bazy w czystej postaci (tablica)
- widok obrabia te dane i przekazuje je do szablonow (smarty)
3. zamierzam wszystkie metody (nawet takie standardowe jak showtopic, showforum itp) umiescic jako moduły. Czyli taki moduł powinien składać się z modelu i widoku/akcji ?
A czy taki przebieg pracy aplikacji jest zgodny z modelem MVC?
ale teraz wywiązuj się pytanie: jeżeli dodam nową funkcjonalność do aplikacji (powiedzmy wyświetlanie userów) to oprócz widoku, który przetwarza dane z modelu, musze także dodać model odpowiedzialny za wyciągnięcie odpowiednich danych z bazy i przekazanie w czystej postasci widokowi. czy tak?
Nie wiem czy moja idea jest dobra ale czy mozna najpierw pobrac dane z GET POST i SESSION, potem wg nich stworzyc lancuch akcji a potem w petli while je wykonac oczywiscie ostatnią akcją byłoby wyswietlenie odpowiedniego widoku ...
no tak, ale jeżeli nowy widok bedzie kozystal z nowej tabeli w db to skad model ma o niej wiedziec, a jak ma stworzyc odpowiednie zapytanie zwracajace odpowioednie dane?
ArticleModel:
- dodaj
- edytuj
- usun
- get title
- get author
- get body
ArticleView:
pobiera z modelu ArticleModel -> get title, get author, get body, formatuje i wyswietla
AddArticleAction:
dodaje za pomoca ArticleModel -> dodaj
W ten sposób mamy obiektowość. Można by było zrobić każdą metodę ArticleModel jako osobny model ale po co??
Co sądzicie?
@ogólnie:
Nie ma sensu zastanawiać się, czy model jest jeden, dwa czy dwadzieścia. Model to tylko warstwa. To tak jakby mieć dwie warstwy bazy danych. Można mieć dwie bazy danych, ale obie należą do warstwy bazy danych. Masłomaślanizm powyższego dowodzi, że mówienie o modelach jest bez sensu.
Ja jestem przeciwny jakiemuś akcentowaniu w nazwach itd. że mamy do czynienia z modelem. Po prostu klasy Article, User, itd. Cała zabawa polega przecież na tym, żeby model był odseparowany od HTTP i innych okropności. Żeby był to ładny, elegancki projekt obiektowy (OOD), bez zawiłości protokołów, sesji, itd. Więc nie żadne $model->getData(), nie żadne metody modelu, tylko po prostu $articleContainer->getArticleById(12345) itd.
A nazywanie klasy ArticleModel jest niekorzystne z tego powodu, że skoro model jest odseparowany od całej reszty, to też nie wie nic o kontrolerze i o MVC. Jak tworzę klasę do artykułów, to nazywam ją Article. Jak tworzę klasę do artykułów w aplikacji MVC, to powinienem postępować tak samo jak poprzednio. W końcu o to chodzi w MVC.
@dag:
To już zagadnienie nie MVC, tylko ogólnie OOD, ale podane przez ciebie metody do Article(Model) są złe. Tzn nie złe z punktu widzenia modelu, tylko złe z punktu widzenia hierarchii klas. Jeżeli są sobie artykuły, to logiczne jest, że potrzebuję klasy Article. Ale potrzebuję też kontenera artykułów. Inaczej się nie da tego sensownie zrobić. Jeżeli mam zbiór artykułów (a przecież mam), to ten zbiór musi być "czymś", czyli musi mieć obiekt. A jak obiekt to i klasa. Kontener. Na tym etapie też robi się tzw. projekt trwałości, czyli po ludzku zaznacza, co siedzi w bazie danych (artykuły). I kontener je wyciąga.
hmm no tak w MVC nigdy nie wnikalem ale teraz moje podstawe pytanie nie odnosi sie w sumie tylko do MVC.
jeden Artykul obrazuje klasa Article powiedzmy
<?php class Article { var $author, $title, $content; } ?>
Zaczynamy od tego, że mamy ten Article tak jak w twoim kodzie. Wyszukiwanie artykułów nie jest zadaniem dla samego artykułu, więc potrzebujesz coś do tego. Kontener. Manager. Jak zwał tak zwał. Nie chodzi o to, żeby ten kontener trzymał 10 czy 100 artykułów, tylko żeby umożliwiał do nich dostęp. A to, że artykuły są w bazie, i że jest jakiś SQL, to jest jego wewnętrzna sprawa.
Pewnie, może sobie wszystkie wczytać i przechowywać, ale to będzie mało wydajne.
Popatrz na to z punktu widzenia MVC. Nie możesz do akcji wrzucić zapytania SQL, które wyciąga artykuły, bo to jest Model. Więc gdzieś to zapytanie musi się znajdować, i to najlepiej w jednym miejscu. Nie może znajdować się w klasie Article, bo musiałbyś stworzyć artykuł a potem go wyciągać - masło maślane. No chyba że w metodzie statycznej, wtedy klasa Article pełni podwójną funkcję. Więc potrzebujesz osobną klasę która potrafi wyciągać artykuły.
Dobrze jest sobie popatrzyć na dostępne systemy DAO, takie jak Turbine/Propel etc. Chociaż tam akurat rozwiązali to poprzez metody statyczne.
hm dzis sobie w szkole myslałem o mvc i narysowałem taki oto "projekt"
1. Ja bym to zrobił tak, że Widok może dostać dane bezpośrednio od Modelu. Tzn normalnie pobiera dane. Pamiętając o tym, że nie wolno mu niczego modyfikować, ale nie da się tego wymusić przez jakieś zabronienie dostępu.
2. Hmm, gdzie? Można w pliku ini. Można w wielkiej tablicy php (np. phrame). Można mieć wszystko hard-coded w kodzie akcji (np. mojavi). Nie widziałem jeszcze sensownego systemu, gdzie to wszystko siedziałoby w bazie danych, ale jest to niegłupie rozwiązanie - ułatwia zarządzanie akcjami.
3. Jak chcesz. To jest niezależne od MVC. Ale po to wymyślałem router, żeby był obiekt odpowiedzialny za tworzenie linków
5. -
6. Szablony są niezależne od MVC. Klasa Widoku to w końcu tylko klasa. Jaki szablon ma w środku, to już jej sprawa, i reszcie aplikacji nic do tego.
7. Jestem genialny . Serio, w sumie to nie wiem. phparchitect. sitepoint. phrame. Polecam też materiały Suna i Microsoftu na temat MVC i takich. Oni to mają trochę lepiej uporządkowane.
A router to wyszedł tak sam z siebie, i nie ma go ani w Javie, ani w .NET.
@DeyV: ale phiend wcale nie ma routera. Ba, nie znam żadnego obecnie funkcjonującego frameworka, który ma router. Owszem, wszędzie przejawia się koncepcja, że z URLa trzeba wyciągnąć nazwę akcji, i jakiś kawałek systemu się tym zajmuje. Niektóre systemy dają tutaj kilka możliwości (index.php?page=foo, index.php/foo, itd). Np. phiend daje kilka możliwości.
Ale nie o to chodzi. Chodzi o to żeby wywalić tą funkcjonalność poza kontroler. Zrobić takie MVCR. I to mi daje dużą elastyczność bo mogę router wymieniać nie ruszając reszty systemu.
A co do wymyślania i nazywania - w sumie to bez znaczenia. I tak nikt routera nie patentuje .
to moze trzeba opatentowac bill ci opatentowal podwojne klikniecie to i my mozemy
bela_666 @ przeczytaj dokładnie artykuł o MVC na php.pl.
Akcja to np. dodawania usera, usuwanie artykułu.
Widok wyświetla, jak sama nazwa wskazuje czyli to co widzimy ;-). Wytłumaczone łopatologiczne, tak na chłopski rozum ;-) lepiej masz wszystko opisane w artykule.
zapytania nie wymagające akcji: SELECT
zapytania wymagające akcji: UPDATE, INSERT
:D:D
@Bela:
Lepiej nie mówmy o zapytaniach, bo w MVC wcale nie musi być bazy danych. A zwłaszcza nie powinno być tego widać w akcjach i w Widoku.
W moim artykule był taki ładny schemat działania MVC, ale chyba się nie wyświetla .
Powinno być tak:
1) Zawsze uruchamia się akcja, która robi wszystkie zmiany w Modelu (addUser, deleteUser, modifyUser, blah, blah).
2) Akcja zawsze podaje, jaki widok uruchomić
3) Zawsze uruchamia się widok, który wyciąga z Modelu potrzebne dane i wyświetla je, bez zmieniania niczego
Czyli w najprostszym przypadku (tylko wyświetlamy coś) akcja nic nie robi, poza wskazaniem widoku. Inna sprawa, czy chce nam się robić klasy dla takich jednolinijkowych akcji, ale tak wygląda oficjalny MVC. Zawsze jest akcja - widok. Tak więc nie ma żadnego rozróżniania zapytań wymagających i nie wymagających akcji. Zawsze jest akcja, a jak ta akcja nic z siebie nie robi, to już jej sprawa.
Tak na marginesie, w phiendzie zrobiłem tak że w zdegenerowanym przypadku bez żadnych modyfikacji można przejść od razu do widoku, bez wywoływania "pustej" akcji. Tylko że to się nazywało "logic action" i "view action". Tak też można, ale ze świadomością, że naginamy wzorzec żeby poprawić wydajność.
ok to mi jeszcze ukazał się taki oto problem:
wyobraźmy sobie, że robię silnik/cms oparty na mvc. Na stronie opartej o taki skrypt może być jednocześnie potrzebnych kilka widoków np. widok newsow, widok menu, widok stopki i Bóg wie jeszcze czego. A jak wiadomo widok musi być ostatni - więc jak wywoływać te poszczególne widoki? Ja pomyslałem nad kolejką ale co wy o tym sądzicie?
Hmm, są dwie zasady:
1. Widok powinien być jeden.
2. Jeżeli potrzebujesz więcej widoków, patrz punkt 1.
Tak naprawdę jest. Żaden wzorzec nie jest idealny i MVC po prostu nie podejmuje tematu: co zrobić jak chcemy mieć wspólne menu itd. I nie musi. Zauważ że nic ci nie zabrania includować w klasie widoku wspólnego szablonu menu. Oczywiście, wspólny szablon menu wymaga też wspólnego kodu który stworzy to menu i podstawi odpowiednie wartości. Ale ten sam problem miałbyś ze zwykłymi skryptami, które korzystają z szablonów i też muszą jakoś współdzielić kod. MVC ani tutaj pomaga ani przeszkadza.
Może trochę jednak ułatwia, bo mamy klasę widoku, więc możemy jakoś sobie dziedziczyć, np. ArticleView extends ViewWithMenu itd. Możesz wpychać to co wypluwa klasa widoku w jakieś headery/footery generowane przez inną klasę. Jest pole do popisu .
BTW nie mówimy "widok stopki", tylko raczej "klasa wyświetlająca stopkę należąca do warstwy widoku". Podobnie jak bez sensu jest mówić "model artykułów".
Witam,
Mam taki maly OT. Otoz stworzylem sobie ostatnio cos na wzor MVC. Jest to bardzo prosta aplikacja, wyswietlanie listy userow i wyswietlanie danych jednego usera. Idea jest prosta. Wywoluje kontroler w zaleznosci od tego jaka wartosc przyjmuje zmienna $_GET['show'], kontroler wywoluje widok, widok pobiera dane z modelu i wyswietla strone.
Jednak moje rozwiazanie jest malo elastyczne poniewaz kazda akcja ma "swoje pliki".
np wylistowanie userow:
UsersController
UsersModel
UsersView
wyswietlenie danych jednego usera:
UserController
UserModel
UserView
Problem pojawia sie np jak bym dodal jeszcze inne funkcje do tej aplikacji, wtedy bym zginal w gaszczu plikow
1) Myslalem, zeby zrobic jeden kontroler, wtedy kazda akcja, miala by tylko plik modelu i formatowana przez Smarty strone. Ale jak to zrobic?
2) Chcialem jeszcze zrobic "glowny" kontroler. Byl by to trzon aplikacji. Jego zadaniem bylo by wywolywanie "malych kontrolerow", ktore mialy by okreslone zadania np kontroler userow, kontroler newsow.
Przyklad:
Kontroler z natury tego wzorca jest jeden.
@hamlecik:
Ja to robie w ten sposob:
Mam jeden glowny kontroler, ktory pobiera dane od usera i na ich podstawie odpala odpowiednia akcje, ktora jest w konfigu.
Przyklad wywolania:
www.example.pl/index.php?go=/phppl/news/12
W pliku z konfigiem mam np.:
$actionsConfig['phppl'] = array( 'news' => 'NewsAction' );
(oczywiscie to tylko kawalek, bo brakuje fallbackow i defaultowych akcji)
phppl - oznacza widok
news - to nazwa akcji
12 (i ew dalsze wartosci po slashu) - to parametry akcji
I teraz kontroler na podstawie tych danych odpala akcje, ktora znajduje sie w action/phppl/NewsAction.class.php:
NewsAction->run( $view, $param );
$view = 'phppl'
$param = array(12)
Na tej podstawie akcja cos tam sobie mieli i korzysta np z NewsModel, ktory to potem odpowiednio przekazuje do widoku - umnie jest to smarty.
I tyle
Seth: Wielkie dzieki za rozjasnienie mi sprawy, chociaz to co napisales troche mi koliduje z tym co czytalem. Czy kontroler nie powinienen wywolywac akcji, akcja wywoluje rzadany widok, a widok pobiera z modelu potrzebne mu dane?
Faktycznie troche zmodyfikowalem wzorzec ale inny niz podales.
Pora na moje pytanie
Dwa różne schematy działania:
1. user chce zobaczyc tresc danego wątku na forum
ActionController >> showTopic >> showTopicView
2. user dodaje nowy post, na koniec wyswietla sie taka sama tresc danego wątku
z tą jednak roznica ze na gorze jest "belka" z napisem "post dodany pomyslnie"
ActionController >> addNewPost >> showTopic >> showTopicView
Jeśli już tu są jakieś błędy to mnie poprawcie. Teraz jednak podstawowe pytanie.
Jak i gdzie zamieścić ten kod php odpowiedzialny za wyświetlanie belki z "post dodany pomyślnie".
U mnie to wyglada tak:
Vengeance, co u Ciebie robi showTopic?
to jest akcja wyswietlajaca to co widzisz teraz
tytul wątku i wszystkie posty (odpowiedzi) userów
A po co Ci i showTopic, i showTopicView? Przeciez mozna to zrobic tylko za pomoca showTopicView. Z reszta przegladajac ten topic i czytajac art Hawka mozna sie dowiedziec, ze akcje sa czescia MVC odpowiedzialna za updatowanie uduwanie i dodawanie danych do np. bazy danych - dlatego nie wiem co ma akcja do wyswietlenia topicu. Tym powinien zajac sie widok, pobierajac przez model dane i je wyswietlajac.
Jak sie myle to mnie poprawcie.
pozdrawiam i zycze swietnej zabawy sylwestrowej do rana
Zaraz, moment, akcja jest częścią kontrolera - i nie ma nic wspólnego z danymi - model jest odpowiedzialny za prace z danymi, widok za wyświetlanie danych w porządanym formacie - natomiast kontroler (więc i akcja) jest odpowiedzialny za aktywowanie modelu, wyciągniecie od niego właściwych danych i przekazanie ich do widoku - który cały ten szajs wyświetli.
bregovic, sciagnij sobie pdf'a z artem hawka 'Wprowadzenie do MVC'. Jest tam bardzo fajny schemat obslugi zadania (rozdzial: 'Obsługa żądania'). Niestety w arcie na wortalu go nie ma.
@kurak :
Hmmm... no to mamy tu przypadek rozbieznosci zeznan Hawk w swoim arcie jasno dal do zrozumienia, ze akcje uruchamiamy tylko w przypadku, kiedy zachodzi potrzeba zmiany stanu danych w modelu. Najlepiej poczekajmy na wypowiedz Hawka
Cale szczescie, ze poruszany jest ten temat, bo wlasnie pisze kontroler...
ee ale to w sumie jest dowolne! nie przesadzajmy ze jesli hawk powie to i to to jest to wlasnie MVC a cala reszta nie.
MVC takze nic nie mowi o akcjach przeciez! ich nawet nie musi byc.
Pozatym wzroce sa po to takze aby je naginac (czesto tak powstaja nowe wzroce) hehe ;]
Żeby wyjaśnić rozbieżności:
Diagram to nie implementacja. Jeżeli kontroler ma uruchomić po prostu widok, i nie ma żadnej modyfikacji (czyli nie potrzeba do tego specjalnej akcji), to jak to zrobić? Można sobie wyobrazić taką implementację, gdzie bezpośrednio wykonywany jest widok (np. phiend), lub taką, gdzie potrzebna jest jakaś minimalna akcja, która odpali ten widok (tak ma większość). To kwestia tego, jak sie napisze framework. Ale idea jest ta sama - nie ma żadnej modyfikacji, chcemy wyświetlić widok jak najmniejszym kosztem.
Hmm... Hawk, podsumowywując - nie ma znaczenia czy nazwiemy to akcją, czy widokiem, czy czymkolwiek - to musi być jakaś klasa, która coś wyświetli. W przypadku phienda, są to klasy z funkcją display - które ewentualnie łączą się z modelem i wyświetlają output (np. przy pomocy smarty).
Innym rozwiązaniem (które tak na prawdę jest dokładnie tym samym - z tymże z innymi nazwami) jest stworzenie akcji - które nie robią nic innego jak wyciągnięcie danych z bazy i wyświetlenie ich.
Różnica, z tego co widzę polega na ilości kontroli jaką przekażemy widokowi. Mnie, wydaje się że widok jako taki nie powinien mieć dostępu do modelu - bo zbyt komplikuje to implementację. Wydaje mi się że to kontroler (więc i akcje) powinien pracować na api modelu - a widok powinien zająć się wcale niełatwą sprawą wyświetlania danych...
Czy się mylę?
@bregovic: krotka mowiac myslisz o tworzeniu widoku przez akcje
i przekazywaniu mu jakos (glownie przez parametry w konstruktorze)
jedynie wyniku jakis tam operacji na modelu (pobierania danych).
Z tego co widze bo roznych przygladach wiele skryptow przekazuje do
widoku instancje modelu aby ten zrobil sobie "co potrzebuje". Jednak moze zrobic takze cos wiecej. A w przypadku rozwiazania podanego powyzej mialby dostepdo tego co naprawde jest mu koniecznie.
Czy tak?
Podłącze się pod temat, żeby nie zakładać nowego
Jestem na etapie budowania aplikacji w oparciu o phiend (co prawda to tylko podstawa, którą trzeba dosć mocno rozbudować, ale zawsze).
Z tego co zdążyłem się zorientować, nie ma tutaj matod dających dostęp to parametrów POST, GET itp, a jako, że nie bardzo chcę operować na nich bezpośrednio - muszę sobie taki kawałek kodu dopisać.
Problem jest właśnie z parametrami GET bo prawdopodobnie czasami na wywołania nałożony będzie mod_rewrite, zresztą ze standardową postacia index.php/moja/akcja/ też nie ładnie wyglądały parametry get przekazane po znaku zapytania.
I tu właściwe pytanie - jak radzicie sobie z wywolaniami w stylu /artykul/15/strona/6 ?
Jakieś idee poza ręczną analizą REQUESTED_URI - którą defacto powinien odwalić rontroler ?
Jeżeli chodzi o index/nazwa/akcji, to na pewno możesz to zrobić za pomocą standardowego phienda. Tak działa np. strona projektu.
Jeżeli chodzi o artykuł/16/strona/5, to istotnie kontroler powinien takie coś odwalić. Ale sam framework nie, bo nie wie nic o artykułach. W zależności od tego, ile akcji potrzebuje takich danych, można wydziedziczyć wszystkie/niektóre akcje z abstrakcyjnej klasy, która parsuje takie coś i wyciąga to co potrzeba.
Można też przyjąć, że url zawsze ma postać cośtam/nazwa/wartość/nazwa2/wartość2 itd. Tego phiend automatycznie nie parsuje, i wtedy najlepiej chyba byłoby zrobić klasę bazową dla wszystkich akcji.
ok no więc ja poruszę troche inny temat MVC. Jest to własciwie tylko małe uniedogodnienie, ale czasem może wkurzyć. Być może ja coś źle robię.
mam akcję showcomments. W tej akcji są wyświetlane komentarze i formularz do wstawienia nowego komentarza. Gdy kliknę na przycisk dodaj komentarz, przejdę do akcji addcomment. Ta akcja zwróci nazwę widoku showcomments, wieć znowu zobaczę komentarze, ale w pasku adresu będzie nadal addcomments i gdy użytkownik niechący lub chcący kliknie F5 to do bazy znowu doda się identyczny komentarz (pomijam, że przeglądarka ostrzega przed tym).
Można by w akcji addcomment zrobic header( 'Location'); do akcji showcomments i po problemie, ale to z kolei odbiera od zasady MVC. Co Państwo o tym myślą?
pozdrawiam
Można zwrócić widok z tekstem "komentarz został dodany..<a>zobacz komentarze</a>"
albo po prostu uneimożliwić dodanie takiego samego komentarza, poprzez sprawdzeni przy dodawaniu do bazy czy nie istnieje juz dokladnie taki sam rekord (pomijając czas oczywiście, no i trzeba uważać żeby przy okazji nie zablokować użytkownikowi możliwości wielokrotnego postowania popoularnych fraz np. "ok")
nawiasem mówiąc, przy okazji implementujemy mały mechanizm anty-floodowy.
Fakt, nie odbiega. Patrz np. phrame.
A generalnie to po prostu potrzebna jest kontrola postback. A przekierowanie jest właśnie jedną z takich metod.
Zresztą można nawet puścić header już w początkowej akcji. Redirect i tak jest tylko wewnętrznym trikiem, a nie widokiem.
czy mozna laczyc MVC z innymi wzorcami, ktos juz tak probowal?
Mozna? Nawet trzeba! Np Dao, Intercepting Filter, Decorator (do widoku).
Btw sam MVC jest zbudowany na Composite, Observer, Strategy i pewnie jeszcze kilku
Witam!
I ja pozwolę sobie dołączyć się do dyskusji Zacząłem właśnie pisać własny framework. Początkowo miał to być CMS, ale stopniowo ewoluowało do frameworka. Planuję wykorzystać model MVC, jednak męczy mnie parę kwestii...
Po pierwsze:
We wprowadzeniu do MVC wyczytałem że powinien być tylko jeden kontroler. Co w sumie logiczne jest jeśli system ma być elastyczny i łatwo się dopasowywać poprzez wyedytowanie configa. Jednak problem pojawia się jeśli chcemy zastosować do tego czegoś subdomeny. Mamy dany kontroler kontroler.php. I teraz w zależności od parametrów przekazanych do niego chcemy wyświetlić dział newsy albo czat. Czyli kontroler.php?dzial=newsy kontroler.php?dzial=czat I wszystko ładnie i pięknie do czasu aż wprowadzimy subdomeny. newsy.domena.pl czat.domena.pl I co się wtedy dzieje? Wychodzi na to że trzeba zastosować kilka kontrolerów. Chyba że... wykorzystać mod_rewrite, ale ten nie zawsze jest dostępny. Można też teoretycznie wykorzystać stronę błędu 404 do "emulacji" mod_rewrite ale to rozwiązanie mało eleganckie. A jeśli podzielimy kontroler to znowu stracimy możliwość łatwej konfiguracji i system w ten sposób będzie mało elastyczny (właściwie przypisany do jednego konkretnetego rozwiązania - czyli przestanie być frameworkiem). Może więc w każdej subdomenie dać plik index.php, w którym wysyłać header Location, przekierowujący do kontrolera i przekazujący mu wszystkie parametry? To też rozwiązanie mało eleganckie i rozwiązujące problem tylko częściowo. A może są jeszcze jakieś ciekawe rozwiązania tego problemu?
Druga sprawa:
Druga? W trakcie pisania tego postu przyszło mi do głowy kilka pomysłów na rozwiązanie pozostałych problemów
Pozdrawiam
Ja mam coś takiego: localhost/język/content(lub forum, chat)/moduł/opcja/id/
przykładowo: localhost/pl/content/articles/show/1/
Do subdomen, można by rzeczywiście użyć mod_rewrite... jaki w tym problem ?
przecież każda subdomena może wskazywać na ten sam katalog, z tym samym index.php i kontrolerem, a kontroler sprawdzi poprawność $_SERVER[HOST].
Jeżeli stwierdzi, że ma doczynienia z odwołaniem z subdomeny, ustala np. katalog z którego ma brać akcje np. /actions/chat/*
Pozatym do tego służy także wzorzec FrontControllera pozwalający utworzyć "jeden spójny punkt wejścia" do aplikacji.
Mam pytanie z nieco innego obszaru. Nie dysponuję gotowym kodem, rozważam jedynie teoretycznie, ale postaram się przedstawić moje wątpliwości w miarę zrozumiale.
Rozpatrując modularyzację aplikacji wygodna jest możłiwość wykonywania sekwencji akcji (czy też łańcuchów akcji; być może mylę pojęcia) przy czym akcje te mogą być dynamicznie kolejkowane w trakcie wykonywania dowolnej akcji.
Przykład: stronę tworzą takie komponenty: drzewiaste menu (np: katalog produktów w e-sklepie - kategorie), lista produktów (główna treść), pole wskazujące w jakim miejscu strony jest użytkownik. Aby wygodnie rozdzielić zadania i ułatwić edycję, każdy z wymienionych komponentów strony może być realizowany oddzielną akcją i wywoływany w zbiorczej akcji, choćby tak:
<?php class Store extends Action { public function perform(httpRequest $request, httpResponse $response) { // kolejkowanie potrzebnych elementów, czyli tworzenie omawianej sekwencji akcji Controller::getInstance()->enqueue('displayCatalog'); Controller::getInstance()->enqueue('displayLocation'); Controller::getInstance()->enqueue('displayProducts'); } } ?>
Jakiś czas temu razem z paroma osobami ze świata napisaliśmy (a oni dalej rozwijają) framework MVC -- Cake php (www.cakephp.org). Rozwiązanie problemu URLi ściągnęliśmy z RoR (www.rubyonrails.org).
Pomysł opiera się na przypisaniu adresów do konkretnych klas i metod, tak, że np. adres:
www.example.com/blog/view/55
odpowiada klasie BlogController (Controller to "C" w "MVC") i metodzie view() w tej klasie, a "55" przekazywane jest jako parametr do wywołania metody, czyli powyższe wywołanie przekształcane jest w:
pies: czyli dla każdego modułu musisz tworzyć nowy Controller ? Nie widze najmniejszego sensu.
Mam link w takiej postaci:
/pl/content/home/ - dla strony głównej portalu. Jeśli chce uruchomić np. blog to daje.
/pl/blog/home/
opcjonalnie mam link z parametrem /pl/blog/entry/view,13/ (przykład).
Request: (cząstka)
<?php public function SimpleVirtualURL() { $iURL = (http://www.php.net/isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : THRORIN_LINK); $this->iURL = http://www.php.net/explode('/', $iURL); } ?>
<?php public function Analyse() { $this->request->SimpleVirtualURL(); $this->lang = (http://www.php.net/empty($this->request->iURL[1]) ? THRORIN_LANG : $this->request->iURL[1]); $this->system=(http://www.php.net/empty($this->request->iURL[2]) ? 'content' : $this->request->iURL[2]); $this->module=(http://www.php.net/empty($this->request->iURL[3]) ? 'home' : $this->request->iURL[3]); if(!http://www.php.net/isset($this->request->iURL[4])) http://www.php.net/exit(); $url = http://www.php.net/explode(',', $this->request->iURL[4]); # czyszczenie tablicy iURL $this->request->iURL = http://www.php.net/array(); $this->option=$url[0]; $this->id=$url[1]; } ?>
<?php $Router->connect('/a4', http://www.php.net/array('controller'=>'Product', 'action'=>'view', 'a4'); ?>
Witam,
hmmm, no to wziąłem temat po raz kolejny już na raz przeczytałem i nie wiem już co myśleć. Tyle tutaj mądrości Więc ja widzę co tak i chcę się upewnić czy dobrze rozumuje:
adres wygląda tak: http://www.example.com/<action>/<view>/
i teraz wchodzimy na stronkę:
http://example.com/: odpalamy dośmyśną akcję i domyślny widok
http://example.com/articles/: odpalamy akcję articles i domyślny widok dla niej
http://example.com/news/showAll/: odpalamy akcję news i widok showAll
http://example.com/news/rss/: odpalamy akcję news i widok rss (wyświtlamy rssy )
http://example.com/news/pdf/423: odpalamy akcję news i widok pdf oraz dajemy jeszcze na końcu id news'a który ma być wyświtlony w formacie pdf'a
i teraz czy czuję o co biega w tym. Co inaczej powinno to działać ?
To ja się dołącze z innym pytaniem. Co zrobić z Apache/php aby takie URLe jak powyżej działały? Co dać w .htaccess aby każdy taki URL odnosił się do http://example.com/index.php
Ważne także by URLe kończące się jakimś rozszerzeniem, lub takie:
http://example.com/katalog/img.jpg?a=tekst
nie były przeżucane do index.php ale interpretowane standardowo
Vengeance: to pytanie nie ma duzego zwiazku z tematem, wiec zadaj je (a w zasadzie znajdz odpowiedz, bo to juz nie raz bylo przerabiane) w opowiednim miejscu, OT tutaj niepotrzebne.
Strzałek: uruchom admina
Jako, że nabyłem doświadczenia (no dobra, trochę), przebudowałem cały system do takiej postaci:
/module/action/parametr/paratemtr1/parametr2
defaultowo /content/display/news
FilterChain - (klasycznie) kolejka -> ActionChain:
<?php public function execute( HttpContext $context, FilterChain $chain ) { $build = $context->module.'_'.$context->method; $model = new $build(); $model->perform($context->what, $context->vars); $chain->nextExecute($context); } ?>
<?php class content_display public function perform($what, $a = null) { if($a == null) { $this->display($what); } else { $this->displayByArgs($what, $f); } } ?>
Nie bede zakladal nowego topic'u poniewaz moje pytania(e) dotycza(y) MVC.
Wszystko co wiem o tym wzorcu wiem z mini-frameworka zaprezentowanego niegdys przez hwao. U siebie zrobilem wiec bardzo podobnie, nie wiem jednak jak zaimplementowac akcje i w jaki sposob.
Stwórz sobie interfejs dla akcji, który posiada jedną metodę, w której akcja dokonuje wszystkich operacji na danych. Żeby nie była odizolowana od otoczenia przekaż jako argument wszystkie potrzebne informacje z kontekstu (żądanie, obiekt sesji itp.). Akcje lepiej uruchamiać w łańcuchach, więc musisz znaleźć sposób na zapisanie nazwy kolejnej akcji (ja to zapisuję w obiekcie Context). Jeżeli nie ma następnej akcji zapisujesz pusty ciąg znaków. Akcje uruchamiasz w pętli...
Troszke strasznie to brzmi, cóz bede musial liczyc ze hwao zaimplementuje jeszcze do tego mini frameworka akcje, albo poszukac jakichs przykladow.
W skrócie, ale od początku:
- Mamy FronController, który uruchamia to, co potrzebne jest każdej akcji.
- Na podstawie danych od użytkownika (np. z URL) uruchamia on odpowiednią akcje (dajmy na to listaNewsow). Tu na chwile praca FrontControllera się kończy, a funkcję określaną jako Controller przejmuje uruchomiona akcja.
- akcja wczytuje plik modelu, pobiera z niego odpowiednie dane (tu: newsy), co może wyglądać tak:
<?php require_once( 'model' ); class listanewsowAction { private model; public function __construct() { $this->model = new Model; } public function uruchom() { $dane = $this->model->listaNewsow(); } } ?>
Wg. mnie to zależne jest od Ciebie jak framework ma działać.
IMHO FrontController uruchamia model, akcję i widok. Model pobiera dane i robi z nimi jakieś czary, przekazuje akcji, a akcja daje widokowi i mamy wynik.
To ja zadam pytanie z seri pytań oczywistych (dla innych) . Przedstawie to obrazowo:
Czy model jest klasą obsługującą np. daną tablę w bazie danych:
<?php class News extends Model { protected $tableName = 'news'; protected $fields = http://www.php.net/array ('id', 'title', 'author_id', 'date', 'content'); } $table = new News (); $table -> WhereAuthor_idEqual('1'); $table -> OrderByIdDesc(); $result = $table -> select (); ?>
<?php class News extends Model { protected function getNews () { $sql = http://www.php.net/mysql_query ('SELECT `id`, `title`, `date`, `content`, `users`.`name` as author FROM `news` IN
NER JOIN `users` ON `author_id` = `users`.`id` ORDER BY id DESC'); while ($row = http://www.php.net/mysql_fetch_array ($sql)) { $result[] = $row; } return $row; } #funkcja wykozystywana przez kontroler do pobierania danych od modeli public function get () { $data = $this -> getNews (); return $data; } } ?>
Te wszystkie klasy należą do modelu. Model jest to wewnętrzna logika aplikacji, włącznie z częścią komunikującą się z bazą danych. Zazwyczaj część odpowiadającą za komunikację z bazą danych wydorębnia się w modelu (w moduł DAO - data access object) ale nadal logicznie rzecz ujmując jest to część modelu. Przynajmniej ja to tak rozumiem.
Jesli moge zastapic slowo model akcja to akcja ma za zadanie wykonac operacje na danych nie dbajac gdzie i jak sa zapisane oraz jakiego sa formaty (no oczywiscie w pewnych granicach). Jak dobijasz sie dodanych to juz raczej nie ejst sprawa modelu, mozesz zastowosowac metode aktywnego rekordu, jakas abstrakcje w stylu PEAR::MDB lub SDO i inne wynalazki.
Witam,
Wydaje mi sie ze w moim projekcie udało mi sie zaimplementowac wzorzec MVC, moze nie dokladnie i nie idealnie ale przeciez nie o to chodzi, trzeba korzystac z pasujacych nam rozwiazan a nie wdrazac je na sile.
Doszedlem jednak do pewnego momentu, ktory zainteresowal mnie. Router rozbija URL i zwraca jako tablice. Pierwszy element tablicy to moduł, ktory ma zostac "odpalony". Wszystko jest przemyslane i dobrze dziala, ale teraz mam dobudowac jeszcze jeden, administracje.
Nie moze byc on wlaczany na tych samych prawach jak inne moduły. Znajduje sie on w innym folderze, w innym folderze beda jego szablony. Zle by bylo przeciez gdy w folderze styli byly default, jakisinny, styl_do_admina.
W moim projekcie FrontController, to glowna klasa zarzadzajaca modulami do wczytania. Jak zastrzec ze modul 'admin' ma byc traktowany w inny sposob?
Nie chodzi mi oczywiscie o to zebyscie powiedzieli "potraktuj to if'em" bo tak mozna najprosciej. Chodzi mi o to jak wy robicie to u siebie.
Nie jestem pewien czy Router powinien rozbijac URL na tablice, wydaje mi sie ze to Geqest powinien to robic a na Router spada odpowiedzialnosc za dostarczenie mechanizmu tworzenia linkow i dostarczenia info o akcji jaka zostala zarzadana.
Nie wiem czy dobrze rozumiem ale czy pytasz o autoryzacje? Czy chcesz wiedziec czy uzytkownik X ma prawo wykonac akcje Y? Ja to robie w ten sposob, ze te akcje, ktore maja ograniczona liczbe uzytkownikow (np. akcje administracyjne) przed swoim wykonaniem musza wykonac akcje autoryzacyjna, ktora jest zwykla akcja tyle tylko ze jesli stwierdzi ze user X nie ma prawa wykonac akcji Y to rzuci wyjatkiem a do wykonania zarzadanej akcji nie dojdzie. Daje mi to duza elastycznosc co do wyboru metody i algorytmu autoryzacji, wszysko mam w jednym miejscu i cokolwiek by sie nie zmienilo wystarczy ze zmienie jedna akcje aby dostosowac sie np. do LDAP'a
Ja w ogóle rozdzieliłem kontroler części administracyjnej i użytkownika (apache jest u mnie front controllerem).
W konfiguracji http ustawiłem też aby część adminstracyjna serwisu była dostępna pod innym portem przykładowo 8100. Natomiast w katalogu htdocs mam dwa podkatalogi 'user' i 'admin'. kiedy użytkownik wchodzi poprzez tradycyjne 'www.mojadomena.com' apache przekierowuje na kontroler w katalogu 'user' a kiedy wchodzi na 'www.mojadomena.com:8100' apache przekierowuje na kontroler w katalogu 'admin'.
Oczywiście aby dokładnie tak to załatwić trzeba mieć pełny dostęp do konfiguracji apache'a.. ale ogólnie idea jest taka, że wydzieliłem osobne ścieżki na część użytkownika i administratora co oczywiście nie przeszkadza im korzystać z tych samych modułów.
Squid: zle zrozumiales, fakt, autoryzacja bedzie kolejnym krokiem, ale chodzi mi wlasnie o to o czym mowi mariuszn3.
Rozdzielenie czesci administracyjnej od czesci uzytkownika. Poczynajac wlasnie od kontrolera. Rozwiazanie ciekawe, ale wymaga jak juz napisał dostepu do Apache'a.
Witam,
Ano nic trudnego, ale nie chce poprostu aby w folderze ktorym trzymane sa moduly byl takze trzymany admin a tpl'ki od admina lezaly w folderze reszty strony.
Niby blahy problem, ale nie chce robic w rodku Frontcontrollera if'a if ( $module == 'admin' ) to odczytuj z innego folderu ;p
Vomit - nie rozumiem twojego podejscia - moze napisz sobie osobna aplikacje administracyjna
front controler to raczej same if'y i switch'e, więc co zaszkodzi dodać jeszcze jeden
Reasumując jeśli nie możesz go zastąpić apachem to chyba nie ma miejsca na inne rozwiązanie.
Ja, gdy chcę mieć pewność, że uruchomine zostaną tylko i wyłącznie te moduły, które chcę, sprawdzam zawsze, czy mam je zapisane w jakiejś tablicy. Przykładowo:
<?php $arrModules = http://www.php.net/array ('kontakt', 'galeria', 'rekrutacja', 'uslugi'); $arrAdminModules = http://www.php.net/array ('admin'); // Zmienna $strModule została nam przekazana z jakiegoś kontrolera, który odczytał
ją ze zmiennych GET/POST if (http://www.php.net/in_array ($strModule, $arrModules)) { // Uruchom dane akcje modułu } elseif (http://www.php.net/in_array ($strModule, $arrAdminModules)) { // Uruchom panel administracyjny } else { throw new Exception ('Ten moduł nie jest obsługiwany'); } ?>
Może poprostu pobawić się uprawnieniami ?
Ja nie wydzielam czesci administracyjnej. U mnie administrator widzi ten sam widok co zwykly user z tym wyjatkiem ze tam gdzie trzeba administratorowi pojawiaja sie jeszcze np. linki edit, delete, add itp. Wymaga to uzycia paru ifow, ale jest bardzo wygodne podczas pracy. Ogladajac cos jako uzytkownik nieraz zauwazam ze cos trzeba zmienic. W takiej sytuacji nie musze sie zastanawiac gdzie to mam w panelu administracyjnym. Zwyczajnie loguje sie jako admin (nie musze nawet przechodzic pomiedzy stronami bo skrypt logowania przekierowuje mnie spowrotem w miejsce z ktorego wyszlo zadanie logowania) i pojawia mi sie odsylacz edit. Prosto i wygodnie. Nie trzeba robic osobnych tplkow poza formularzami.
Popieram przedmówcę - to bardzo wygodne rozwiązanie. Logowanie przekierowuje do strony, która nas do ostatnio oglądanej strony, i te 2 IF-y w szablonach nie mają wpływu na wydajność skryptu. Szablon sprawdza mi uprawnienia danego użytkownika (odwołując się do obiektu User w którym przechowuję te uprawnienia) i jeśli np. użytkownik ma uprawnienie edycji newsów, to koło nagłówka wiadomości pokazuje się link do jej edycji.
Prosto i przyjemnie
Po co rozdzielac. Pisali Ci juz poco? Dajesz w akacji metode np. add_item() i w add_item() dajesz if($admin==ok) ;P itp. Nie rozdzialaj a dodaj kolejne akcje
No przeciez pisze ze nie wszystko jest "add_item" chocby sprawdzenie zamowien w sklepie internetowym czy np. sprawdzenie platnosci itd. To rzeczy ktorych nie mozna zrobic sensownie ifem, musi byc jakis panel.
Nie o to mi chodzi :|
mam cos takiego:
I ja wywołałbym to tak: action=sklep&view=show_zamownienia (zmienan view tlkyo tak, mozna zmienić) I w czym problem?
<?php class SklepAction { function defaults() {} //domyslna akcja function add_item() { if($admin) { formularz dodania pliku } } function show_zamowienia() { if($admin) { spis zamówien } } } } ?>
A nie uwazasz ze zbytnio generalizujesz? Taka klasa jak sklepAction ktora oprocz obslugi sklepu bedzie miala jeszcze akcje do zarzadzania np. zamowieniami, uzytkownikami itd zrobi sie mocno przepasna.
Moim zdaniem zamowienia powinny byc osobnym kontrolerem gdzies wlasie w panelu, a jak nie w panelu to przynajmniej powinna byc jakos zabezpieczona przed dostepem.
i wtedy mozna zrobic osobne akcje dla pokzywania zamowien, zmiany statusu, edycji itd.
A dzieki osobnemu front controllerowi (dla panelu) ktory przyjmie obowiazek sprawdzania autoryzacji na siebie, nie musimy sie o to martwic w kontrolerach administracyjnych.
Nie wiem... może i tak. Tylko teraz jak to zrobić? Osobny kontroller? No nie wiem, ja by dał w starym kontrollerze nową metodę. Np executeAdmin() itp. i ona zajeła by się prawami i czytała akcję np, newsA.action a modele newsA.model.php itd. Może bardziej zaawansowani cos powiedzą No albo zrobić osobny kontroller
tak mnie meczy, w koncu odwazylem sie zaptac...
1.
Jest obiekt "pracownik" - dziedziczy z klasy GenericObject (odwzorowujacej tabele w bazie na obiekt) dodakowo sklada sie z innych obiektow dziedziczacych z GenericObject (np "opinia" - pracownik ma swoje opinie).
Pytanie 1:
Tworzac widok oparty na szablonie smarty, wypada przekazywac mu obiekt np typu "pracownik" zeby szablon sam siegnal do jego metod i powyciagal potrzebne dane (imie, nazwisko, opinie) czy lepiej dla widoku przekazac juz tablice asocjacyjna z wczesniej przygotowanymi danymi (to co w pierwszej propozycji wyciaga smarty, wyciamy wczesniej)...
2.
kontroler.
1. odwiedzam strone wpisujac http://strona.pl/?action=showPracownicy w celu wyswietlenia wszystkich pracownikow
2. glowny kontroler, analizujac parametr "action" includuje klase showPracownicy.class.php, (kazda klasa zaladowana przez kontroler, ma okreslony interfejs), tworzy obiekt tej klasy i wywoluje jego metode 'exec(HTTPReq $req)' (obiekt 'req' grupuje paramtery przeslane od uzytkownika, w tym wypadku nie jest konieczne przeslanie)
3. Funkcja 'exec(HTTPReq $req)' pobiera model (klasa ktora zawiera wszystkie operacje na pracownikach 'dodaj', 'usun', 'pobierz' 'wyszukaj' itp) i wywoluje jego funkcje 'pobierzWszystkichPracownikow()'; funcka zwaraca tablice/kolekcje obiektow typu 'pracownik'
Pytanie2:
Lepiej bedzie utworzyc widok w metodzie 'exec(HTTPReq $req)' obiektu klasy showPracownicy (jak tworzyc to poprzednie moje pytanie), przypisac wszystko do szablonu i go wyswietlic, czy tez zwrocic nazad do kontrolera nazwe widoku + w jakis sposob opakowane dane potrzebne do wyswietlenia, i niech glowny kontroler (ten z ktorym laczy sie uzytkownik i ten ktory stworzyl obiekt typu showPRacownicy) sobie podopisuje zmienne do szablonu i go wyswietli?
Nie wiem czy dobrze rozumuje cala koncepcje tworzenia oprogramowania, ale wole zapytac niz zaczynac pisac i uczyc sie zlych nawykow...
Watpliwosci:
3. czy rozwiazanie typu http://strona.pl/?action=nazwaAkcji jest prawidlowe? (powstanie pewnie bardzo duzo plikow a katalogu /actions/
Myslalem ze mozna np zrobic (pewnie tak sie robi) http://strona.pl/modul/funkcja/parametry i wtedy glowny kontroler bedzie ladowal klase 'modul' (zawiera wszystkie funkcje jakie sa dostepne dla modulu) i wywolywal jego metode 'funkcja' przekazujac jej 'paramtery' + tablice _REQUEST. Rozwiazanie daloby umieszczenie w jednym miejscu wszystkich funkcji zwiazanych z jednym modulem (kolejny problem to czy modulem moze byc "pracownicy" wraz z wszystkimi funkcjami czy to jest zla idea)
4. Czy mozna uzyc stwierdzenia 'model' w stusunku do klasy operujacych (zawiera wszystkie funckje jakie mozna wykonac z obiektem, np wyszukiwanie, itp) na obiektach 'pracownik'?
Ale jak to wygląda w praktyce? Masz różne widoki dla różnych grup? Czy w samym widoku ustawiasz co ma być widoczne dla poszczególnej grupy?
Wydaje mi się, że najbardziej zgodne z wzorcem MVC są osobne widoki.
<?php Aplet user extends Apos_View_Aplet { public function hasGroup($name) { return $this->user->hasGroup($name); } }?>
Eeesshh, w Zend Framework jeszcze apletów nie wprowadzili :/ Chociaż w SVN jest już Zend_Acl i zarządzanie uprawnieniami jest łatwiejsze. Będzie trzeba się posiłkować zmiennymi dopisanymi do szablonu.
W ZF są helpery, a u mnie dziala to na tej samej zasadzie tyle że jak już mówiłem Aplet ma dostęp do HttpContext, klasy Usera, Modelu itp, a zwykły helper takich żeczy nie ma
No nie wiem, nie wydaje mi się, że helpery mogą służyć do tego. Aplet to aplet (czy komponent jak kto woli). Ale można się pokusić o napisanie czegoś podobnego.
Kontekst można uzyskać łatwo:
<?php Zend_Controller_Front::getInstance(); // Na takiej zasadzie działa Zend_View_Helper_Url - jeszcze w inkubatorze. ?>
<?php Zend::register(); // zapisywanie OBIEKTU w rejestrze Frameworka Zend::registry(); // odczytywanie OBIEKTU z rejestru. ?>
<?php switch(http://www.php.net/intval($_GET['wartosc_parametru'])) { case 1: case 2: case 3: etc.. } ?>
<?php /* Kontroler */ if($model->zaloguj($login, $haslo) == SUCCESS) //wywołanie modelu include("strona_glowna.php"); // wywołanie widoku else include("blad.php"); // wywołanie innego widoku ?>
Router jest częścią kontrolera, która tłumaczy url na zmienne na podstawie których dalszy algorytm kontrollera wywołuje akcję.
NULL myślę, że za bardzo rozwarstwiasz pewne rzeczy.. jeśli nie częścią kontrolera to częścią czego? Widoku czy Modelu?
Kiedy piszę o kontrolerze piszę o jednej z trzech warstw abstrakcji, która odczytuje żądanie (którego nośnikiem jest między innymi adres url) a nie o konkretnej jednej klasie.
Zauważyłem w swoich projektach, że duża część kodu powtarza się. Przyglądałem się frameworkom, które były prezentowane przez użytkowników tego forum jak i innym. Podoba mi się np, Rapide ale jak na razie jest za duży dla moich potrzeb. Chcę spróbować napisać sobie zestaw kilku prostych klas i zaimplementować MVC. Czytałem ten temat mnóstwo artykułów i każdy inaczej rozumie ten wzorzec. Spróbuje zebrać to co zrozumiałem - jeśli się mylę to mnie poprawcie:
1. Model - odpowiedzialny za logikę biznesową, jest jedyną częścią aplikacji, która przechowuje dane. Sposób przechowywania jest obojętny (baza, plik, itp.) Dobrym sposobem implementacji modelu jest utworzenie odzielnej klasy dla każdego logicznego obiektu, np. klasa Produkty, która będzie pobierać dane o produktach lub klasa Uzytkownicy, która będzie pobierać listę zarejestrowaych użytkowników... Jeśli dane są przechowywane w bazie danych, zazwyczaj jedna klasa odpowiada jednej tabeli lub kilku tabelom ściśle powiązanych ze sobą.
Spotkałem się też z twierdzeniem, że dobrze zaprojektowany model powinien być odporny na wewnętrzne zmiany w strukturze tabel bazy. I tu uważam, że jest to ciężkie do zrealizowania. Bo jeśli klasa Użytownicy pobiera dane wskazanego użytkownika (np. imie, nazwisko, pesel, data zarejestrowania itp, to po zmianie struktury trzeba zmieniać zapytanie..)
Widok - odpowiada za prezentacje danych. Wykorzystuje model do pobrania danych. Widok powinien utworzyć instacje klas modelu i wywołać metody odpowiedzialne za pobranie danych. Widok nie może modyfikować danych. Widok nie jest szablonem, pobiera dane i includuje odpowiedni szablon.
Kontroler - na podstawie analizy żądania http powinien zdecydować jakie akcje wykonać i jaki widok wyświetlić. Kontroler to jeden główny plik zbudowany na switchu..
PYTANIA:
1. Jeśli widok nie może zmieniać danych, to jak odbywa się aktualizacja (np. zmień hasło użytkownikowi) ?
Kontroler odbiera żądanie zmień hasło i wywołuje odpowiednią akcje, która uruchamia widok z formularzem zmiany hasła. Ten formularz wywołuje.. co? Znowu kontroler czy inną akcje, która zmienia hasło i odpala widok z komunikatem udanej zmiany/nieudanej zmiany ?
2. Wiele z osób torzy jeszcze klasy Request i Response. Po co?
Początkowo kontroler wydawał mi się najłatwiejszy (myliłem się). Dorwałem frameworka i załapałem widok, model i jak to działa. Wiem jak ogólnie działa kontroler ale nie mogę załapać jak napisać i połączyć w wspólne działanie Request/Response.. :/
Mógłby mi to ktoś wyłumaczyć prostym przykłądem (dwie przykładowe klasy i jak to połączyć)?
Przyłącze się do prośby ... ja jestem juz po wybieraniu z urla potrzebnych informacji,operowania na nich , problem mam natomiast z generowaniem wyniku operacji .
//edit
Jak klasa specjalizująca może dodawać funkcjonalności nadklasie ? (jeśli dobrze rozumiem o co chcę zapytać )
Czy mógłby ktoś naszkicować diagram (uml) do elementu głównego dla wzorca MVC ( np obiekt page jako obiekt który powstaje z innych klas dzięki dziedziczeniu,kompozycji bądź innch) , poglądowy - jak połączyć klasy ? . Rozumiem częściowo jak klasy mogą przekazywać sobie wyniki operacji na obiektach , ale jeszcze mi czegoś brakuje
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)