27 Mar, 2010 | Artykuły, PHP
Bawiąc się frameworkiem [1] CakePHP (wersja 1.3) natrafiłem ostatnio na pewien problem: wyobraźmy sobie całkiem sporą aplikację opartą o Cake z dziesiątkami widoków. W każdym z tych widoków, co najmniej parę razy korzystamy z metody link()
Cake-owego HtmlHelpera
np.:
|
metoda domyślnie wygeneruje następujący mark-up:
|
tymczasem potrzebowałem, aby zwracany mark-up miał taką postać:
|
Aby tego dokonać, konieczne jest wywołanie metody link()
w ten sposób:
|
Jak widać, aby osiągnąć pożądany mark-up, należy wyłączyć domyślny „escaping” tytułu linku w metodzie link()
. Wszystko fajnie – tylko co jeśli chciałbym, aby linki w całej aplikacji miały element span
w środku? Przecież nikt przy zdrowych zmysłach nie będzie przeczesywał kilkudziesięciu widoków i zmieniał parametrów wywołań metody link()
. Jak ugryźć ten problem? Zanim przedstawię rozwiązanie, przytoczę parę istotnych informacji o helperach w CakePHP.
Generalnie w Cake nie ma czegoś takiego jak automatyczne ładowanie helperów w momencie pierwszego użycia w widoku (przynajmniej na chwilę obecną). To, z jakich helperów chcemy korzystać w widoku, określamy za pomocą atrybutu $helpers
w kontrolerze np.:
|
Dzięki powyższej konstrukcji, w widoku każdej akcji kontrolera Posts
mamy dostęp do HtmlHelpera
i RssHelpera
. Atrybutu $helpers
możemy użyć także w AppController
, czyli „kontrolerze wszystkich kontrolerów” – w ten sposób dany helper zostanie załadowany globalnie dla wszystkich widoków w naszej aplikacji:
|
Teraz mała zagadka – jakie helpery zostaną załadowane w widoku akcji index()
w PostsController
? Prawidłowa odpowiedź: Session
, Form
, Html
, Rss
– dzieje się tak, ponieważ tablica $helpers
z AppController
jest łączona z tablicą $helpers
danego kontrolera (w naszym przypadku PostsController
).
W tym momencie rodzi się pytanie: co zrobić, jeżeli z danego helpera chcemy skorzystać tylko w jednej akcji danego kontrolera i nie chcemy ładować go dla innych akcji bo np. mamy na względzie oszczędność zasobów serwera? Nic bardziej prostszego:
|
Dzieki temu zabiegowi, trzymając się naszego przykładu, w widoku dla akcji index()
mamy dostęp do 5 helperów: Session
, Form
, Html
, Rss
, Time
. W taki sposób np. metoda paginate()
kontrolera ładuje PaginatorHelper
, jeśli nie został on jawnie określony w kontrolerze przez użytkownika. Czyli mamy coś na kształt ładowania helperów na żądanie. Dobrą praktyką jest napisanie prostej funkcji pomocniczej do ładowania helperów, którą umieszczamy w AppController
, by mieć do niej dostęp z wnętrza każdej akcji każdego kontrolera:
|
Uzbrojeni w te informacje, prześledźmy rozwiązanie problemu z początku tego wpisu.
Przedstawia się następująco:
HtmlHelper
(plik html.php
) z:cake/libs/view/helpers
do app/view/helpers
link()
dostosowując ją do własnych potrzebPowyższe rozwiązanie ssie z prostego powodu: za każdym razem, gdy wyjdzie nowa wersja frameworka, należy sprawdzić, czy czasem deweloperzy nie zmieniali czegoś w tej metodzie. Jeśli tak – znowu musimy wykonać proces kopiowania pliku i wprowadzania naszych poprawek.
Najlepszym wyjściem jest napisanie własnego helpera, który będzie rozszerzał domyślny HtmlHelper
– nasz helper umieszczamy w pliku app/view/helpers/custom_html.php
:
|
Jak widać w wierszu 7 wywołujemy oryginalną metodę link()
z Cake-owego HtmlHelpera
, jednak zanim to nastąpi wykonujemy czynności, które rozwiązują nasz problem z elementem span
wewnątrz linku. Oczywiście to tylko przykład, jednak daje nam obraz jak elastycznie możemy wchodzić w interakcję z Cake-owym helperem i zmieniać np. domyślne wartości parametrów. Przy tym musimy wiedzieć tylko i wyłącznie jak wygląda prototyp przeciążanej metody – nie interesuje nas jej wewnętrzna logika.
Aby skorzystać z naszego nowego helpera dodajemy go do tablicy $helpers
kontrolera:
|
i już możemy wykorzystywać jego dobrodziejstwa w widoku:
|
Zaraz, zaraz – ale przecież nadal w całej aplikacji wywołania mają postać $this->Html->link()
a nie $this->CustomHtml->link()
. Okazuje się, że recepta na ten problem jest trywialna – wystarczy proste przypisanie w widoku:
|
To, że powyższy trick działa możemy wykorzystać do ładowania naszych helperów, które rozszerzają domyślne helpery CakePHP i co najważniejsze – odnosimy się do nich przez oryginalne „frameworkowe” nazwy. Zanim Cake załaduje helpery, możemy sprawdzić:
/app/view/helpers
)CustomHtml
zamiast Html
)Idealnym miejscem realizacji dwóch pierwszych punktów z powyższej listy jest callback beforeFilter()
w AppController
:
|
Oczywiście, jeśli np. w PostsController
również korzystamy z callbacka beforeRender()
musimy jawnie (najlepiej na końcu) wywołać callback z AppController
: parent::beforeRender()
.
Mapowania naszych helperów na Cake-owe dokonujemy z kolei w callbacku beforeRender()
w AppHelper
:
|
Być może komuś powyższe rozwiązanie okaże się pomocne :) Więcej ciekawych artykułów na temat CakePHP znajdziecie na blogu [2] Grzegorza Pawlika – webbricks.
-----
Wydrukowano z: https://www.kminek.pl/elastyczne-rozszerzanie-domyslnych-helperow-w-cakephp/
Lista adresów URL występujących w tekście:
© 2007-2025 kminek.pl