Kilka dni temu otrzymałem maila z zapytaniem dotyczącym helperów widoku w Zend Frameworku. Nie zagłębiając się w szczegóły, chodziło o mechanizm, który w zależności od pewnych warunków wstawi do layoutu stosowną treść. Podczas wymiany maili padło zdanie będące przyczynkiem dzisiejszego wpisu: nigdzie nie znalazłem konkretnego tutka nt view_helperów. Od dnia dzisiejszego powyższe stwierdzenie przestaje być prawdziwe.
Co to jest helper widoku?
Helperem widoku w kontekście Zend Frameworka nazywamy powtarzalny fragment kodu, który oprócz warstwy prezentacyjnej, posiada własną logikę. Za przykład niech posłuży typowy element większości stron – mały formularz logowania – idealne miejsce do szybkiego zalogowania się do serwisu. Ale co ma się stać z formularzem, gdy użytkownik jest już zalogowany? Najczęściej w jego miejscu pojawiają się link do konta użytkownika oraz link pozwalający na wylogowanie się z serwisu. W minimalistycznej wersji formularz po prostu znika. Oczywistym jest, że dodanie, nawet najprostszego, warunku przez osobę pracującą tylko z warstwą prezentacji może stanowić problem. Poza tym naszpikowanie layoutu dziesiątkami if-ów nie jest najlepszym pomysłem. Tutaj właśnie z pomocą przychodzą helpery widoku. Zamykają one problematycznego if-a w osobnym bycie i pozwalają skupić się na layoucie jako całości, a nie na sieczce instrukcji warunkowych.
Oczywiście helpery nie służą tylko jako pojemnik na instrukcje warunkowe. Każda złożona funkcjonalność, która wymaga wymieszania kodu PHP z HTML powinna znaleźć się helperze.
Jak tworzyć helpery widoku?
Helper widoku jest klasą dziedziczącą po klasie Zend_View_Helper_Abstract. Domyślną lokalizacją helperów jest katalog application/views/helpers. Nazwa klasy helpera musi składać się z przestrzeni nazw oraz nazwy helpera. W praktyce będzie to Zend_View_Helper_MojHelper, gdzie MojHelper jest nazwą helpera oraz nazwą pliku, w którym klasa musi zostać zapisana. Ostatnim wymogiem stawianym przed helperem widoku jest nazwa głównej metody. Musi się ona nazywać tak samo jak helper, przy czym ma rozpoczynać się małą literą oraz być metodą publiczną. Przykładowy helper będzie więc miał postać:
class Zend_View_Helper_MojHelper extends Zend_View_Helper_Abstract
{
public function mojHelper()
{
}
}
Ważne jest aby pamiętać, że helper widoku ma zwrócić zawartość, a nie ją wyświetlić.
Do helpera można przekazywać argumenty. Nie różni się to niczym od przekazywania argumentów do standardowej metody znajdującej się w klasie.
class Zend_View_Helper_MojHelper extends Zend_View_Helper_Abstract
{
public function mojHelper(array $arg1, $arg2 = null)
{
}
}
Jak wywoływać helpery widoku?
Z helperów korzysta się w taki sam sposób, jak ze zwykłych metod obiektu widoku. Uczulam tutaj na stwierdzenie “obiektu widoku”. Helpery powinny być wywoływane tylko i wyłącznie w plikach layoutu oraz widoku. To, że można je wywołać w innym miejscu, nie oznacza, że powinno się to robić.
Wywołanie przykładowego helpera będzie wyglądało następująco.
// wersja bez argumentów
echo $this->mojHelper();
// wersja z argumentami
echo $this->mojHelper(array('123', '234'), 'abc');
Zwracanie zawartości przez helpery
Wspomniałem, że helper nie powinien “echować” treści, tylko ją zwracać. Ale co zrobić w przypadku, gdy kod HTML zwracany przez helper jest sporych rozmiarów, przez co babranie się w escape’owanie (nigdy nie wiem jak to poprawnie zapisać – jakieś sugestie na przyszłość ?) znaczników i argumentów powoduje ból głowy?
Rozwiązania są dwa. Możemy zwrócić treść poprzez wyrenderowanie pliku widoku lub skorzystanie z partiala. Pierwszy sposób nie różni się niczym od standardowego renderowania widoku kontrolerze. Ewentualne zmienne zapisujemy do widoku, a następnie renderujemy plik widoku
class Batman_View_Helper_MojHelper extends Zend_View_Helper_Abstract
{
public function mojHelper()
{
$this->view->zmienna = 'Jestem zmienna';
return $this->view->render('skryptWidoku.phtml');
}
}
Drugim sposobem jest skorzystanie z partiala. Tym różni się on standardowego renderowania, że dane przekazywane są bezpośrednio do pliku widoku a nie poprzez obiekt widoku. Pozwala to wyizolować dane z globalnej przestrzeni nazw i uodpornić je na przypadkowe nadpisanie.
class Batman_View_Helper_MojHelper extends Zend_View_Helper_Abstract
{
public function mojHelper()
{
return $this->view->partial('skryptWidoku.phtml', null, array('zmienna' => 'jestem zmienna'));
}
}
W obu przypadkach skrypt widoku musi znaleźć się w katalogu views/scripts. Jeśli chcielibyśmy skorzystać z pliku widoku umieszczonego w katalogu dowolnego kontrolera, wówczas przed nazwą pliku należy umieścić nazwę kontrolera, np. user/skryptWidoku.phtml.
Do zmiennych przekazanych do pliku widoku odwołujemy się z poziomu obiektu widoku. Oznacza to, że przykładową zmienną wyświetlimy tak:
<?php echo $this->zmienna; ?>
Niestandardowa klasa helpera
Czasami zachodzi potrzeba “wynieść” helper poza aplikację lub zmienić jego przestrzeń nazw/położenie. Na szczęście nie namęczymy się zbytnio podczas konfigurowania aplikacji do poprawnego ładowania helerów. Jedyne co musimy zrobić, to wskazać aplikacji gdzie ma szukać naszych klas. Najprościej i najszybciej zrobimy to w pliku konfiguracyjnym application.ini.
resources.view.helperPath.Batman_View_Helper = APPLICATION_PATH "/views/mojeHelpery"
Jako klucz musimy podać przestrzeń nazw naszych helperów (tutaj jest to Batman_View_Helper). Wartością będzie katalog przechowujący nasze pliki.
Helpery i moduły
Na koniec pozostało dowiedzieć się jak działają helpery w modułach. Tutaj niestety sprawy nie wyglądają tak różowo. Dla każdego modułu musimy dodać osobną przestrzeń nazw. Co więcej, moduł domyślny również musi znaleźć się w konfiguracji.
; domyślny moduł resources.view.helperPath.Zend_View_Helper = APPLICATION_PATH "/views/helpers" ; moduł admina resources.view.helperPath.Admin_View_Helper = APPLICATION_PATH "/modules/admin/views/helpers"
Oczywiście w miejsce Admin należy wstawić poprawną nazwę modułu.
Podsumowanie
Wydawać by się mogło, że coś tak banalnego jak helper widoku będzie prostą klasą, która po prostu działa. Okazuje się, że nawet tak prostą rzecz można skomplikować. Mam nadzieję, że udało mi się rozwiać wszystkie wątpliwości dotyczące helperów widoku w Zend Frameworku. W razie pytań piszcie śmiało.
W zasadzie można by powiedzieć, że Helper jest to pewien rodzaj widgetu, czy kontrolki znanej z aplikacji desktopowych.
Jeśli by się uprzeć, helper widoku można nazwać mini kontrolerem, który komunikuje ze sobą model i widok.
Hm, prędzej taką rolę pełnią chyba helpery kontrolera. Bo z tego co widzę to raczej nie zaleca się w helperach widokowych obsługi requestu etc.
Helpery akcji (o to chyba Ci chodziło) mają na celu dodanie funkcjonalności do procesu przepływu aplikacji.
Nic nie stoi na przeszkodzie aby obsługiwać requesty w helperze widoku (np walidacja formularza). Oczywiście należy zachować umiar, by nagle nie okazało się, że cała aplikacja tylko helperami stoi.
Właśnie je miałem na myśli :>. Oczywiście, że nie stoi na przeszkodzie, natomiast jedyny sposób użycia ich w ten fason to pobranie requestu poprzez wywołanie singletonowe FrontControllera. Pytanie tylko, czy skoro robimy rzeczy kontrolerowe w view helperze, to potrzebujemy do czegokolwiek klas kontrolera oprócz routingu ?
Jakiś czas temu spotkałem się ze schematem aplikacji/frameworka, gdzie „duże” MVC było podzielone na mniejsze MVC, które z kolei dzieliło się na jeszcze mniejsze MVC, itd. Podejście to było o tyle ciekawe, że pozwalało na tworzenie atomowych wręcz funkcjonalności, które można było przenosić między aplikacjami bez najmniejszego problemu. Niestety mimo usilnych starań, nie udało mi się odnaleźć tego artykułu.
W taki właśnie sposób postrzegam helpery widoku w ZF. Jako mniejsze odpowiedniki MVC, które wzbogacają aplikację. W wersji ekstremalnej klasa kontrolera rzeczywiście staje się tylko elementem routingu i niczym więcej.
Takie podejście nazywa się HMVC (od hierarchical) i w sumie tworze teraz coś w tym guście
Dokładnie o to chodziło. Z chęcią zobaczę jak to wygląda. Daj znać jak już stworzysz „to coś”
W zasadzie mam już podstawowy szkielet, tylko muszę dopracować jeszcze kilka szczegółów i napisać samplową aplikację ;P. Zaglądaj na blog
@batman – odnośnie MVC – miałeś na myśli ten artykuł? http://techportal.ibuildings.com/2010/02/22/scaling-web-applications-with-hmvc/
Niestety nie. Ale ten jest tak samo dobry
To, że ktoś nie potrafi szukać to nie znaczy, że w Sieci nie ma dobrych przewodników.
Chociażby świetnie pomocników widoku opisuje OFICJALNA dokumentacja:
http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.custom
Witam.
Mam pytanie dotyczące ścieżek.
Na viewHelper składają się dwa pliki: plik widoku i klasa helpera. Napisałes, że domyślnie klasy helperów są w Zend/View/Helper, a pliki phtml to views/scripts. Później piszesz, że można w zależności od modułu wskazać inna lokalizację plików. Jak rozumiem w dalszym ciągu chodzi i pliki phtml ? Jezeli tak , to jak wskazać aby plik klasy był czytany z np App/View/Helper a nie z Zend/View/Helper ?
@Gaza
To powinno rozwiązać Twój problem (dodaj w pliku application.ini):
resources.view.helperPath.App_View_Helper = APPLICATION_PATH „/../library/App/View/Helper”
Witam,
Mi w modułach działa normalnie bez:
Wywołałem po prostu $this->Images();
A helper w module wygląda tak:
class cms_View_Helper_Images extends Zend_View_Helper_Abstract
{
public function images()
{
echo "Wypluj to z siebie";
}
}
; domyślny moduł
resources.view.helperPath.Zend_View_Helper = APPLICATION_PATH „/views/helpers”
; moduł admina
resources.view.helperPath.Admin_View_Helper = APPLICATION_PATH „/modules/admin/views/helpers”
Bardzo fajny tutorial. Brawo brawo brawo I dziękuję.