kwiateusz
21.07.2008, 09:31:30
Zgłoszono zapotrzebowanie na taki temat więc tworzę

Myśl przewodnia: "W jaki sposób tworzyć routery na potrzeby naszych aplikacji, jakie są wydajne a jakie nie. Jakich używać a jakich nie używać."
Przeglądając framework Zenda, system Rutowania oparty jest o jeden Router_Rewrite zawierający tablicę obiektów tras, na których poźniej wykonywana jest pętla foreach i każdemu z osobna jest wywoływana metoda $route->match($pathInfo).
Pomysł bardzo wygodny, bo możemy definiować sobie tyle tras różnego rodzaju ile chcemy, implementując oczywiście odpowiedni interfejs. Minusem jest jednak wydajność takiego rozwiązania.
Myśle że lepszym pomysłem byłoby rozdzielić Router_Rewrite na routery:
a) Rewrite (domyślny ostatni w kolejności do sprawdzania router)
- brak magazynowania tras, bo nie byłoby takiej potrzeby ponieważ router wyciąga parametry z tego co dostaje (/onas/kontakt)
B) Static (statyczny router):
- magazynuje tylko statyczne trasy i jej parametry
- brak dynamicznych parametrów
- przechowuje trasy w tablicy a indeksem tablicy jest szablon trasy (np. o-nas,kontakt.html)
- błyskawiczne znajdowanie trasy
c) Static Rewrite (statyczno-dynamiczny router):
- magazynuje tylko statyczne trasy i jej parametry
- możliwość dynamicznych parametrów (id/3)
- przechowuje trasy w tablicy a indeksem tablicy jest szablon(np. /pl/wydarzenia-o-biznesie) trasy (np. /pl/wydarzenia-o-biznesie/id/5 gdzie /pl/wydarzenia-o-biznesie to trasa statyczna a id/5 to dodatkowy parametr dynamiczny)
- dość szybkie znajdowanie tras
d) Regex (rutowanie za pomocą wyrażeń regularnych)
- magazynuje wszelkiego rodzaju trasy i ich parametry
- przechowuje trasy w tablicy a indeksem jest pattern wyrażenia regularnego
- niestety mało wydajne wyszukiwanie - konieczność użycia wyrażeń regularnych
W pierwszej kolejności nasz framework zacząłby od sprawdzania tras statycznych, następnie od statyczno - dynamicznych, potem wyrażenia regularne i na koniec rewrite który wyciąga z urla parametry jeśli nie znaleziono nic w powyższych routerach.
Po testach szybkości:
3 krotnie szybciej routing się wykonuje jeśli mamy 3 routery a trasy i parametry przechowywujemy na tablicach, niż używając jednego routera i przechowywując instancje obiektów tras w jednej tablicy.
Routing oparty o instancje obiektów tras:
Dodanie tras statycznych:0.00089502334594727
Dodanie tras regex:0.0009760856628418
Szukanie tras:0.00070309638977051
Czas całkowity:0.0026209354400635
Routing oparty o 3 routery i tablicę do przechowywania tras i parametrów:
Dodanie tras statycznych:0.00034093856811523
Dodanie tras regex:0.00036096572875977
Szukanie tras:0.00030183792114258
Czas całkowity:0.0010831356048584
Cysiaczek
21.07.2008, 15:46:24
Mam prośbę: czy mógłbyś wykonać miarodajne testy np. w pętli? Bo obecne mogą być wynikiem działania winampa, albo chwilowego wzrostu obciążenie procka, czy zatkania się danych na FSB ;]
Pozdrawiam.
To były testy w pętli for i <= 100, robiłem testy dla 1000 i dla 1 000 000, dla 1 000 000 tablice ukończyły test w 16 sekund, a instancje obiektow w tablicy nie ukonczyly testu z powodu braku pamięci.
Sedziwoj
23.07.2008, 09:58:10
Cytat(eai @ 21.07.2008, 16:49:12 )

