Выход ZF 1.8 порадовал нас несколькими новыми (а главное очень полезными) компонентами. В этой статье я хочу рассказать о практике использования Zend_Navigation для построения меню сайта, карты сайта, хлебных крошек. Особое внимание уделю использованию Zend_Navigation в связке с Zend_Acl.
Это перевод статьи с моего блога. Так как она публикуется на нескольких сайтах, то самой полной версией всегда будет оригинал (на украинском).
Для начала создам каркас проекта используя Zend_Tool.
1. Меню
Для настройки Zend_View добавляю в «application/configs/application.ini» следующий код:
Если следовать здоровой логике, то меню должно присутствовать на всех страницах сайта (или большинстве). Для этого идеально подходит Zend_Layout.
А в «application/configs/application.ini» выношу настройки для ресурса layout, который инициализирует Zend_Layout:
И запускаю (оригинал статьи я писал на украинском и скриншоты переделывать чесно говоря лень :)):

Вуаля :). Видим готовою, расхлопнутую менюшку! Активный пункт помечен как class=«active».
2. Хлебные крошки
Ок, менюшка готова. Теперь я хочу, чтобы при пользовании сайтом пользователь всегда видел свое текущее месторасположение. Для этого можно использовать «хлебные крошки».
Чтобы приложение не ругалось на отсутсвие нужного контроллера или вьюшек я с помощью Zend_Tool создам контроллер Users добавлю к нему необходимые экшены. Все очень просто:
Ну и добавлю немного нового кода в шаблон layout'a (между меню и контентом):
Смотрю, что вышло:

Прикольно :)?
Метод setLinkLast(true) означает, что последнюю крошку нужно отображать как ссылку. Также можна указывать разделитель и минимальную глубину — смотрите API
3. Sitemap
С сайтмапом все так же просто. Все делается по аналогии. Вот мануал, а вот минимальный код:
4. Zend_Navigation && Zend_Acl
А теперь я расскажу о том, что мне больше всего понравилось в Zend_Navigation — возможность использовать его в связке с Zend_Acl.
Добавляю в Bootstrap роли и привилегии для доступа к страницам, а также инициализацию Zend_Acl (читайте комментарии к коду!):
Запускаю:

Ну и вижу меню для гостей. А хлебных крошек нету потому что, нужно задать минимальную глубину равной нулю.
Итоги
Вобще Zend_Navigation очень удобный и гибкий компонент. Ещё я забыл сказать, что стандартные вью хелперы поддерживают Zend_Translate, что очень удобно при создании мультиязычных сайтов.
Кажется все. Надеюсь эта статья вам пригодится. И заходите к нам на форум zendframework.ru (а также на самом сайте много полезного и интересно).
UPD. Тут (точнее уже там :)) san подсказывает, что вот так делать
Если на сайте только одно меню, тогда можно делать проще:
И выводить его в вьюшках таким образом:
UPD2.
Хабрапользователь jarool сделал дельное замечание:
Это перевод статьи с моего блога. Так как она публикуется на нескольких сайтах, то самой полной версией всегда будет оригинал (на украинском).
Для начала создам каркас проекта используя Zend_Tool.
$ zf create project ./
1. Меню
Для настройки Zend_View добавляю в «application/configs/application.ini» следующий код:
; ViewsДальше в файле «application/Bootstrap.php» создаю новый метод _initNavigation() (просьба читать комментарии в коде):
resources.view.encoding = "UTF-8"
resources.view.basePath = APPLICATION_PATH "/views"
resources.view.helperPath.Application_View_Helper = APPLICATION_PATH "/views/helpers"
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
/*
* Инициализируем объект навигатора и передаем его в View
*
* @return Zend_Navigation
*/
public function _initNavigation()
{
// Бутстрапим View
$this->bootstrapView();
$view = $this->getResource('view');
// Структура простого меню (можно вынести в XML)
$pages = array(
array(
'controller' => 'index',
'label' => _('Главная страница'),
),
array(
'controller' => 'users',
'action' => 'index',
// Я обворачиваю текст в _(), чтобы потом вытянуть его парсером gettext'а
'label' => _('Пользователи'),
'pages' => array (
array (
'controller' => 'users',
'action' => 'new',
'label' => _('Добавить пользователя'),
),
)
),
array (
'controller' => 'users',
'action' => 'registration',
'label' => _('Регистрация'),
),
array (
'controller' => 'users',
'action' => 'login',
'label' => _('Авторизация'),
),
array (
'controller' => 'users',
'action' => 'logout',
'label' => _('Выход'),
)
);
// Создаем новый контейнер на основе нашей структуры
$container = new Zend_Navigation($pages);
// Передаем контейнер в View
$view->menu = $container;
return $container;
}
}
Если следовать здоровой логике, то меню должно присутствовать на всех страницах сайта (или большинстве). Для этого идеально подходит Zend_Layout.
$ mkdir application/layoutsДобавляю в шаблон «application/layouts/scripts/default.phtml» вывод меню и контента страницы:
$ mkdir application/layouts/scripts
$ touch application/layouts/scripts/default.phtml
<div id="menu">
<h3>
<?php echo $this->translate('Меню'); ?>:
</h3>
<?php echo $this->navigation()->menu($this->menu); ?>
</div>
<div id="content">
<?php echo $this->layout()->content; ?>
</div>
А в «application/configs/application.ini» выношу настройки для ресурса layout, который инициализирует Zend_Layout:
; Layout
resources.layout.layout = "default"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
И запускаю (оригинал статьи я писал на украинском и скриншоты переделывать чесно говоря лень :)):

