Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: HttpRequest a Router i generator linków
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
Stron: 1, 2
aleksander
Router to obiekt który rozbija żądanie i wyciąga z niego nazwę żądanej akcji, parametry itp. Router jest także generatorem linków (np nice urls)

HttpRequest jest obiektem, bedącym otoczką dla żądania http.

I teraz moje pytania:
1. Czy HttpRequest powinien by jednocześnie routerem:
Kod
--- klient ---

--- HttpRequest i Router w jednym ---

--- kontroler - pobiera nazwe akcji z Routera ---
czy router powinien byc oddzielny analizowac dane z httpRequest i na tej podstawie stwierdzac, którą ma akcję uruchomic:
Kod
--- klient ---

--- HttpRequest ---

--- Router - analizuje HttpRequest sprawdzająca jaka akcja ma byc uruchomiona ---

--- Kontroler - pobiera z routera nazwe akcji ---
?

2. Jeżeli ta pierwsza opcja to gdzie tu powinien by generator linków? Przecież nie za bardzo pasuje on do HttpRequest
squid
Cytat(aleksander @ 2005-07-21 15:41:19)
czy router powinien byc oddzielny analizowac dane z httpRequest i na tej podstawie stwierdzac, którą ma akcję uruchomic:
Kod
--- klient ---

--- HttpRequest ---

--- Router - analizuje HttpRequest sprawdzająca jaka akcja ma byc uruchomiona ---

--- Kontroler - pobiera z routera nazwe akcji ---
?

a co bys chcial zeby HttpRequest robil (troche konkretniej)
aleksander
no HttpRequest jest otoczką dla rządania http, ma metody pozwalające na wyciągnięcie danych POST GET COOKIE FILES.

Po prostu mam kilka argumentów jedne na to, żeby HR i Router były połączen drugie na nie i nie wiem co lepsze, więc pytam się Was:)
mike
Ostatnio zainteresowałem się Mojavi. Tam HttpRequest i Ruter (w zasadzie nie wystepuje on jawnie) nie są w żadnym razie połączone.

Dla mnie ideałem jest:
1. HR jest odpowiedzialne za żądanie aplikacji (parametry POST, GET, ...) i posiada metody do manipulacji nimi.

2. Router w rzeczywistości służy tylko do pobrania nazwy akcji z żądania i przekazanie tej informacji do Kontrolera

3. Kontroler rozdziela zadania, na podstawie informacji od Rutera i to on powinien zawierać metody do generowania linków.

W modelu tym bez wachania mozna pominąć Ruter, gdyż jest tylko ogniwem przekazującym dane i nie wnosi nic do aplikacji. Dane z HR Kontroler może sobie sam pobrać bez przeszkód:
  1. <?php
  2.  
  3. $objRequest->getParameter( 'actionName' );
  4.  
  5. ?>


... czy jakoś tak. Kontroler wcale nie potrzebuje tutaj Rutera. Jeżeli miałby on się jednak znaleść to napewno cząść Kontrolera, ale z pewnością nie część HR.

Tak funkcjonuje framework Mojavi, który moim zdaniem jest baaardzo bliski ideałowi.
hwao
  1. <?php
  2. class Request { // abstract class Request
  3.  protected $request = null;
  4.  
  5. abstract public function get() {
  6. }
  7. }
  8.  
  9. class httpRequest extends Request() {
  10. public function get() {
  11. if( in_null( $this->request ) ) {
  12.  return $this->request = $_SERVER['xxx']; // wybrac sobie klucz
  13. }
  14. return $this->request;
  15. }
  16. }
  17.  
  18. class Router {
  19.  /**
  20.  * @var object Request
  21.  */
  22.  private $request;
  23.  public function __construct( Request $request ) {
  24.  $this->request = $request;
  25.  }
  26. }
  27.  
  28. ?>

Moze troche byc zle napisane bo nie oto chodzi.

Mysle ze imho tak to powinno wygladac, czemu?
Mozna dopisac sobie np request z lini polecen
ConsoleRequest
nie trzeba calosci przerabiac.

Mysle ze Router nie powinien dziedziczyc z request (podobnie request z routera) tutaj lepszym rozwiazaniem jest agregacja (zawieranie).

Request jest poto zeby z niego dziedziczyc.

Daje to jako taka swobode dzialania.

Jak ktos ma ciekwasze pomysly to z checia obejrze.

Router w tym ukladzie dostarcza informacji kontrolerowi co i jak...
mike
Cytat(hwao @ 2005-07-21 21:37:39)
(...)
Mysle ze imho tak to powinno wygladac, czemu?
Mozna dopisac sobie np request z lini polecen
ConsoleRequest
nie trzeba calosci przerabiac.