To były testy w pętli for i <= 100, robiłem testy dla 1000 i dla 1 000 000, dla 1 000 000 tablice ukończyły test w 16 sekund, a instancje obiektów w tablicy nie ukończyły testu z powodu braku pamięci.
To zadbaj o ten wyciek pamięci, bo każdy obrót pętli powinien być na "świeżo", ponieważ w normalnym użytkowaniu Router jest tylko raz wywoływany.
Ja bym szybciej rozdzielił rodzaje tras, może nawet na takie co wymieniłaś, i odpowiednio je kolejkował.
Mnie jeszcze zastanawia wielopoziomowe przekierowanie, czyli wykorzystanie tylko części informacji, a dalsze dobieranie akcji już odbywa się na poziomi niżej. (nie jestem pewien ale coś jak urls w Django)
SHiP
31.07.2008, 10:41:15
Ja swój router oparłem o dynamiczne dobieranie typów. Pierwsze 2 parametry adresu tj. /klasa/metoda to nic innego jak odwolania do konkretnego controllera i jego metody. Pozostałe dane z adresu dobiera juz sobie indywidualnie controller podajac tablice typow np.
Kod
id => integer
title => string
mydate => date
Dzieki temu aplikacja moze dzialac w kilku różnych trybach np.
/klasa/metoda/1/tytul/2008-07-31
/klasa/metoda/2008-07-31/tytul/1
/klasa/metoda/2008-07-31/1/tytul
itd.
Oczywiście mam tez system linków, dzięki którym router sam dobiera wszystkie lub tylko część parametrów adresu.
Tak więc u mnie jest to uklad statyczno-dynamiczny(linki) a nastepnie dynamiczny.
Przemielanie ogromnej tablicy w poszukiwaniu odpowiedniego wzorca adresu to imho pomyłka. Tak routera tworzyc się nie powinno. Zmniejsza to elastyczność(tworząc controller trzeba edytować konfiguracje routera) i działa duużo wolniej.
Tworzenie routera obslugującego tylko skladnię opartą o rewrite również jest dziwne(żechyba robi się aplikacje na własny użytek) Dobrze jest zrobić 2 tryby adres.pl/zmienne oraz adres.pl/index.php?/zmienne
Sedziwoj
31.07.2008, 14:06:06
@SHiP
Wiesz, można mieć tak że jest obiekt który tłumaczy dane wejściowe (czy to z URL, konsola czy jakkolwiek) i dopiero potem przekazuję te informacje obiektowi który uruchamia odpowiednią akcję. Takie rozdzielenie pozwala zmieniać, skąd dane pochodzą, niezależnie od tego jak są wykorzystywane przy uruchamianiu odpowiednich akcji.
splatch
9.09.2008, 08:02:23
Bardzo dobry routing posiada Agavi,
opis w dokumentacji i
manualu.
jarek_bolo
9.09.2008, 15:26:44
W Kohanie integrują Routing oparty na tym:
http://dev.horde.org/routes/Całkiem rozbudowany system routingu.
bigZbig
21.10.2008, 18:33:01
Cytat(SHiP @ 31.07.2008, 11:41:15 )

...Dzieki temu aplikacja moze dzialac w kilku różnych trybach np.
/klasa/metoda/1/tytul/2008-07-31
/klasa/metoda/2008-07-31/tytul/1
/klasa/metoda/2008-07-31/1/tytul
itd.
Jeśli cię dobrze zrozumiałem do jednego zasobu możesz dzięki temu stworzyć 3 różne linki, które pokarzą to samo. Osobiście proponowałbym zaimplementowanie mechanizmu, który do danego zasobu umożliwi stworzenie tylko jednego linka. Każda zmiana w linku powinna prowadzić do innego zasobu albo też zwracać kod 404. Jest to niezwykle istotne z punktu widzenia pozycjonowania stron.
Sedziwoj
21.10.2008, 22:51:19
@bigZbig
Nie chodzi o to aby wykorzystywać wiele różnych linków w aplikacji, ale aby router umożliwiał użycie takich jakie mamy ochotę i zmianę, jeśli jest taka potrzeba.
Po zmianie stare linki też powinny funkcjonować, więc nie powinno się ich po prostu pozbywać.
Sh4dow
22.10.2008, 10:04:23
Nie wiem ale czasami takiego sposobu rozwiązywania routerów nie pojmuje. Może jest to pro ale jak dla mnie czasami mało elastyczne. Nie chce się spierać czy robię lepiej czy nie, po prostu przedstawię to co ja kiedyś zrobiłem i używam do dziś.
Każdy URL jaki przychodzi do aplikacji leci przez 'index.php', nie wliczając URL'i które są fizycznie istniejącymi plikami lub katalogami. układ URL'a to '/nazwaKlasyAkcji/dowolna/ilosc/parametrow'.
Każda klasa akcji ma swój własny (ja sobie to tak nazywam) miniRouter który na podstawie dowolnych parametrów wywołuje określoną metodę, która wykonuje resztę działań.
Wady to to ze miniRouter należało by definiować dla każdej klasy. Zalety to możliwość tworzenia miniRouterów dla kazdej z klasy i nie działanie na sztywnych schematach co czasami nie jest wygodne.
Pewnie to kiedyś sie rozwinie i może dojdą jakieś gotowe schematy ale na chwile obecna działa i to mnie cieszy
bigZbig
24.10.2008, 14:46:52
Cytat(Sedziwoj @ 21.10.2008, 23:51:19 )

