--=REKLAMA=--
Proste adresy internetowe nazywane też czytelnymi dla człowieka (human-readable), czystymi albo przyjaznymi dla wyszukiwarek (Search Engine Friendly, SEF) to adresy URL, które mają sens zarówno dla ludzi, jak i wyszukiwarek, ponieważ objaśniają ścieżki do stron, na które wskazują. Człowiek może je łatwo zapisać, zapamiętać i przeczytać, a robot wyszukiwarki zidentyfikować na ich podstawie strukturę witryny i prawidłowo ją zaindeksować.
Od wersji 1.5, Joomla! jest zdolny do tworzenia i przetwarzania adresów URL w dowolnym formacie, w tym adresów przyjaznych dla wyszukiwarek. Funkcja ta nie jest zależna od translacji (przepisywania) URL przez serwer WWW, działa, nawet jeśli Joomla jest zainstalowany na innym serwerze niż Apache z modułem mod_rewrite. Proste adresy tworzone są według ustalonego wzorca, ale użytkownik może sam zdefiniować krótki tekst opisowy (alias) dla każdego segmentu adresu URL.
Wewnętrzna, lokalna część prostego adresu URL (część po nazwie domeny) nazywa się trasą (route. Dlatego tworzenie i przetwarzanie adresów SEF nazywane jest dalej trasowaniem (routing), a odpowiedni kod nazywany jest ruterem (router).
W Joomla! każdy komponent jest odpowiedzialny za obsługę własnych adresów SEF. Dlatego też, jako twórca komponentu, będziesz musiał stworzyć własny router, aby umożliwić komponentowi używanie adresów SEF.
Zakładając, że stosujesz standardowe praktyki rozwoju, Twój komponent używa prawdopodobnie systemowe adresy URL, które wyglądają trochę jak http://www.example.com/index.php?option=com_twójkomponent&view=article&id=1&catid=20&Itemid=50, i twoim celem jest przekształcenie tego adresu do http://www.example.com/example-menu-item/20/1. Jako deweloper, masz dwa zadania: poinformować system, że niektóre fragmenty tekstu są adresami i muszą zostać przekształcone oraz objaśnić systemowi, jak je przekształcić i używać.
JRoute::_
Trudne i nieefektywne jest dla Joomla! dowiadywanie się, które części Twojego komponentu generują URL. Do wspierania adresów SEF, trzeba będzie zmienić kod generowania adresu URL tak, że stosuje JRoute::_
przed wyprowadzeniem adresu URL:
echo JRoute::_('index.php?view=article&id=1&catid=20');
Zauważ, że jest to możliwe, aby pominięcie parametrów opcji
i Itemid
. Opcja
domyślnie składa się z nazwy komponentu aktualnie wykonywanego i Itemid
domyślnych dla bieżącego ID pozycji menu.
W ogóle, to należy stosować tylko do adresów URL, które użytkownicy i/lub wyszukiwarki są w stanie zobaczyć. Na przykład, nie ma potrzeby przekształcenia adresów stosowanych w przekierowaniach, które bezpośrednio prowadzą do innych przekierowań.
Jeśli użytkownik wyłączy adresy SEF w ustawieniach witryny, JRoute::_
będzie używać adresy nie-SEF bez żadnych zmian w kodzie.
Trzeba także napisać ruter, którym jest jeden plik z dwoma funkcjami, które przekształcają używane przez system URL-e do i z adresów SEF. Plik ten musi być umieszczony w /components/com_twójkomponent/router.php .
Pierwsza funkcja [NazwaKomponentu]BuildRoute(&$zapytanie)
musi przekształcić tablicę parametrów URL do tablicy segmentów, które będą stanowić URL SEF. Schematycznie przemiana przebiega w następujący sposób :
JRoute::_
dołączany przez Twój komponent lub inne rozszerzenie
$zapytanie=array('view'=>'article','id'=>1,'catid'=>20)
com_TwójKomponentBuildRoute
$segmenty=array(20,1)
Druga funkcja [NazwaKomponentu]ParseRoute($segmenty)
musi przekształcić tablicę segmentów z powrotem do tablicy parametrów URL. Schematycznie:
$segmenty=array(20,1)
com_twójkomponentParseRoute
$zapytanie=array('view'=>'article','id'=>1,'catid'=>20)
Obie funkcje muszą współpracować w taki sposób, żeby oryginalny URL mógł być zrekonstruowany. Możesz myśleć o BuildRoute
jako formie kodowania a ParseRoute
dekodowania. Gdy oryginalny URL nie jest prawidłowo odtwarzany, komponent przestanie działać.
Pierwszym etapem jest wygenerowanie tak zwanego aliasu. Alias jest używany w adresie URL zamiast tytułu. Jest to tekst, który chcesz mieć w adresie URL. Alias musi być bezpiecznym URI, co oznacza, że akcentowane znaki UTF8, są zastąpione przez ich odpowiedniki ASCII7, a białe znaki myślnikami itp.
Alias może być zdefiniowany przez użytkownika, ale należy upewnić się, że powyższe wymagania dotyczące bezpiecznego aliasowego URL są spełnione. Dobrym sposobem na to jest w użycie JTable::check()
w trakcie procesu zapisywania.
Spójrz na przykładowy kod:
function check() { jimport( 'joomla.filter.output' ); if(empty($this->alias)) { $this->alias = $this->title; } $this->alias = JFilterOutput::stringURLSafe($this->alias); / * Wszystkie inne Twoje kontrole * / return true; }
Jeśli pole alias jest puste, tytuł będzie używany jako alias. Następnie alias zostanie przetworzony na bezpieczny URL za pomocą JFilterOutput::stringURLSafe()
.
Kontynuując powyższy przykład "slug" - "1:Zapraszamy do joomla" ma dwie części. Pierwsza część to identyfikator artykułu (ID), a druga to alias. Są one oddzielone od siebie dwukropkiem. Te dwa elementy zostały połączone w zapytaniu do bazy danych w modelu:
$query = 'SELECT a.*, '. 'CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(":", a.id, a.alias) ELSE a.id END as slug,' /*...*/;
Po tym etapie slug jest używany zamiast id.
JRoute::_
- wewnętrzna metoda translacji URL Joomla! na URL użytkownika. JRoute posiada trzy parametry i jej prototypem jest:
JRoute::_($url,$xhtml=true,$ssl=null);
Gdzie:
$url
jest typu string zawierającym absolutny lub relatywny wewnętrzny URL Joomla!.
$xhtml
jest typu boolean i określa, czy wyjście ma być w XHTML. Ten parametr jest opcjonalny i jeśli jest pominięty ma domyślną wartość true.
$ssl
jest typu integer i określa, czy URI powinno być zabezpieczone. Przyjmuje trzy stany:
Najważniejszym parametrem jest $url
. Wywołanie tej metody może wyglądać tak:
JRoute::_( 'index.php?view=article&id='.$row->slug );
$row>slug
jest wartością generowaną w drugim etapie z kombinacji id i aliasu tytułu.
Kolejną zaletą korzystania z JRoute jest to, że ruter obsługuje teraz $option (nazwa komponentu) i $Itemid (ID pozycji menu).Sam komponent nie musi znać swojej nazwy ($option) lub aktywnej pozycji menu ($Itemid), jak to miało miejsce w poprzedniej wersji Joomla!.
Ważne jest, aby pomyśleć o kolejności parametru URL w tym etapie. Będzie to bardziej oczywiste, gdy przyjrzymy się plikowi router.php w następnej sekcji.
Proces budowania JRouter jest podzielony na dwa etapy:
W pliku router.php będziemy mieć dwie funkcje. Jedna jest odpowiedzialna za budowanie URL, a druga za parsowanie go. W następnym przykładzie zakładamy, że mamy trzy widoki, dwa bardzo proste i jeden bardziej zaawansowany, na które mogą wskazywać odnośniki. Pierwszy jest przeglądem kategorii (view=categories
), drugi pojedynczą kategorią (view=category
) i trzeci jest pojedyńczym artykułem (view=article
).
Plik router.php powinien znajdować się w obszarze frontu strony Twojego komponentu. Nie jest on używany w obszarze administracyjnym/zapleczu strony. Nie zapomnij również dodać go do Twojego pliku XML plik manifestu w folderze frontu strony Twojego komponentu.
Poniższy przykład zilustruje podstawową implementację rutera dla Twojego komponentu.
function [componentname]BuildRoute( &$query ) { $segments = array(); if(isset($query['view'])) { $segments[] = $query['view']; unset( $query['view'] ); } if(isset($query['id'])) { $segments[] = $query['id']; unset( $query['id'] ); }; return $segments; }
JRouter
przekazuje tablicę $query do funkcji [NazwaKomponentu]BuildRoute</ code>. Ta funkcja doda odpowiednie części tablicy do tablicy $segments w odpowiedniej kolejności i zwróci odpowiednio uporządkowaną tablicę. Zawartość tablicy <code>$query
nie może być ustawiona, inaczej JRouter
doda ją do adresu URL w formie łańcucha zapytania (tzn. wszelkie zmienne, które nie są obsługiwane przez ruter będą przekazywane w zapytaniu).
Prefix NazwaKomponentu jest nazwą Twojego komponentu, jaką znaleźć można w katalogu z plikami komponentów. Na przykład, komponent "Magic" w katalogu /components/com_magic/... powinien używać jako przedrostka magic
(małymi literami).
Druga funkcja w router.php parsuje adres URL:
function [componentname]ParseRoute( $segments ) { $vars = array(); switch($segments[0]) { case 'categories': $vars['view'] = 'categories'; break; case 'category': $vars['view'] = 'category'; $id = explode( ':', $segments[1] ); $vars['id'] = (int) $id[0]; break; case 'article': $vars['view'] = 'article'; $id = explode( ':', $segments[1] ); $vars['id'] = (int) $id[0]; break; } return $vars; }
Co się w niej dzieje? W funkcji [NazwaKomponentu]BuildRoute
zorganizowaliśmy pozycje w tablicy $query
w określonej kolejności. Oznacza to, że w tym przykładzie w tablicy widok jest pierwszy a identyfikator drugi.
Czytając $segments[0]
, możemy uzyskać dostęp do nazwy widoku. Ustawiamy właściwy widok i/lub identyfikator w zależności od jego wartości i zwracamy tablicę $vars
do JRouter
. Tablica $vars powinna być tablicą asocjacyjną podobną do tablicy, która została przekazana do metody BuildRoute.
Powyższy przykład z router.php jest bardzo prostym sposobem na generowanie adresów SEF, lecz powinien pokazać, jak to działa dość wyraźnie.
Wygenerowany adres URL w tym przykładzie zawiera nazwę widoku i nie odzwierciedla hierarchii zawartości:
http://www.example.com/[aliasmenu]/[widok]/[slug]
W kolejnym przykładzie spróbujemy pozbyć się konieczności podawania widoku i spróbujemy odzwierciedlić aktualny poziom hierarchii w adresie URL.
Naszym celem są URLe, które wyglądają tak:
Załóżmy, że zrobiliśmy krok 1 i 2 również dla kategorii.
Link do artykułu będzie wyglądać tak:
JRoute::_( 'index.php?view=article&catid='.$row->catslug .'&id='.$row->slug );
a link do kategorii będzie wyglądać tak:
JRoute::_( 'index.php?view=category&id='.$row->catslug );
Odpowiedni router.php:
function [''NazwaKomponentu'']BuildRoute(&$query) { $segments = array(); if(isset( $query['catid'] )) { $segments[] = $query['catid']; unset( $query['catid'] ); }; if( isset($query['id']) ) { $segments[] = $query['id']; unset( $query['id'] ); }; unset( $query['view'] ); return $segments; }
Różnica jest taka, że teraz nie możemy dodać nazwy widoku do tablicy $segments
. Nieustawiamy klucza widoku gdyż w przeciwnym razie JRouter
doda go do adresu URL jako część kwerendy. Kolejną nową rzeczą jest tutaj dodatkowy parametr catid, który wstawiamy do tablicy $segments
.
function [''NazwaKomponentu'']ParseRoute($segments) { $vars = array(); $app =& JFactory::getApplication(); $menu =& $app->getMenu(); $item =& $menu->getActive(); // licznik segmentów $count = count( $segments ); //Uchwyt widoku i identyfikatora switch( $item->query['view'] ) { case 'categories': if($count == 1) { $vars['view'] = 'category'; } if($count == 2) { $vars['view'] = 'article'; } $id = explode( ':', $segments[$count-1] ); $vars['id'] = (int) $id[0]; break; case 'category': $id = explode( ':', $segments[$count-1] ); $vars['id'] = (int) $id[0]; $vars['view'] = 'article'; break; } return $vars; }
Widać, że funkcja ParseRoute ma więcej różnych części kodu w porównaniu do poprzedniego przykładu. Powód tego jest prosty. Nie mamy nazwy widoku w tablicy $segments
i musimy znaleźć inny sposób, aby ją określić.
Musimy dowiedzieć się, z którego poziomu w hierarchii otrzymujemy element główny. Robimy to, patrząc na widok z nazwą pozycji aktywnego menu:
$item->query['view']
Musimy także znać liczbę elementów w tablicy $segments
:
$count = count( $segments );
Dzięki tym informacjom możemy prawidłowo ustawić widok dla wszystkich możliwych trzech przypadków:
$segments
ma dwa elementy ($catid
i $id
). W tym przypadku wiemy, że musimy parsować link do artykułu.
$segments
ma jeden element ($id
). W tym przypadku wiemy, że musimy parsować link do kategorii.
$segments
jest identyfikatorem artykułu.
Wynikiem całego tego kodu jest czysty i czytelny dla człowieka adres URL komponentu.
Ostatnim ważnym etapem tworzenia routera jest zastanowienie się co zrobić z pozycjami menu. Jak wyjaśniono to w Proste adresy internetowe, wyjście routera komponentu jest używane po pierwszym segmencie trasy, którym jest aliasem pozycji menu. Stwarza to trudne pytanie: skąd router i/lub inny kod ma wiedzieć, z której pozycji menu trasować?
Załóżmy na przykład, że komponent generuje wyjście dla bieżącej strony /psy, który wymienia wszystkie psy w systemie. Oczywiście, pozycjami na liście muszą być linki do stron, które wyświetlają więcej szczegółów na temat każdego psa. Co powinien zwrócić URL dla psa o ID 21 i nazwie Fido? Użyć routera, który działa zgodnie z zasadami, które widzieliśmy do tej pory. Trasa, która jest generowana /psy/21-fido, lub z dodatkowym przetworzeniem /psy/fido. Ale może użytkownik utworzył pozycję menu z aliasem mojpiesek, który wyświetla właśnie szczegółowe informacje o tym psie. Jest prawdopodobne, że intencją użytkownika było aby trasować adres URL tej pozycji menu, a pozycja na liście powinna odwoływać się do strony /mojpiesek.
Bardziej ogólnie, gdy budujesz trasę, trzeba będzie znaleźć element menu, który jest najbardziej odpowiedni jako punkt wyjścia do budowy trasy. Termin punktem wyjścia jest zaznaczony, ponieważ reszta trasy zależy od konfiguracji pozycji menu. W naszym przykładzie powyżej, /psy/21-fido jest dopuszczalną trasa, /mojpiesek jest zapewne jeszcze lepszą, ale /mojpiesek/21-fido jest po prostu błędne, ponieważ /mojpiesekjest sam w sobie jest elementem menu, który jest skonfigurowany do wyświetlania informacji o Fido.
Dostępne są różne podejścia do rozwiązania tego problemu. Podstawowe komponenty Joomla! rozdzielają zadania na dwie części: ruter i klasę pomocniczą [NazwaKomponentu]RouteHelper
. [NazwaKomponentu]RouteHelper
dostarcza metody, które mają pozyskać dane do wyświetlenia na wyjściu modułu, podczas gdy ruter analizuje pozycję menu i wstawia informacje, które są określone w konfiguracji pozycji menu do trasy.
Oznacza to, że dołączony kod musi jawnie wywołać metodę pomocnika przed trasowaniem (echo JRoute::_(PsyRouteHelper::getPiesRoute(21))
).