(...)

Request jest poto zeby z niego dziedziczyc.


Dokladnie o to chodzi i to jest siłą takiego rozwiązania.
Hierarchia może wtedy wyglądać tak: Class Request

Cytat(hwao @ 2005-07-21 21:37:39)
(...)
Router w tym ukladzie dostarcza informacji kontrolerowi co i jak...

W zasadzie, jak już wspomniałem, jest on zbędnym przekaźnikiem. Nie wnosi nic konkretnego poza kolejną warstwą przez którą sie trzeba przebić w poszukiwaniu danych o żądaniu aplikacji.

ak dla mnie może on istnieć jako część (metodda, lub jakiś mały obiekcik) Kontrolera. Ale najlepiej to by było, jakby go nie było biggrin.gif
Przecią Kontroler sam może sobie dane pobrać z Requesta (a dokładnie z klasy dziedzczącej po nim).
squid
Cytat(hwao @ 2005-07-21 22:37:39)
  1. <?php
  2. class Request { // abstract class Request
  3.  protected $request = null;
  4.  
  5. abstract public function get() {
  6. }
  7. }
  8.  
  9. ?>


Request jest poto zeby z niego dziedziczyc.

Daje to jako taka swobode dzialania.

Czemu wiec request jako klasa abstrakcyjna a nie interfejs?
wtedy klasa httpRequest moglaby implementowac metody wspolne dla wszystkich mozliwych rodzajow requestow z interfesu Request i metody specyficzne dla tego protokolu jak implementacja interfejsu HTTP
matid
Sam zastanawiam się teraz nad tym problemem. U mnie cala operacja wygląda tak:

Mam klasę HttpRequest, która implementuje interfejs iHttpRequest.
W konstruktorze klasy HttpRequest mam takie coś:
  1. <?
  2. $this->GetParametersContainer = new GetParametersContainer;
  3. $this->PostParametersContainer = new PostParametersContainer;
  4. ?>

i tak dalej dla Cookie, Files, itp.
Klasa GetParametersContainer wygląda tak:
  1. <?php
  2.  
  3. class GetParametersContainer extends ParametersContainer
  4. {
  5. public function __construct()
  6. {
  7. foreach( $_GET as $sKey => $mValue )
  8. {
  9. $Key = new String( $sKey );
  10. $Value = new String( $mValue );
  11.  
  12. if( is_numeric( $mValue ) )
  13. {
  14. $Value = new Integer( $Value );
  15. }
  16.  
  17. $this->addParameter( new Parameter( $Key, $Value ) );
  18. }
  19. }
  20. }
  21.  
  22. ?>

Teraz najlogiczniejszym IMO umiejscowieniem routera będzie klasa GetParametersContainer i nowa klasa HttpRequest. Np. tworzę sobie klasę RoutedGetParamterersContainer, która będzie odpowiednio rozszyfrowywala PATH_INFO. Potem tworzę sobie klasę RoutedHttpRequest rozszerzającą HttpReqest i imlpementującą interfejs iHttpRequest, która w konstruktorze zawiera zamiast:
  1. <?php
  2. $this->GetParametersContainer = new GetParametersContainer;
  3. ?>

to
  1. <?php
  2. $this->GetParametersContainer = new RoutedGetParameteresContainer;
  3. ?>

Dzięki temu do zmiennych Get mogę odwolywać się tak jak zawsze mimo, że przechodzą one przez router.
hawk
Dla mnie funkcje requesta to:
- wymuszanie, żeby dostęp do danych POST, GET itd był tylko przez tą klasę
- nie można zmieniać np. danych POST, bo request na to nie pozwala
- można wymienić klasę requesta i np. wczytać wszystkie dane z pliku XML (dobre do testowania)
- można dołożyć jakieś filtry na requesta, np. odtegować magic_quotes_gpc
- jest to dobre miejsce do jakiejś analizy danych wejściowych

Funkcje routera: tylko jedna, ale bardzo ważna: zamiana URLi na nazwy akcji i z powrotem. Mojavi nie zawiera routera, i przez to schemat URLi musi być zakodowany na sztywno w kontrolerze.

Router i request powinny być IMHO rozdzielone, bo zadania mają inne.