Po zmianie stare linki też powinny funkcjonować, więc nie powinno się ich po prostu pozbywać.
Po zmianie stary link powinien zwracać nagłówek 301 Moved Permanently (Zasób trwale przeniesiony) i wskazać nowy link do zasobu
Sedziwoj
27.10.2008, 10:38:42
Cytat(bigZbig @ 24.10.2008, 15:46:52 )

Po zmianie stary link powinien zwracać nagłówek 301 Moved Permanently (Zasób trwale przeniesiony) i wskazać nowy link do zasobu
Czyli mówisz to co ja, powinien nadal działać.
Moli
29.12.2008, 21:39:15
W temacie ostatnio nikt nie pisze, więc opiszę w jaki sposób ja robie router

U mnie wszystko opiera się na wyrażeniach regularnych, jeśli jest to domena główna to pobiera tablicę z pliku:
Cytat
config/router.php
jeśli subdomena (np. xxx.nazwa.pl) to:
Cytat
config/router/xxx.php
jeśli adres to nazwa.pl/admin/.... to:
Cytat
config/router/admin.php
Tablica z routerem wygląda tak:
<?php
'wyrazenie' => array(kontroler
,metoda
,[opcjonalna tablica ze stalymi elementami
]), );
?>
jeśli w adresie mamy jakieś parametry zmienne pobrane z wyrażenia regularnego to przekazujemy je do danej metody w danym kontrolerze, elementy stale sa tak samo przekazywane. Elementy stałe wydają się mało potrzebne, ale chodzi o to że mam np. metodę wyświetlająca jakieś wiadomości i chce zrobić na tym samym kontrolerze wyświetlanie elementow z archiwum, wtedy daje jako parametr stały
<?php
?>
i w metodzie jednym ifem zmieniam pobieranie danych z modelu czy przekazanie do dbgrida

Jest to jedno z fajniejszych (jak dla mnie) rozwiązań, zawszę mogę zmienić format danego adresu bez większych zmian w kontrolerach czy metodach
wlamywacz
30.12.2008, 15:01:24
No i może ja swój router opiszę. Zasada jego działania opiera się na zwykłym
explode" title="Zobacz w manualu PHP" target="_manual. Czyli:
Cytat
www.domena.pl/admin-users/create/
lub
Cytat
www.domena.pl/admin/index/
Pierwsza zmienna (
admin-users lub
admin) to nazwa obiektu kontrolera który ma zostać utworzony. Jeśli jest to tablica, następuje znowu użycie funkcji
explode" title="Zobacz w manualu PHP" target="_manual i wychodzi na to że nasz kontroler znajduje się
aplication/controllers/adminControllers/usersController.php. Chodziło dokładnie mi o to że mogę tworzyć coś w rodzaju modułów do poszczególnych kontrolerów. Następna zmienna (
create lub
index) to nazwa funkcji którą ma zostać wywoła, w przypadku jej braku odpala defaultFunction. Następne zmienne są przekazywane jako parametry odpowiednią funkcją i to na tyle
bim2
13.01.2009, 23:25:59
To może ja zapodam już gotowy Router. Pewnie jest do zrobienia parę zmian/dodatków ale swoją podstawową funkcję spełnia.
http://hernass.pl/download/entry-b9e3dca91...0719b6ae3a2.htmPewnie niektórzy mają sprawniejsze pomysły, ale na razie udało mi się napisać coś takiego.
bigZbig
13.02.2009, 15:09:52
@bim2 Widze, że coś podobnego do rootera w Zend Frameworku wykombinowałeś. Ja próbuję zrobić rooter który działa na podobnej zasadzie co Twój tylko, żeby nie trzeba było nazw zmiennych w url-u podawać. Poszczególne zmienne są rozpoznawane na podstawie ich położenia w ścieżce.
bim2
13.02.2009, 15:53:11
W sumie można dopisać do tych confingu które położenie jak nazywa się zmienna

