Pull to refresh

Поговорим о Zend_Navigation

Reading time15 min
Views5.8K
Выход ZF 1.8 порадовал нас несколькими новыми (а главное очень полезными) компонентами. В этой статье я хочу рассказать о практике использования Zend_Navigation для построения меню сайта, карты сайта, хлебных крошек. Особое внимание уделю использованию Zend_Navigation в связке с Zend_Acl.

Это перевод статьи с моего блога. Так как она публикуется на нескольких сайтах, то самой полной версией всегда будет оригинал (на украинском).

Для начала создам каркас проекта используя Zend_Tool.
$ zf create project ./


1. Меню
Для настройки Zend_View добавляю в «application/configs/application.ini» следующий код:
; Views
resources.view.encoding = "UTF-8"
resources.view.basePath = APPLICATION_PATH "/views"
resources.view.helperPath.Application_View_Helper = APPLICATION_PATH "/views/helpers"
 
Дальше в файле «application/Bootstrap.php» создаю новый метод _initNavigation() (просьба читать комментарии в коде):
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
mkdir application/layouts/scripts
touch application/layouts/scripts/default.phtml
Добавляю в шаблон «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) — хелперы сами найдут и не надо в лейоут пихать и указывать при вызове хелпера.
Tags:
Hubs:
+11
Comments57

Articles

Change theme settings