Jeszcze co do requesta: Jest to bardzo praktyczna i wygodna rzecz. Gdyby ktoś zrobił request w ramach SPL, to wziąłbym go bez zastanawiania się. Problem w tym, że ciężko dojść do porozumienia, jakie dokładnie metody powinien zawierać, i jest to zawsze kawałek kodu, który nie jest niezbędny. Więc chyba najlepiej jest go zaimplementować tak, żeby narzut czasowy i ilość kodu były minimalne.
mike
Cytat(hawk @ 2005-07-22 09:16:43)
Mojavi nie zawiera routera, i przez to schemat URLi musi być zakodowany na sztywno w kontrolerze.


Tak to wygląda w Mojavi, (kawałek klasy WebController)
  1. <?php
  2. public function genURL( $url = null, $parameters = array() )
  3. {
  4. if ($url == null)
  5. {
  6. $url = $_SERVER['SCRIPT_NAME'];
  7. }
  8.  
  9. if (MO_URL_FORMAT == 'PATH')
  10. {
  11. // use PATH format
  12. $divider = '/';
  13. $equals  = '/';
  14. $url  .= '/';
  15. } else
  16. {
  17. // use GET format
  18. $divider = '&';
  19. $equals  = '=';
  20. $url  .= '?';
  21. }
  22.  
  23. // loop through the parameters
  24. foreach ($parameters as $key => &$value)
  25. {
  26. $url .= urlencode($key) . $equals . urlencode($value) . $divider;
  27. }
  28.  
  29. // strip off last divider character
  30. $url = rtrim($url, $divider);
  31.  
  32. // replace &'s with &amp;
  33. $url = str_replace('&', '&amp;', $url);
  34.  
  35. return $url;
  36. }
  37. ?>

Stała MO_URL_FORMAT jest definiowana w pliku konfiguracyjnym, a możliwość rozszerzenia tej funkcji ogromne. Więc niby zaszyte ale nie tak bardzo sztywno smile.gif



O.T. Przepraszam za nieustanną propagandę Mojavi ale jakoś mnie ten framework zafascynował, jest bardzo przejrzyście i ładnie napisany. I dlatego można go sobie w banalny sposób przebudować i dostosować do swoich upodobań.

Pewnie ma jakieś wady, ale nie znalazłem jeszcze większych/rażących smile.gif
hawk
Wiem, sam uważnie studiowałem Mojavi winksmiley.jpg. Nie chcę tutaj go krytykować, bo to bardzo dobry framework. I może się nieprecyzyjnie wyraziłem. Chodzi o to, że Mojavi oferuje dwa schematy kodowania URLi. Problemy są dwa:
1) Jak chcę, żeby mój URL wyglądał inaczej, to muszę grzebać w kodzie samego frameworka. Co praktycznie wyklucza taką możliwość.
2) Zwiększanie liczby opcji też nie jest dobre, bo php będzie musiał parsować np. kilkanaście różnych if...else parsujących URL, kiedy przez cały czas używana jest tylko jedna opcja - niepotrzebny kod.
mike
Przyznają rację - jest to niedogodność.

P.S. Zauważyłeś jeszcze jakieś bugi/biedogodności w Mojavi. Bo ja chyba tylko jeszcze jedną. Ale to rozmowa na inny temat lub na PW.

Nie zanieczyszczajmy wątku bo schodzimy z tematu winksmiley.jpg
matid
Ale wciąż mam wątpliwości co do tego Routera. Jeśli mamy linki postaci:
index.php/module/test/action/test/p1/blah/p2/test
To HttpRequest nie będzie mial żadnych zmiennych w tablicy $_GET, a IMO powinien mieć. Powinien rozszyfrować ten url i mieć 4 zmienne: module, action, p1 i p2. Router zaś powinien chyba zapytać HttpRequest o zmienne module i action i podać je kontrolerowi. Albo powinien mieć możliwość zmiennych GET klasy HttpRequest, tak, aby w dalszej części skryptu byly normalnie dostępne przez HttpRequest.
hawk
Nie powinien mieć. To router powinien wiedzieć, że nie szukamy zmiennych w tablicy GET, tylko bierzemy REQUEST_URI (czy jak to się nazywało) z SERVER i tniemy na kawałki. Request powinien tylko dostarczać wszystkie te dane tak, jak były one ustawione przez serwer http, bez interpretowania ani szukania w nich module/action.

W każdym razie takie jest moje zdanie. Nigdzie nie jest napisane, że nie może być inaczej, ale tak wydaje mi się lepiej. Wtedy zmiana schematu URLi == zmiana routera, a request zostaje bez zmian.
matid
Cytat(hawk @ 2005-07-22 14:41:55)
Nie powinien mieć. To router powinien wiedzieć, że nie szukamy zmiennych w tablicy GET, tylko bierzemy REQUEST_URI (czy jak to się nazywało) z SERVER i tniemy na kawałki. Request powinien tylko dostarczać wszystkie te dane tak, jak były one ustawione przez serwer http, bez interpretowania ani szukania w nich module/action.