Вуаля :). Видим готовою, расхлопнутую менюшку! Активный пункт помечен как class=«active».
2. Хлебные крошки
Ок, менюшка готова. Теперь я хочу, чтобы при пользовании сайтом пользователь всегда видел свое текущее месторасположение. Для этого можно использовать «хлебные крошки».
Чтобы приложение не ругалось на отсутсвие нужного контроллера или вьюшек я с помощью Zend_Tool создам контроллер Users добавлю к нему необходимые экшены. Все очень просто:
$ zf create controller users
$ zf create action new --controller-name users
$ zf create action registration --controller-name users
$ zf create action login --controller-name users
$ zf create action logout --controller-name users
Ну и добавлю немного нового кода в шаблон layout'a (между меню и контентом):
<div id="breadcrumbs">
<h3>
<?php echo $this->translate('Хлебные крошки'); ?>:
</h3>
<?php echo $this->navigation()->breadcrumbs($this->menu)->setLinkLast(true); ?>
</div>
Смотрю, что вышло:

Прикольно :)?
Метод setLinkLast(true) означает, что последнюю крошку нужно отображать как ссылку. Также можна указывать разделитель и минимальную глубину — смотрите API
3. Sitemap
С сайтмапом все так же просто. Все делается по аналогии. Вот мануал, а вот минимальный код:
<?php echo $this->navigation()->sitemap($this->menu); ?>
4. Zend_Navigation && Zend_Acl
А теперь я расскажу о том, что мне больше всего понравилось в Zend_Navigation — возможность использовать его в связке с Zend_Acl.
Добавляю в Bootstrap роли и привилегии для доступа к страницам, а также инициализацию Zend_Acl (читайте комментарии к коду!):
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
/**
* Инициализируем ACL.
* Создаем роли и ресурсы. Раздаем права доступа
*
* @return Zend_Acl
*/
protected function _initAcl()
{
$auth = Zend_Auth::getInstance();
// Определяем роль пользователя.
// Если не авторизирован - значит "гость"
$role = ($auth->hasIdentity() && !empty($auth->getIdentity()->role))
? $auth->getIdentity()->role : 'guest';
$acl = new Zend_Acl();
// Создаем роли
$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'), 'guest')
->addRole(new Zend_Acl_Role('administrator'), 'member');
// Создаем ресурсы
// Я использую префиксы для наименования ресурсов
// "mvc:" - для страниц
$acl->add(new Zend_Acl_Resource('mvc:index'))
->add(new Zend_Acl_Resource('mvc:error'))
->add(new Zend_Acl_Resource('mvc:users'));
// Пускаем гостей на "морду" и на страницу ошибок
$acl->allow('guest', array('mvc:error', 'mvc:index'));
// А также на страницы авторизации и регистрации
$acl->allow('guest', 'mvc:users', array('login', 'registration'));
// А мемберам уже облом :)
$acl->deny('member', 'mvc:users', array('login', 'registration'));
// Ну и т.д.
$acl->allow('member', 'mvc:users', array('index', 'logout'));
$acl->allow('administrator', 'mvc:users', array('new'));
// Цепляем ACL к Zend_Navigation
Zend_View_Helper_Navigation_HelperAbstract::setDefaultAcl($acl);
Zend_View_Helper_Navigation_HelperAbstract::setDefaultRole($role);
return $acl;
}
/*
* Инициализируем объект навигатора и передаем его в View
*
* @return Zend_Navigation
*/
public function _initNavigation()
{
$this->bootstrapView();
$view = $this->getResource('view');
$pages = array(
array(
'controller' => 'index',
'label' => _('Главная страница'),
),
array(
'controller' => 'users',
'action' => 'index',
// Ресурс для проверки прав доступа
'resource' => 'mvc:users',
// И привилегия
'privilege' => 'index',
'label' => _('Пользователи'),
'pages' => array (
array (
'controller' => 'users',
'action' => 'new',
'resource' => 'mvc:users',
'privilege' => 'new',
'label' => _('Добавить пользователя'),
),
)
),
array (
'controller' => 'users',
'action' => 'registration',
'resource' => 'mvc:users',
'privilege' => 'registration',
'label' => _('Регистрация'),
),
array (
'controller' => 'users',
'action' => 'login',
'resource' => 'mvc:users',
'privilege' => 'login',
'label' => _('Авторизация'),
),
array (
'controller' => 'users',
'action' => 'logout',
'resource' => 'mvc:users',
'privilege' => 'logout',
'label' => _('Выход'),
)
);
$container = new Zend_Navigation($pages);
$view->menu = $container;
return $container;
}
}
?>
Запускаю:

Ну и вижу меню для гостей. А хлебных крошек нету потому что, нужно задать минимальную глубину равной нулю.
Итоги
Вобще Zend_Navigation очень удобный и гибкий компонент. Ещё я забыл сказать, что стандартные вью хелперы поддерживают Zend_Translate, что очень удобно при создании мультиязычных сайтов.
Кажется все. Надеюсь эта статья вам пригодится. И заходите к нам на форум zendframework.ru (а также на самом сайте много полезного и интересно).
UPD. Тут (точнее уже там :)) san подсказывает, что вот так делать
$view->menu = $container;не очень удобно, потому что можно случайно затереть эту переменную в контроллере.
Если на сайте только одно меню, тогда можно делать проще:
$view->navigation($container);
И выводить его в вьюшках таким образом:
<?php echo $this->navigation()->menu(); ?>
<?php echo $this->navigation()->breadcrumbs(); ?>
UPD2.
Хабрапользователь jarool сделал дельное замечание:
Для большинства приложений строится один объект навигации и один ACL список. Поэтому можно менюшку положить в Zend_Registry::set('Zend_Navigation', $AppNavigation) — хелперы сами найдут и не надо в лейоут пихать и указывать при вызове хелпера.