RSS

Обсуждаемые вопросы: Zend Framework,
информационная безопасность, CMF, CSS + HTML,
AJAX, PHP, веб-программирование и многое другое.

 
 
Анатолий Скорняков
2009—2012
Контактная информация
Живу в Белгороде
Сделано у Беликова
Алексей Беликов
 
 

Поговорим о Zend_Navigation

10 декабря 2009 г, 11:45

zend frameworkВыход ZF 1.8 порадовал нас несколькими новыми (а главное очень полезными) компонентами. В этой статье я хочу рассказать о практике использования Zend_Navigation для построения меню сайта, карты сайта, хлебных крошек. Особое внимание уделю использованию Zend_Navigation в связке с Zend_Acl.
Автор: Степан Танасийчук aka stfalcon

Для начала создам каркас проекта используя 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() (просьба читать комментарии в коде):

<?php

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>

; Layout
resources.layout.layout     = "default"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

И запускаю:

zend_navigation меню

Вуаля :). Видим готовою, расхлопнутую менюшку! Активный пункт помечен как.

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>

Смотрю, что вышло:

zend_navigation меню

Прикольно :)? Метод 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_Navigator
        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_Navigation очень удобный и гибкий компонент. Ещё я забыл сказать, что стандартные вью хелперы поддерживают Zend_Translate, что очень удобно при создании мультиязычных сайтов. Кажется все. Надеюсь эта статья вам пригодится.

UPD. Тут Александр Махомет подсказывает, что вот так делать

$view->menu = $container;

не очень удобно, потому что можно случайно затереть эту переменную в контроллере. Если на сайте только одно меню, тогда можно делать проще:

$view->navigation($container);

И выводить его таким образом:

<?php echo $this->navigation()->menu(); ?>
<?php echo $this->navigation()->breadcrumbs(); ?>

Комментарии

Оставить комментарий