W każdym razie takie jest moje zdanie. Nigdzie nie jest napisane, że nie może być inaczej, ale tak wydaje mi się lepiej. Wtedy zmiana schematu URLi == zmiana routera, a request zostaje bez zmian.

A dajmy na to w Phiend2, Router mialby być ladowany przed BasicHttpRequest (i czytać bezpośrednio z tablicy $_SERVER), czy po i przyjmować jako argument instancję klasy implementującej iHttpRequest i z niej pobierać informacje z tablicy $_SERVER?
A co jeśli mamy caly URL w techinice NiceURL, czyli dajmy na to:
index.php/a/1/b/2/c/3
HttpRequest ma nie wiedzieć o tym, że te dane z PATH_INFO są zastępstwem zwyklych danych z tablicy $_GET? W takim razie jak w innej części kodu mamy pobrać wartość zmiennej a, b lub c? Mi się wydawalo najrozsądniej w kodzie wyciągnąć z kontekstu (Context) instancje iHttpRequest i poprosić ją o te zmienne. A jak Ty to widzisz?
hawk
W phiend2 (dokładnie: w phiend.mvc) router jest po request. Przyjmuje jako argument i wyciąga takie dane, jakie chce.

Co do wyciągania później zmiennych, widzę 2 sposoby:
1) router może zwrócić nazwę akcji + parametry, więc jedna implementacja routera może przepisać te parametry z tablicy GET, a druga na podstawie PATH_INFO

2) sama akcja może odwołać się bezpośrednio do requesta i wyciągnąć potrzebne parametry

Ale tutaj widzę pewien problem, i pewnie o to Tobie chodziło: jeżeli schemat URLi dyktuje nie tylko, jak wyciągać z URLa nazwę akcji, ale także, jak uzyskać inne parametry potrzebne konkretnej akcji, akcja nie powinna odwoływać się bezpośrednio do requesta, bo nie wie, jak są te parametry zakodowane. W tej sytuacji widzę 3 wyjścia:
1) zrobić requesta, który potrafi w ograniczonym zakresie przetwarzać dane wejściowe (nie szuka nazwy akcji, ale przepisuje parametry z PATH_INFO do GET, jeżeli trzeba), i podmienić zamiast BasicHttpRequest

2) zrobic routera, który będzie w stanie zorientować się, że dana akcja potrzebuje parametrów, i wyciągnąć je zgodnie z przyjętym schematem URLi

4) router zawsze bierze wszystkie dodatkowe parametry GET (lub wszystko, co zostaje w PATH_INFO) i podaje akcji jako parametry, a akcja niech sama się martwi, które z nich naprawdę były jej potrzebne
matid
Dokladnie o twoją 1 propozycję chodzilo mi w tym poście. Osobiście wolę przerzucić wyciąganie potrzebnych parametrów na akcje niż pchać je na silę przez Router winksmiley.jpg
IMO najlepszym wyjściem jest po prostu tworzenie nowej klasy implementującej interfejs iHttpRequest, a router ograniczyć do pobierania od tej klasy informacji o bieżącej akcji/module.
Vengeance
Ponieważ każdy widział kod phiend2, to wszystko będzie pod jego "logike" tak by łatwiej było się dogadać :]

Kod
url1: site.org/modul/akcja/param1/param2/param3
url2: site.org?m=modul&a=akcja&1=param1&2=param2&3=param3

W zaleznosci ktory Request wybierzemy, rozbija on podane URLe na tablice:
Kod
array[m] = modul
array[a] = akcja
array[1] = param1
array[2] = param2
array[3] = param3


Akcje pobieraja sobie te dane bezpośrednio:
  1. <?php
  2.  
  3. $request->getParam(1); // zwroci 'param1'
  4. $request->getParam(2); // zwroci 'param2'
  5.  
  6. ?>


I teraz podstawowe pytanie... gdzie w cały schemat klas umiejscowić Router (Jak zwał tak zwał) bym mógł szybko generować URLe dla dowolnego schematu. Przypuśmy że w kodzie TPL potrzebuje zrobić:
Kod
<a href="{funkcja_smarty(array('m'=>modul2,'a'=>akcja2,1=>param1))}">Inna akcja i modul niz obecnie wywolane</a>

Albo w kodzie akcji:
  1. <?php
  2.  
  3. $response->redirect(tworz_url(array('m'=>modul2,'a'=>akcja2,1=>param1)));
  4.  
  5. ?>


