Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

3 Stron V   1 2 3 >  
Reply to this topicStart new topic
> HttpRequest a Router i generator linków
aleksander
post
Post #1





Grupa: Przyjaciele php.pl
Postów: 742
Pomógł: 0
Dołączył: 14.12.2003
Skąd: Gdańsk, Trójmiasto

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
squid
post
Post #2





Grupa: Zarejestrowani
Postów: 358
Pomógł: 0
Dołączył: 3.07.2003
Skąd: Szczecin->niebuszewo->*(next to window)

Ostrzeżenie: (0%)
-----


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)


--------------------
Jeśli życie to kara to nieźle nabroiłem ;-)
Go to the top of the page
+Quote Post
aleksander
post
Post #3





Grupa: Przyjaciele php.pl
Postów: 742
Pomógł: 0
Dołączył: 14.12.2003
Skąd: Gdańsk, Trójmiasto

Ostrzeżenie: (0%)
-----


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:)
Go to the top of the page
+Quote Post
mike
post
Post #4





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
hwao
post
Post #5


Developer


Grupa: Moderatorzy
Postów: 2 844
Pomógł: 20
Dołączył: 25.11.2003
Skąd: Olkusz




  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...
Go to the top of the page
+Quote Post
mike
post
Post #6





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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).
Go to the top of the page
+Quote Post
squid
post
Post #7





Grupa: Zarejestrowani
Postów: 358
Pomógł: 0
Dołączył: 3.07.2003
Skąd: Szczecin->niebuszewo->*(next to window)

Ostrzeżenie: (0%)
-----


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

Ten post edytował squid 3.08.2005, 13:20:17


--------------------
Jeśli życie to kara to nieźle nabroiłem ;-)
Go to the top of the page
+Quote Post
matid
post
Post #8





Grupa: Zarejestrowani
Postów: 362
Pomógł: 0
Dołączył: 18.02.2004
Skąd: Knurów

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
hawk
post
Post #9





Grupa: Zarejestrowani
Postów: 521
Pomógł: 0
Dołączył: 3.11.2003
Skąd: 3city

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
mike
post
Post #10





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
hawk
post
Post #11





Grupa: Zarejestrowani
Postów: 521
Pomógł: 0
Dołączył: 3.11.2003
Skąd: 3city

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
mike
post
Post #12





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
matid
post
Post #13





Grupa: Zarejestrowani
Postów: 362
Pomógł: 0
Dołączył: 18.02.2004
Skąd: Knurów

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
hawk
post
Post #14





Grupa: Zarejestrowani
Postów: 521
Pomógł: 0
Dołączył: 3.11.2003
Skąd: 3city

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
matid
post
Post #15





Grupa: Zarejestrowani
Postów: 362
Pomógł: 0
Dołączył: 18.02.2004
Skąd: Knurów

Ostrzeżenie: (0%)
-----


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?
Go to the top of the page
+Quote Post
hawk
post
Post #16





Grupa: Zarejestrowani
Postów: 521
Pomógł: 0
Dołączył: 3.11.2003
Skąd: 3city

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
matid
post
Post #17





Grupa: Zarejestrowani
Postów: 362
Pomógł: 0
Dołączył: 18.02.2004
Skąd: Knurów

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
Vengeance
post
Post #18





Grupa: Zarejestrowani
Postów: 657
Pomógł: 2
Dołączył: 15.08.2003
Skąd: Łódź

Ostrzeżenie: (0%)
-----


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 ?!


--------------------
Go to the top of the page
+Quote Post
hawk
post
Post #19





Grupa: Zarejestrowani
Postów: 521
Pomógł: 0
Dołączył: 3.11.2003
Skąd: 3city

Ostrzeżenie: (0%)
-----


Ż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?
Go to the top of the page
+Quote Post
Vengeance
post
Post #20





Grupa: Zarejestrowani
Postów: 657
Pomógł: 2
Dołączył: 15.08.2003
Skąd: Łódź

Ostrzeżenie: (0%)
-----


@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


--------------------
Go to the top of the page
+Quote Post

3 Stron V   1 2 3 >
Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 21.08.2025 - 10:00