0 follower

Zarządzanie adresami URL

Pełne zarządzanie adresami URL w ramach aplikacji webowej składa się z dwóch aspektów. Pierwszy, gdy ze strony użytkownika pojawia się żądanie w formacie URL. Wówczas aplikacja musi przetworzyć je do postaci zrozumiałych dla siebie parametrów. W drugim przypadku aplikacja musi dostarczyć mechanizmu tworzenia takich adresów URL, by były one zrozumiałe dla samej aplikacji. W przypadku aplikacji Yii jest to dokonywane przy pomocy CUrlManager.

1. Tworzenie adresów URL

Pomimo, że adresy URL mogą być sztywno zapisane w widokach kontrolera, bardziej elastycznym sposobem jest ich dynamiczne tworzenie:

$url=$this->createUrl($route,$params);

gdzie $this odnosi się do instancji kontrolera; $route określa trasę route wywołania; $params jest listą parametrów GET, dodaną do adresu URL.

Domyślnie adres URL utworzony przez createUrl jest w tak zwanym formacie get. Przykładowo, dla zadanych $route='post/read' i $params=array('id'=>100), uzyskamy następujący URL:

/index.php?r=post/read&id=100

parametry pojawiają się w wywołaniu w postaci listy wyrażeń Name=Value, złączonych znakiem ampersand (&). Parametr r reprezentuje żądanie route. Ten format URL nie jest zbyt przyjazny użytkownikowi, ponieważ wymaga kilku nieczytelnych znaków.

Możemy sprawić by powyższy URL prezentował się czytelniej i był bardziej zrozumiały używając adresu formatowanego ukośnikami (ang. path), który eliminuje kwerendę i umieszcza parametry GET na ścieżce adresu URL:

/index.php/post/read/id/100

Aby zmienić format adresów URL musimy skonfigurować komponent aplikacji urlManager tak, by createUrl mógł automatycznie przełączyć się na nowy format i by aplikacja mogła zrozumieć nowe adresy URL:

array(
    ......
    'components'=>array(
        ......
        'urlManager'=>array(
            'urlFormat'=>'path',
        ),
    ),
);

Zauważ, że nie musimy definiować klasy komponentu urlManager ponieważ jest on wstępnie zadeklarowana jako CUrlManager w CWebApplication.

Wskazówka: URL wygenerowany przy pomocy metody createUrl jest adresem względnym. Aby uzyskać pełny adres wystarczy poprzedzić adres względny Yii::app()->hostInfo lub wywołać metodę createAbsoluteUrl.

2. Przyjazne adresy URL

Gdy używany jest URL formatowany ukośnikami (ang. path) możemy zdefiniować pewne reguły tworzenia URL tak, by adres był jeszcze bardziej przyjazny użytkownikowi. Przykładowo możemy generować adres tak krótki jak /post/100, zamiast długiego /index.php/post/read/id/100. Reguły tworzenia adresów URL używane są przez CUrlManager, zarówno do celów tworzenia, jak i przetwarzania adresów URL.

Aby utworzyć te reguły musimy skonfigurować właściwość rules komponentu aplikacji urlManager:

array(
    ......
    'components'=>array(
        ......
        'urlManager'=>array(
            'urlFormat'=>'path',
            'rules'=>array(
                'pattern1'=>'route1',
                'pattern2'=>'route2',
                'pattern3'=>'route3',
            ),
        ),
    ),
);

Opisywane reguły definiowane są w tablicy przechowującej pary wyrażeń postaci wzorzec-trasa, każda z takich par odpowiada jednej regule. Wzorzec reguły jest łańcuchem używanym w celu dopasowania części informacyjnej adresu URL do wzorca. Trasa powinna odnosić się do poprawnej trasy kontrolera.

Info: Rozpoczynając od wersji 1.0.6, reguła może zostać jeszcze bardziej dostosowana poprzez ustawienie jej opcji urlSuffix oraz caseSensitive. Poczynając od wersji 1.0.8 reguła może również posiadać domyślne parametry defaultParams, które reprezentują listę par nazwa-wartość, które będą dołączone do zmiennej globalnej $_GET. Aby wzbogacić regułę o te opcje, powinniśmy zdefiniować część trasy reguły jako tablicę, jak pokazano dalej:

'pattern1'=>array('route1', 'urlSuffix'=>'.xml', 'caseSensitive'=>false)

Info: Starting from version 1.0.6, a rule may be further customized by setting its urlSuffix and caseSensitive options. And starting from version 1.0.8, a rule may also have defaultParams which represents a list of name-value pairs to be merged into $_GET. To customize a rule with these options, we should specify the route part of the rule as an array, like the following:

Używanie nazwanych parametrów

Reguła może być powiązana z kilkoma parametrami GET. Te parametry pojawiają się we wzorcu reguły jako specjalne znaczniki o formacie:

<ParamName:ParamPattern>

gdzie ParamName określa nazwe parametru GET, a opcjonalny ParamPattern definiuje wyrażenie regularne, które ma być używane do badania dopasowania wartości parametru GET. W przypadku gdy pominięto ParamPattern, oznacza to, że parametr ten może zawierać wszystkie znaki poza ukośnikiem /. Gdy tworzymy adres URL znaczniki tych parametrów zostaną zastąpione odpowiednimi wartościami parametru GET; podczas przetwarzania adresu URL odpowiednie parametry GET zostaną wypełnione wynikami tego przetwarzania.

Pokażmy kilka przykładów by wyjaśnić jak działają reguły adresów URL. Zakładamy, że nasz zestaw reguł składa się z trzech, widocznych poniżej:

array(
    'posts'=>'post/list',
    'post/<id:\d+>'=>'post/read',
    'post/<year:\d{4}>/<title>'=>'post/read',
)
  • Wywołanie $this->createUrl('post/list') tworzy /index.php/posts. Stosowana jest pierwsza reguła.

  • Wywołanie $this->createUrl('post/read',array('id'=>100)) generates /index.php/post/100. Zastosowana została druga reguła.

  • Wywołanie $this->createUrl('post/read',array('year'=>2008,'title'=>'a sample post')) tworzy /index.php/post/2008/a%20sample%20post. Zastosowana została trzecia reguła.

  • Wywołanie $this->createUrl('post/read') tworzy /index.php/post/read. Żadna z reguł nie została użyta.

Podsumowując: gdy używamy createUrl do generowania adresów URL, trasa i parametry GET przekazywane do tej metody umożliwiają wybór reguły, która ma być zastosowana. Jeżeli każdy z parametrów powiązanych z pewną reguła występuje również wśród parametrów GET przekazywanych do createUrl i jeżeli trasa zawarta w tej regule pasuje do trasy w parametrach wywołania metody, to ta reguła będzie użyta do wygenerowania adresu URL.

Jeżeli parametrów GET przekazywanych do metody createUrl jest więcej niż wymaga jakakolwiek reguła, nadmiarowe parametry pojawią się w ciągu argumentów tej metody. Przykładowo: jeżeli wywołamy $this->createUrl('post/read',array('id'=>100,'year'=>2008)) otrzymalibyśmy /index.php/post/100?year=2008. Po to, by te dodatkowe parametry pojawiły się w części informacyjnej adresu, powinniśmy dodać /* do reguły. Wówczas, używając reguły post/<id:\d+>/*, możemy uzyskać adres URL postaci /index.php/post/100/year/2008.

Jak wcześniej wspominaliśmy innym zastosowaniem reguł URL jest przetwarzanie wywoływanych adresów URL. Jest to oczywiście proces odwrotny do tworzenia adresów. Np. gdy użytkownik zgłasza żądanie adresu /index.php/post/100, zastosowanie będzie miała druga reguła z przykłady wyżej. Spowoduje to rozłożenie żądania na trasę post/read i parametr GET array('id'=>100) (dostępny poprzez $_GET).

Uwaga: korzystanie z reguł URL obniża wydajność aplikacji. Dzieje się tak ponieważ CUrlManager przetwarzając wywoływany URL porównuje go z każdą regułą, aż nie trafi na odpowiednią. Im większa ilość reguł, tym większy mają one wpływ na wydajność. Z tego względu w mocno obciążanych aplikacjach webowych należy minimalizować użycie reguł URL.

Parametryzowane trasy

Poczynając od wersji 1.0.5, możemy odnosić się do nazwanych parametrów w części reguły związanej z trasą. Pozwala to zastosować regułę do wielu tras w oparciu o spełniane kryterium. Może to pomóc zredukować ilość reguł potrzebnych dla aplikacji i przez to zwiększyć ogólną wydajność.

Będziemy używać następujących przykładowych reguły aby zilustrować jak parametryzować trasę za pomocą nazwanych parametrów:

array(
  '<_c:(post|comment)>/<id:\d+>/<_a:(create|update|delete)>' => '<_c>/<_a>',
  '<_c:(post|comment)>/<id:\d+>' => '<_c>/read',
  '<_c:(post|comment)>s' => '<_c>/list',
)

W powyższym kodzie, uzyliśmy dwóch nazwancyh parametrów w cześci reguły odnoszącej się do strasy: _c oraz _a. Pierwszy parametr odpowiada ID kontrolera posiadającym wartość post lub comment, podczas gdy drugi odpowiada ID akcji, która może mieć wartość create, update lub delete. Możesz nazywać parametry dowolnie, dopóki ich nazwy nie konfliktują z parametrami GET znajdującymi się w URLach.

Używając powyższych reguł, URL /index.php/post/123/create zostanie sparsowany na trasę post/create z parametrem GET id=123. A biorąc pod uwagę trasę comment/list oraz parametr GET page=2, możemy stworzyć URL /index.php/comments?page=2.

Ukrywanie index.php

Czyszcząc adresy URL możemy zrobić jeszcze jedną rzecz więcej ukrywając w adresie URL skrypt startowy index.php. To wymaga od nas skonfigurowania web serwera oraz komponentu aplikacji urlManager.

Po pierwsze musimy skonfigurować web serwer tak, by adres URL pozbawiony skryptu wejściowego mógł być zawsze obsługiwany z uwzględnieniem skryptu. W przypadku serwera HTTP Apache może to być zrealizowane poprzez włączenie tzw. mechanizmu nadpisywania URL (ang. URL rewriting engine) i zdefiniowanie kilku reguł nadpisywania. Możemy stworzyć plik /wwwroot/blog/.htaccess z następującą zawartością. Zauważ, że ta sama zawartość może zostać umieszczona w pliku konfiguracji Apache'a wewnątrz elementu Directory dla /wwwroot/blog.

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# jeżeli katalog lub plik istnieje użyj ich bezpośrednio
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# w przeciwnym razie przekieruj na index.php
RewriteRule . index.php

Później konfigurujemy wspomnianą właściwość showScriptName komponentu urlManager przypisując jej wartość false.

Teraz możemy wywołać $this->createUrl('post/read',array('id'=>100)), otrzymując URL /post/100. I co ważniejsze ten adres URL będzie poprawnie rozpoznany przez twoją aplikację webową.

Pozorowany sufiks adresu URL

Możemy również dodawać pewne sufiksy do adresów URL. Na przykład możemy uzyskać /post/100.html zamiast /post/100. To sprawia, że wygląda on bardziej jak URL do strony statycznej. Aby to zrobić po prostu skonfiguruj komponent urlManager ustawiając jego właściwość urlSuffix na taki sufiks, jaki ci odpowiada.