Więc jak tu dobrze umiejscowić ROuter by móc się do niego wygodnie odwoływać z Szablonów czy też akcji w celu stworzenia URLa ?!
hawk
Żeby to dobrze działało, router i request musiałyby być "zsynchronizowane". Tzn jeżeli request bierze parametry z GET, to router tworzy urle wykorzystując GET. A to mi śmierdzi, bo dwa komponenty muszą mieć wspólny sposób obsługi. Zgodnie z prawem Murphiego... Jakieś pomysły?
Vengeance
@hawk: nie koniecznie, Request może rozbijać PATH_INFO by np. obsłużyć pokazany wyżej url1, a Router będzie tablicę podaną w parapetrze join-ował ze znakiem '/'. Tylko mnie chodzi o to, jak połączyć Router z innymi klasami, by łatwo było go wymieniać, ale i łatwy był dostęp z TPL czy z akcji do niego. Kompletnie nie wiem pod co pasuje ficzer "generowania urli" tym bardziej ze jest to potrzebne w wielu miejsach
aleksander
zazwyczaj do akcji przekazuje sie request i response wiec teoretycznie pasowalby on do requesta. Można też zrobic coś takiego: $oRequest->getRouter();, lub Router::getInstance(); jak używałem kiedyś:]

A może coś takiego, że Router jest przezroczysta warstwą dla Requesta? Bo w sumie Request nigdy się nie zmieni, to Router jest wymienialny, w zalezności od linków, więc może on np rozszerzac Request.
hawk
Co do dostępu do routera (znowu mówię w kategoriach phiend2):
  1. <?php
  2. //w kodzie akcji:
  3. $url = PluginLoader::getInstance()->getPlugin('router')->createURL('niepamiętamco');
  4. ?>

Jeżeli jest dostęp z akcji, to również z template. Można np. przekazać do smarty.

Natomiast request przekazywany jest do akcji jako parametr - dokładnie przekazywany jest IHttpContext, i wystarczy zrobić $context->getRequest().

@Vengeance: Ja się martwię tym, że request musi rozbijać wg PATH_INFO, a router łączyć slashami. A jeżeli ktoś weźmie inny router? Nagle mu się rozjedzie sposób tworzenia URLi ze sposobem dekodownia URLi. Więc wolałbym trzymać obie te funkcje tylko w routerze. Tylko że jak pokazał matid, to rodzi pewne problemy sad.gif.

@aleksander: Jeżeli router będzie rozszerzał requesta, to będę miał przy moim podziale na pakiety lekkie zamieszanie. Bo request nie potrzebuje MVC i może być teoretycznie używany bez tego. A router już jest częścią MVC, bo na wyjściu daje nazwy akcji.

edit: a gdyby tak dodać do routera metodę getParam($request, $paramName) ? Router już będzie wiedział, jak co wyciągnąć z requesta, a w ten sposób request nie musi nic analizować i przetwarzać.
serafin
@hawk: btw, ja bym w phiendzie dorzucil do filtrow i pluginow cos co ja nazwalem PluginAccessor:

function __get($plugin) {
return PluginLoader::get($plugin);
}

co skraca uzycie do $this->router->costam();

Co do routera, wydaje mi sie ze najlepszym rozwiazaniem jest przekazywanie z routera do request sparsowanej tablicy z parametrami sparsowanego urla. Czemu tak? A bo wtedy wyciagamy dane wylacznie z requesta nie martwiac sie o to jak zostaly sparsowane. Fakt faktem ze musimy wtedy stworzyc w miare uniwersalny format tych danych w tablicy: np [ 0(nazwa akcji) -> test, 1(pierwszy parametr) -> 10 itd] Wprowadza to pewne ograniczenia ale i korzysci...

Majac w indeksowanej tablicy parametry sparsowanego urla mozemy latwo tworzyc schematy urli. Przyjmujemy ze 1 parametr to zawsze nazwa akcji, a potem juz akcja decyduje czym sa kolejne parametry.

Wg mnie nie powinnismy nigdy wyciagac bezposrednio z routera danych. To co router sparsuje powinno zostac polaczone z danymi z request z priorytetem na dane routera. W koncu router przydaje sie wylacznie przy zapytanaich typu HTTP i ewentualnie do sprawdzenia ip klienta / przegladarki itp.

Przy requestach ala xml-rpc czy soap, router jest praktycznie zbyteczny.

Pozdrawiam
bela
Cytat
2) zrobic routera, który będzie w stanie zorientować się, że dana akcja potrzebuje parametrów, i wyciągnąć je zgodnie z przyjętym schematem URLi


