W życiu każdego programisty nadchodzi chwila, od której staje się leniwy (czytaj: mądrzejszy) i zaczyna korzystać z gotowych, wydajniejszych rozwiązań w postaci frameworków. Do tej pory programista tworzył w pocie czoła swoje „klocki”, z których mógł sobie składać aplikacje. W literaturze zwie się takie coś „reinventing the wheel”, czyli po naszemu tracenie czasu na klepanie kodu, który ktoś napisał za nas. Śpiechu niniejszym przechodzi na następny level i zaczyna poznawać Zend Framework.
Nie ma niestety dobrej literatury w języku polskim do Zenda. Przy okazji czekania na pociąg zahaczyłem o Empik i kupiłem sobie PHP5. Programowanie z wykorzystaniem Symfony, CakePHP, Zend Framework Tomasz Skaraczyńskiego i Andrzeja Zoła. 2/3 książki zajmuje niestety opis Symfony. Myślę jednak, że te kilkadziesiąt stron na start z Zendem wystarczy. Potem wgryzamy się w dokumentację na stronie producenta.
W skrócie: Zend Framework stosuje wzorzec projektowy Model-Widok-Kontroler (MVC). Na świat wystawiony mamy jedynie plik index.php. Router rozpracowuje żądanie wyświetlenia strony i kieruje do odpowiedniego kontrolera i jego akcji. Jeden kontroler może mieć wiele akcji, z których każda może robić co innego. Dla każdego kontrolera przypisany jest osobny katalog z widokami, z których generowana jest ostateczna strona. Kontroler w razie potrzeby odpala również jakieś zapytania do bazy danych (model) i przekazuje wyniki do widoku.
Chcemy uzyskać taki efekt, że po kliknięciu konkretnego elementu menu ten nam się podświetli. I to tak żeby cała operacja odbywała się bez ingerencji programisty piszącego kolejne akcje. Samego startu z Zendem nie będę omawiał. Zapytajcie wujka Google o Zend_Layout i o rozszerzanie Zend_Controller_Plugin_Abstract.
Pierwsze czego potrzebujemy to plik layout.phtml w application/layouts/scripts. Jest super prosty i zawiera 2 placeholdery — 1 na menu i 1 na treść z akcji.
<html><head></head>
<body>
<div id="menu">
<?php echo $this->layout()->menu; ?>
</div>
<div id="content">
<?php echo $this->layout()->content; ?>
</div>
</body>
</html>Następnie potrzebujemy kontrolera, który będzie zajmował się tylko wyświetlaniem menu. Tworzymy plik MenuController.php w application/controllers.
class MenuController extends Zend_Controller_Action { public function init() { $this->_helper->viewRenderer->setResponseSegment('menu'); } public function showmenuAction() { $menuItems = array( array('tytul' => 'pierwszy link', 'kontroler' => 'index', 'akcja' => 'pierwszy'), array('tytul' => 'drugi link', 'kontroler' => 'index', 'akcja' => 'drugi'), array('tytul' => 'trzeci link', 'kontroler' => 'index', 'akcja' => 'trzeci') ); $this->view->assign('menu', $menuItems); $front = Zend_Controller_Front::getInstance(); $this->view->assign('highlight_action', $front->getPlugin('Spiechu_Menu_Plugin_Menu')->getActionName()); $this->view->assign('highlight_controller', $front->getPlugin('Spiechu_Menu_Plugin_Menu')->getControllerName()); } }
Powyższy kod ustawia placeholder na menu (content jest domyślny), następnie przekazuje zmienne potrzebne do wyświetlenia widoku.
Teraz trzeba by jakoś wyświetlić te elementy menu. Tworzymy plik widoku odpowiadający nazwie akcji. W naszym przypadku jest to showmenu.phtml w views/scripts/menu.
<ul> <?php foreach ($this->menu as $menuItem): ?> <?php if ($this->highlight_action == $menuItem['akcja'] && $this->highlight_controller == $menuItem['kontroler']): ?> <li><a style="background-color:green;" "href="<?php echo $this->url(array('controller' => $menuItem['kontroler'] , 'action' => $menuItem['akcja'])); ?>"><?php echo $menuItem['tytul'] ?></a></li> <?php else: ?> <li><a href="<?php echo $this->url(array('controller' => $menuItem['kontroler'] , 'action' => $menuItem['akcja'])); ?>"><?php echo $menuItem['tytul'] ?></a></li> <?php endif; ?> <?php endforeach; ?> </ul>
Powyższa hybryda php i html iteruje nam po wszystkich elementach tablicy $this->menu. Jeżeli aktualnie iterowany element odpowiada temu do podświetlenia to wklejamy mu styl background-color podświetlający na zielono. Warty uwagi jest również helper widoku $this->url(), który montuje nam prawidłowy adres do danego elementu menu.
Zapewne zwróciliście uwagę na takie dziwne coś jak Spiechu_Menu_Plugin_Menu. Jest to mój plugin podczepiający się do kontrolera frontowego i pobierającego z niego dane na temat żądanego kontrolera i akcji. A czemu taka dziwna nazwa? Zend rozpracowuje sobie gdzie ma szukać danej klasy w strukturze katalogów za pomocą nazw poprzedzielanych podkreślnikiem.
Tworzymy kod pluginu w library/Spiechu/Menu/Plugin/Menu.php
class Spiechu_Menu_Plugin_Menu extends Zend_Controller_Plugin_Abstract { protected $_actionName; protected $_controllerName; public function routeShutdown(Zend_Controller_Request_Abstract $request) { $this->_actionName = $request->getActionName(); $this->_controllerName = $request->getControllerName(); $menu = clone $request; $menu->setControllerName('menu')->setActionName('showmenu'); $frontController = Zend_Controller_Front::getInstance(); if (!$frontController->hasPlugin('Zend_Controller_Plugin_ActionStack')) $frontController->registerPlugin(new Zend_Controller_Plugin_ActionStack()); $actionStack = $frontController->getPlugin('Zend_Controller_Plugin_ActionStack'); $actionStack->pushStack($menu); } public function getActionName() { return $this->_actionName; } public function getControllerName() { return $this->_controllerName; } }
Macie tutaj sporo niezrozumiałego kodu. Dla każdego pluginu po zakończeniu procesu routingu, a przed rozpoczęciem pętli wykonywania akcji odpalana jest m.in. metoda routeShutdown(). Używamy jej do zapisu danych nt. żądanego kontrolera i akcji, a następnie wrzucamy na stos (Zend_Controller_Plugin_ActionStack) dodatkową akcję do wykonania, która wyświetli nam menu. Jest tutaj użyty numer z klonowaniem, który gdzieś znalazłem na forum. Potrzebujemy jakiegoś żądania, które można przeflancować na wyświetlenie menu. Ponadto nie możemy popsuć tego właściwego, więc używamy klonowania.
Ostatnie czego potrzebujemy to zarejestrować plugin, gdyż Zend nie wie czy chcemy go używać czy nie. Najlepiej to zrobić w pliku application/bootstrap.php. U mnie wygląda to tak:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { public function __construct($application) { parent::__construct($application); Zend_Loader_Autoloader::getInstance()->registerNamespace('Spiechu_'); $frontController = Zend_Controller_Front::getInstance(); $frontController->registerPlugin(new Spiechu_Menu_Plugin_Menu()); } }
Najpierw rejestrujemy nową ścieżkę, a następnie rejestrujemy plugin. Jak zapewne zauważyliście, Zend_Loader_Autoloader jak i Zend_Controller_Front to singletony. Mamy przez to pewność, że gdy w kontrolerze chcemy wyciągnąć dane z naszego pluginu, to jest to ta sama instancja.
Na razie wszystko to jest dla mnie dosyć nowe. Sam nie do końca czuję czemu to nie wyrzuca jakiegoś błędu. :-)
Myślę, że ten wpis to dopiero początek pisania o Zendzie.
PS.: Nie zapomnijcie sobie stworzyć akcji pierwszyAction(), drugiAction(), trzeciAction() w kontrolerze IndexController (może wyświetlać tylko 1, 2, 3 — ważne, żeby można było poznać czy rzeczywiście podświetla nam ten element, który wybraliśmy).
Podobne wpisy:

O autorze
One comment
Dzięki wielkie, bardzo się przydało ! :)