Kategorie
Apache PHP Porady

Organizacja adresów URL w panelu administracyjnym

Przemyślenia na temat organizacji adresów URL w aplikacji

W czasie dokumentowania jednego z projektów, zastanawiałem się nad złożonością pliku .htaccsess, który zawierał kilkadziesiąt wpisów dotyczących panelu administracyjnego. Moim zdaniem problemu nie stanowi akurat użycie modułu mod_rewrite do przepisywania adresów, bo to bardzo popularny sposób. Innym rozwiązaniem uzyskania przyjaznych adresów jest własna klasa Router. Stosowanie przyjaznych adresów URL nie jest konieczne, a już z pewnością nie w panelu administracyjnym. Jeśli jednak zrobisz coś dobrze raz, to w kolejnym przypadku pokusa zrobienia tego źle będzie mniejsza.

Hipotetyczny problem

Kiedy zastanowimy się poważniej nad przedstawioną we wstępie tezą dojdziemy do wniosku, że bez względu sposób przepisywania adresów, problem leży po stronie organizacji adresów. Nie ma znaczenia czy określenie kontrolera, akcji i parametrów odbywa się podczas przetwarzania żądania w serwerze Apache czy w pliku PHP. Pomijam kwestie wydajnościowe czy ideologiczne, dotyczące organizacji kodu. Jeśli sama polityka adresów będzie złożona, z wieloma wyjątkami i trudna w analizie to jej obsługa stanie się problematyczna.

Moim zdaniem większość adresów panelu administracyjnego sprowadza się do serwowania danych jako listy obiektów lub pojedynczego obiektu. Kiedy przeniesiemy to na grunt czysto prezentacyjny sprowadzi się to do tabeli i formularza. Analogicznie w logice biznesowej, znowu dwa typy, czyli Collection oraz Instance.

RewriteRule ^([a-zA-Z]+)/Edit/([a-zA-Z0-9\s-_.@]+)$ index.php?ctrl=$1&act=Edit&email=$2 [L]
RewriteRule ^([a-zA-Z]+)/Edit/([0-9]+)$ index.php?ctrl=$1&act=Edit&id=$2 [L]
RewriteRule ^([a-zA-Z]+)/Edit/([a-z0-9\s-_.]+)$ index.php?ctrl=$1&act=Edit&domain=$2 [L]

Dlaczego istnieją 3 reguły do edytowania obiektów różnego typu? Fakt, że w pierwszym mamy do czynienia z adresem poczty elektronicznej, drugim z identyfikatorem liczbowym, a trzecim z domeną jest przecież zupełnie bez znaczenia. Powyższe reguły dotyczą tego samego, czyli zmiany danych konkretnego obiektu. Istotne zamiast postaci identyfikatora jest jego wartość. Zatem czemu służy szukanie poprzez różne reguły identyfikatorów różnego typu?

Wiem! Poprawa bezpieczeństwa i ograniczenie polityki dostępu.

Proszę cię. Wierzysz w to, a może to jedna z Twoich kolejnych niesamowitych teorii, powtarzanych do znudzenia, aż w końcu zabrzmią jak prawda. Moim zdaniem, przekazanie do aplikacji identyfikatora w dowolnej postaci jest równie bezpieczne. Dodatkowo całość stanie się przejrzysta, czytelna i łatwiejsza w rozwoju. Przecież dostęp do obiektu bazodanowego uzyskamy dopiero po weryfikacji uprawnień w samej aplikacji, a nazwa zmiennej nie ma żadnego znaczenia w tej sytuacji. Moja propozycja dla reguły typu instance resource przedstawia się bardzo prosto:

RewriteRule ^([a-zA-Z]+)/Edit/([^/]+)$ index.php?ctrl=$1&act=Edit&id=$2 [L]

Ponieważ nie ograniczamy w zasadzie konwencji nazewnictwa obiektów w naszej aplikacji, możliwa jest sytuacja, w której identyfikator danego obiektu będzie wyjątkowo skomplikowany. Głupotą będzie poddanie się argumentom typu: „mniej precyzyjne dopasowanie ciągu, zmniejsza bezpieczeństwo aplikacji”, skoro nigdy nie ufamy danym przesłanym przez użytkownika. Prawda.

Kolejnym przykładem, być może nawet prostszym w rozumieniu architektury informacji jest lista wszystkich obiektów. Tak się składa, że w dużym uproszczeniu systemy informatyczne sprowadzają się do prezentowania danych (Index) oraz ich zmiany (Edit/Update). Dopełnieniem tych dwóch niech będzie dodawanie (Add/Insert) oraz usuwanie (Delete). Wyświetlenie danych konkretnego typu wymaga od nas jednej informacji. Poniższe reguły w zupełności wystarczą do obsługi żądań typu collection resource.

RewriteRule ^([a-zA-Z]+)$ index.php?ctrl=$1&act=Index [L]
RewriteRule ^([a-zA-Z]+)/([a-zA-Z]+)$ index.php?ctrl=$1&act=$2 [L]

Czy to jest skomplikowane? Ależ skąd. Rozwiązania proste są najlepsze.

Jedna reguła, aby wszystkimi rządzić. Jedna, aby w mroku wszystkie związać!

Dobra przesadziłem, ale trudniej o bardziej obrazowy przykład. Na tym polega właśnie prostota. Dlaczego komplikujemy rzeczy w istocie proste. Lista komentarzy wymaga jedynie informacji jaka tabela przechowuje te dane (comments), podobnie każdy inny zasób. Przekazanie akcji Index jest pewnym dodatkiem, który w naszej aplikacji komplikuje organizację adresów URL.

Prezentowanie danych to więcej niż tylko zwykła kolekcja. Nie wyobrażasz sobie przecież braku porcjowania, sortowania, filtrowania i wyszukiwania danych. Właśnie te aspekty utrudniają utrzymanie wszystkiego w prostej postaci, jako jednej reguły dostępu. Jednak dwie lub trzy reguły to nie kilkadziesiąt. Zatem jeśli to możliwe: Zrób to prosto, ale nie prościej niż potrzeba!.

Dodatkowe problemy niosą za sobą wyjątkowe akcje w aplikacji, które mniej lub bardziej pasują do przedstawionych podstawowych reguł. Jednak zachowanie rozsądku i dyscyplina spowodują, że nasze założenie nie rozsypią się po kilku tygodniach czy miesiącach, gdy projekt z małej aplikacji zamieni stanie się wielką kobyłę, przepraszam – kod klasy enterprise.

Podsumowanie

Przedstawione przykłady pokazują dwie możliwości z jakimi spotyka się programista, a przed nim architekt aplikacji. Istnieje bardzo mała granica pomiędzy upraszczaniem rzeczy skomplikowanych, a komplikowaniem rzeczy prostych. Jeśli jesteśmy świadomi konsekwencji naszych decyzji w przyszłości, najpierw kilka razy zastanowimy się nad implementacją danego rozwiązania.