Ja mam trochę jak w Cocoonie tongue.gif Znaczy definiuję w config request w którym są akcje, tak:

  1. <request match="foo/bar/?/*" />


? oznacza wszystko oprócz /, a * każdy znak. A router już sobie dopasowaję to przekształcając na RegExpy smile.gif
Vengeance
Cytat("hawk")
@Vengeance: Ja się martwię tym, że request musi rozbijać wg PATH_INFO, a router łączyć slashami. A jeżeli ktoś weźmie inny router? Nagle mu się rozjedzie sposób tworzenia URLi ze sposobem dekodownia URLi. Więc wolałbym trzymać obie te funkcje tylko w routerze. Tylko że jak pokazał matid, to rodzi pewne problemy .

Stąd mój udzial w tym wątku, bo mam te same rozterki :]
matid
Można ew. tworzyć nową klasę Request, która w konstruktorze stworzy instancję Routera i pobierze od niego rozszyfrowane dane z PATH_INFO. Jak ktoś będzie chcial stworzyć nowy url, to albo pobierze sobie Router (np. $request->getRouter(); albo zmapuje się funkcję generowania URL-a do requesta (trochę mniej mi się to podoba).
W takiej sytuacji możemy sobie spokojnie wymienić Router i zmienia się zarówno sposób kodowania, jak i dekodowania, ale możemy także zmienic klasę Request.
A w Phiendzie wystarczyloby zostawić BasicHttpRequest w phiend.context a RoutedHttpRequest wraz z Routerem wrzucić do phiend.mvc. I tak BasicHttpContext dostaje iHttpRequest w kostruktorze, więc nie ma problemu ze znajdowaniem się tych klas w różnych pakietach. (i tak instancja BasicHttpContext będzie tworzona najprawdopodobniej we kontrolerze, który jest częścią phiend.mvc).
serafin
matid: pamietaj ze router nie zawsze jest potrzebny. Niezlym rozwiazaniem byloby $request->setData($router->getTranslated());
Vengeance
Ale właśnie sposobow na powiazanie Request i Router sa tysiace i kazdy dobry... to juz rozwiazal kazdy z nas tongue.gif

Pytanie jak zorganizowac generowanie URLa bo jak dla mnie
$request->GetRouter()->CreateURL(array()); jest troche logicznie glupie :]
hawk
$request->getRouter() mi nie pasuje. Bo zwykły request nie wie, co to jest router i nie powienien się tym zajmować. A jeżeli napiszemy RoutedHttpRequest extends BasicHttpRequest, to nagle okaże się, że cała idea z wymienialnym requestem wzięła w łeb, bo potrzebne są nam nowe metody w RouterHttpRequest. I nic nie da się z tym zrobić, bo AdvancedRoutedHttpRequest extends AdvancedHttpRequest, RoutedHttpRequest jest niedozwolone.

@serafin: $request->setData() jest niebezpieczne, bo nie tylko router może użyć tej metody. Niemodyfikowalny request ma swoje zalety. Czasami może to być przydatne, ale w ten sposób nie mielibyśmy możliwości zablokowania tego.

@bela_666: problem nie polega na tym, jak dopasować akcję, ale co zrobić z pozostałymi parametrami podanymi w URLu. AFAIK, Cocoon też nic sensownego z nimi nie robi. Dopasowuje i tyle.
bela
Cytat(hawk @ 2005-07-22 20:43:11)
@bela_666: problem nie polega na tym, jak dopasować akcję, ale co zrobić z pozostałymi parametrami podanymi w URLu. AFAIK, Cocoon też nic sensownego z nimi nie robi. Dopasowuje i tyle.

Pozostałe? Dla mnie nie ma pozostałych, są tylko właściwe, akcja używa jakiś parametrów i juz smile.gif A jakich to wybierasz przez {1}, {2} etc.
aleksander
a takie rozwiązanie:

Kontroler z routera pobiera nazwę akcji i wszystkie parametry, a następnie parametry przekazuje w argumencie do akcji:
  1. <?php
  2. interface Action
  3. {
  4. public function Perform( IHttpRequest $oRequest, IHttpResponse $oResponse, $aParams );
  5. }
  6. ?>
albo przekazywac cały Router do akcji
  1. <?php
  2. interface Action
  3. {
  4. public function Perform( IHttpRequest $oRequest, IHttpResponse $oResponse, IRouter $oRouter );
  5. }
  6. ?>
Router z kolei ma funkcje do pobierania parametrów.