Albo w skrypcie podawać po kolejnosci zmiennej, tylko to tyle roboty co dodanie kolejnych sposobów routingu
Helid
10.02.2010, 19:01:33
Najpraktyczniejszym rozwiązaniem jest już powyżej wspominane "sprawdzanie etapowe":
- strony statyczne (/rejestracja.html na moduł register, akcje home)
- wyrażenie regularne (/([a-z]).html na page, akcje view z parametrem $1)
- wszystkie pozostałe na moduł home, 404 itd
Wszystko pięknie działa, a możliwości konfiguracji praktycznie nieograniczone
tomahawk
1.08.2010, 20:36:41
Pozwolę sobie odkopać temat.
Jak proponujecie przekazywać parametry z url do metody akcji?
Jako tablicę np. $c->akcja($params); Czy może $c->akcja($id,$page); ?
I zależnie od wybranego sposobu jak proponujecie rozwiązać problem error 404?
Bo jeżeli mam url: /c/akcja/id/page to jest ok. Natomiast jeżeli ktoś dopisze /c/akcja/id/page/costam/costam2/ to w jaki sposób rozpoznać że strona nie istnieje? Bo można by w każdej metodzie-akcji zdefiniować ile powinna mieć parametrów i liczyć ile jest parametrów wejściowych... No ale to trzeba by było to samo w każdej akcji klepać.
Acha... mówię o przypadku routingu niestatycznego kiedy nie mamy w tablicy zapisanych tras. Bo jak ma się trasy to wystarczy sprawdzić czy któraś pasuje i jak żadna nie pasuje to 404.
1. W mojej opinii dane z routingu powinno sie wykorzystywac jaka dane z GET i tam je wrzucic - ew ubrac w obiekt.
2. Tak czy tak w jakis sposob musisz zapisac liczbe potrzebnych parametrow do akcji, ew parsowac w .htaccess i ustawic customowy 404.
Ormin
2.09.2010, 17:59:38
A teraz coś innego , hasło Router, ale nie chodzi o URLe.
Mam aplikację. Dużą aplikację , która pobiera z wielu serwerów wiele plików. Zastanawiam się, jak sensownie rozdzielić obciążenie, tak, aby dać maksymalną elastyczność ( środowisko pracy jest bardzo niestabilne, dajmy na to chociazby że tylko niektóre dedykowane moga pobierac z okreslonych serwerów ) a jednocześnie w miare robic to normalnie. No to pomyslalem o ,,Routerze", choc chyba odpowiednia nazwa bardziej bylby Load Balancer, ktory pod kazdy serwis mialby tablice IP serwerów pod ktore sie laczy zasadą Round-Robin.
Dobry pomysl? Zly pomysl? Argumentujcie, propozycje mile widziane ;D
Cytat(tomahawk @ 1.08.2010, 21:36:41 )

Pozwolę sobie odkopać temat.
Jak proponujecie przekazywać parametry z url do metody akcji?
Jako tablicę np. $c->akcja($params); Czy może $c->akcja($id,$page); ?
I zależnie od wybranego sposobu jak proponujecie rozwiązać problem error 404?
Bo jeżeli mam url: /c/akcja/id/page to jest ok. Natomiast jeżeli ktoś dopisze /c/akcja/id/page/costam/costam2/ to w jaki sposób rozpoznać że strona nie istnieje? Bo można by w każdej metodzie-akcji zdefiniować ile powinna mieć parametrów i liczyć ile jest parametrów wejściowych... No ale to trzeba by było to samo w każdej akcji klepać.
Acha... mówię o przypadku routingu niestatycznego kiedy nie mamy w tablicy zapisanych tras. Bo jak ma się trasy to wystarczy sprawdzić czy któraś pasuje i jak żadna nie pasuje to 404.
Ja osobiście chwalę sobie przekazywanie jako parametry metody czyli:
articles/view/What_about_routing/5/2
wywołało by $articlesController -> view('What_about_routing', 5, 2);
Oczywiście warto też zrobić tak żeby example.com/articles wywołało np. $articlesController -> main();