Jest to moim zdaniem rozbicie odpowiedzialności ($_GET lub PATH_INFO idą przez Router, reszta przez Request) ale nic sensowniejszego nie wymysliłem smile.gif
NuLL
Nie lepiej wladowac dane z router'a do request-u :?:
  1. <?php
  2. //...pola klasy
  3. class request
  4. {
  5. public function __contruct()
  6. {
  7. $this->post_data=$_POST;
  8. $this->get_data=adressRouter::translateURL();
  9. //..itd
  10. }
  11. }
  12.  
  13. ?>
squid
@bela_666 a jak masz powiedzmu w url'u zakodowane jak posortowac jakas liste i wg jakiego pola to akcja moze sie spokojnie odwolywac do parametrow ale trzeba to jeszcze zamienic na url potem

@hawk blokujemy zapis danych typu $_SESSION $_COOKIE w Requescie to jak chcesz dodac nowe dane do ciasteczka albo serializowac w sesji obiekt koszyka uzytkownika to jak chcesz to rozwiazac??
NuLL
Co do genracji linków - może zrobić tak :?:
  1. <?php
  2.  
  3. class linkGenerator
  4. {
  5. public static function generate(&$data)
  6. {
  7. return router::generateLink($data);
  8. }
  9. }
  10.  
  11. ?>

linkGenerator byłby poprostu osobną klasą w systemie, bo wg. mnie nie nadaje się on ani do requestu ani do routera.

Co Wy na to :?:
squid
Cytat(NuLL @ 2005-08-06 12:26:56)
linkGenerator byłby poprostu osobną klasą w systemie, bo wg. mnie nie nadaje się on ani do requestu ani do routera.

Co Wy na to :?:

No wedle tego co tu powiedziano glownym zadaniem rutera jest odszyfrowywanie akcji z url'a oraz zamiana potem na url'e wiec jak nie pasuje to routera?
NuLL
Dobre pytanie czy ja muszę sie słuchać tego co powiedzieli inny :?: snitch.gif

Pozatym wpadłem goże godzinę temu na inne rozwiązanie. Najpierw zmieńmy lekko definicję routera. Router - klasa/komponent/itp która jest odpowiedzialna za 'obsługę ruchu' w aplikacji - if u know whats I mean.

Router dzielimy na dwie klasy: UrlTranslator oraz LinkGenerator. Teraz wydaje mi się, że wszystko się trzyma do kupy smile.gif

Hmmm :?:
M4chu
U mnie to nawet nie sa 2 klasy a dwie metody: encodeUrl i decodeUrl winksmiley.jpg
squid
jesli router mialby sie zajmowac kodowaniem i dekodowaniem url znaczy ze do widoku musi przekazac wszystkie zakodowane URL'e. A gdyby tak przekazywac do widoku odpowiednie parametry i widok z nich skladal by sobie url'e? Ma to jakies ograniczenia (to rozwiazanie)?
Vengeance
Ja gdy korzystam z czego ala router, robie w szablonach po prostu

<?php echo $tpl->URL('index.php?param1=a&param2=b');?>

ewentualnie dla maniakow smarty

{url href="index.php?param1=a&param2=b"}
ebe
Hmm u mnie np. linki genrowane są w... pluginie systemu szablonów. Tj. pobieram z konfiga aplikacji router (np. NiceUrl) który implmentuje interfejs IRouter, w tym interfejsie deklrauję IRouter::buildUrl() , którą wykorzystam w pluginie.
Do plugina wrzucam w ten sposób (używam savanta)

Kod
{['url','news',array('mode'=>'ext', 'id'=>32)]}


gdzie news to zmienna page czyli moja akcja/widok , a to co w tablicy to parametry...
Vengeance
No to właśnie u mnie jest to samo :] Ale dla przejrzystości używam standardowego URLa php który potem konwertuje do tablicy przez parse_url()

Po co kombinować w jakieś parametry widoków :]
squid
OK.
Wrocmy na chwile do Requesta, jedna z jego podstawowych f-cji jest przefiltrowanie wszystkich zmiennych/tablic jakie skrypt dostaje na wejsciu. Np dla $_GET:
  1. <?php
  2. foreach ( $_GET as $key => $value )
  3. {
  4. if ( ctype_alnum ( $key ) and ctype_alnum ( $value ) )
  5. {
  6. $this->HttpGetVars[$key] = $value;
  7. }
  8. }
  9. ?>

zakladam ze zarowno klucze jak i wartosci moga byc [a-zA-Z0-9] dla tablic $_GET, $_POST, $_SESSION, $_COOKIE i wtedy sa bezpieczne wartosci. Czy moze sie zdazyc w ktorejs z tablic ze beda potrzebne inne dozwolone wartosci? W $_GET i $_POST wg mojej filozofii nie ale $_SESSION i $_COOKIE ?

Po za tym takie przefiltrowanie to dla akcji za malo bo na arzie wiemy ze wartosci sa bezpieczne ale nie wiemy czy sa poprawnego typu bo np. $_GET['id'] dla akcji powinien byc wartoscia calkowita a $_POST['author'] powinien zawierac tylko [a-zA-Z]. Czy kontrole poprawnosci typu zostawic Requestowi? czy tez moze lepiej zeby akcja sie tym zajela ale skoro akcja to po co na poczatku filtrowac wszystko jak i tak nie przeszlo by to przez filtr poprawnosci typu danych akcji.
Vengeance
Zapomniałes o tablicach :] W szczególności w POST często się je stosuje
squid
Cytat(Vengeance @ 2005-08-08 11:11:55)
Zapomniałes o tablicach :] W szczególności w POST często się je stosuje

POST stosuje tablice? nie rozumiem.
Ale wlasnie sie zreflektowalem ze mze i dla wszystkich kluczy takie rzumowanie jest dobre ([a-zA-Z0-9]) ale w poscie moze byc juz cokolwiek i do tego polskie znaczki.
$_GET bym zrobil tak jak pokazalem ale na $_POST juz trzeba cos lepszego np.:
  1. <?php
  2. foreach ( $_POST as $key => $value )
  3. {
  4. if ( ctype_alnum ( $key ) )
  5. {
  6.  // teraz albo na podstawie jakies mapy oczekiwanych wartosci robie filtracje
  7. // wartosci zmiennej ale zostawiam dalszy ciag sprawdzania akcji 
  8. $this->HttpPostVars[$key] = $value;
  9. }
  10. }
  11. ?>


Sa dwie rzeczy, ktore mi nie pasuja:
1. Chcialbym utrzymac konsekwencje w dzialaniu i jesli $_GET przefiltruje w calosci za pomoca metod Requesta to z innymi tablicami chcialbym robic to samo w tym samym miejscu zeby zapobiedz balaganowi w aplikacji.
2. Chcialbym uniknac powtarzania kodu np. w kiedy akcja ma sprawdzic poprawnosc typu $_GET['id'] i zrobi to tak:
  1. <?php
  2.  
  3. if (is_int($this->HttpGetVars['id']))
  4. {
  5. //... costam
  6. }
  7. else
  8. {
  9.  // jakis wyjatek
  10. }
  11. ?>

i tak w kilku akcjach to mamy mnostwo powtarzalnego kodu
Vengeance
GET: index.php?tablica[klucz1]=wartosc1&tablica[klucz2]=wartosc2
POST:
<input type="checkbox" name="tablica[]" value="wartosc1"/>
<input type="checkbox" name="tablica[]" value="wartosc2"/>
squid
@Vengeance juz rozumiem o co Ci chodzilo smile.gif ale nie stosuje czegos takiego bo nie wiem po co zwlaszca ze wprowadza troche zamieszania. Potrafisz mi podac przyklad gdzie uzycie czegos takie jest najprostrzym sposobem na uzyskanie czegos?
Vengeance
<input type="checkbox" name="wybrane[]" value="mysql"/>
<input type="checkbox" name="wybrane[]" value="sqlite"/>
<input type="checkbox" name="wybrane[]" value="oracle"/>

takie pola formularza (mozliwosc szybkiego dodania wiekszej ilosc) + w razie bledu w jakims innym polu, zazaczone pola maja byc zapamietane i zaznaczone automatycznie biggrin.gif

Przy wykorzystaniu tablic w POST, mozesz szybko i bezbolesnie cos takiego zrealizowac, jedna petelka i juz :]
hawk
Z walidacją ciężka sprawa... ja jeszcze dorzucę, że request powinien "odtegowywać" magic_quotes_gpc.

A co do rozbijania routera na 2 klasy: właśnie po to jest to jedna klasa, żeby nie było ryzyka, że kodować będziemy tak, a dekodować inaczej. I cała aplikacja padnie.
NuLL
No dobra - zachowajmy tą nową definicję ale zamiast tego będą dwie metody w klasie - wiadomo do czego. Sam router będzie posiadał wczytany na początku schemat URL który najpierw odczyta o potem będzie tworzył smile.gif
squid
zalozmy na chwile ze nasza apikacja moze byc wywolywana w rozny sposob najczesniej przez rzadanie HTTP albo z lini polecen. Jak rozpznac jakie wywolanie nastapilo zeby wlaczyc odpowiedni Request? Czy sprawdzanie poprzez apache_request_headers() czy jakies naglowki HTTP zostaly odebrane to dobry pomysl?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.