private function view($articleName, $articleCategory, $articleID)
{
...
}
dzięki temu metoda kontrolera staje się czytelna a parametry tejże metody dodatkowo można zgrabnie opisać phpdoc jako @param. Jedyny minus to to że articleName (które dopisaliśmy do adresu tylko po to żeby google ładnie indeksowało) jest nie potrzebnie przekazywane. Ale po 1. jest to mały minus a po 2. nie zawsze wrzucamy do adresu takie rzeczy.
Co do rozpoznawanie czy strona nie istnieje, to czy na prawdę musimy to robić? Kto przy zdrowych zmysłach będzie tam próbował coś dopisać?

Tylko ewentualnie jakieś próby hackingu. Wychodzę z założenia że jeżeli zdarzenie nie jest czymś co normalny użytkownik robi to nie ma co się trudzić z jego obsłużeniem. Na upartego trzeba by było do każdej metody dopisywać coś w stylu:
hind
15.10.2010, 09:15:35
ja u siebie mam rozwiązane to w ten sposób że do klasy kontrolera przekazywany jest obiekt z parametrami
i potem w kontrolerze już tylko
public function indexPage() {
echo $this->router->args[0
] ; }
gdzie $this->router jest ustawiany w konstruktorze (jedyny argument do konstruktora), a następnie dane w metodzie exec() są przetwarzane
a w tedy tak jak u @bmL dla celów SEO dalsze argumenty są ignorowane (/art/43/jakis-malo-istotny-tekst")
Crozin
15.10.2010, 14:28:21
Cytat
Jedyny minus to to że articleName (które dopisaliśmy do adresu tylko po to żeby google ładnie indeksowało) jest nie potrzebnie przekazywane.
Nie patrzyłem jak to dokładnie zaimplementowało, ale Symfony2 przekazuje parametry wywołania do metod właśnie w taki sposób jak pokazałeś i jest w stanie pominąć zbędne parametry oraz zignorować ich kolejność:
/article/:category/:id/:slug
public function viewAction($id);
public function viewAction($id, $category);
public function viewAction($category, $id);
public function viewAction($category, $id, $slug);
// Wszysystkie powyższe są poprawne
Będę musiał sprawdzić jak to jest dokładnie zrobione, bo wygląda co najmniej interesująco

Tak na szybkiego spojrzałem i widzę że wymaga to także definiowania kolejnego pliku z regułami routera więc jednak trzeba niestety więc kodu nastukać

Ale rozwiązanie jest interesujące
mrWodoo
2.05.2013, 14:47:24
Mój router
http://wklej.to/UbZcaKlucz zabezp. - 123
Dobrze to zrobiłem? Jeszcze nie skończone, bo brakuje wymagań dla zmiennych tj. tylko liczby, tekst, bez myslnikow itd. itd.
Glownie prosze o analize metody route, bo calkiem rozbudowana mi sie wydaje, moze namieszalem? Może okaże się, że dodam kilka ścieżek i samo przeprasowanie tego przez router zajmie 70% czasu wykonywania sie skryptu?
em1X
19.10.2013, 00:08:43
Cytat(mrWodoo @ 2.05.2013, 15:47:24 )

Mój router
http://wklej.to/UbZcaKlucz zabezp. - 123
Dobrze to zrobiłem? Jeszcze nie skończone, bo brakuje wymagań dla zmiennych tj. tylko liczby, tekst, bez myslnikow itd. itd.
Glownie prosze o analize metody route, bo calkiem rozbudowana mi sie wydaje, moze namieszalem? Może okaże się, że dodam kilka ścieżek i samo przeprasowanie tego przez router zajmie 70% czasu wykonywania sie skryptu?
Niemożliwe do przetestowania testami jednostkowymi
Nie przestrzegasz standardów kodowania
Tworzysz "hard dependencies"
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.