Как стать автором
Обновить

Древовидная навигация с помощью Zend Framework

Время на прочтение3 мин
Количество просмотров716
У больших проектов есть большая проблема — рано или поздно его содержимое превращается в хаос (в большей части это относится к бэкэнду, ибо на фронте обычно все в порядке). С ростом проекта усложняется его иерархическая структура, что затрудняет контроль или работу, поэтому стоит воспользоваться вполне очевидной вещью — вывод навигации в виде дерева. Довольно удобно, когда все содержимое вашего проекта отображается в иерархическом виде, вы так не думаете?

Задача


Реализовать навигацию по дереву. Вложенность дерева неограничена.

База данных



Таблица MySQL

CREATE TABLE IF NOT EXISTS `navigation` (
`nav_id` smallint(5) unsigned NOT NULL auto_increment,
`nav_parent` smallint(5) unsigned NOT NULL default '1',
`nav_title` varchar(200) NOT NULL,
PRIMARY KEY (`nav_id`),
KEY `nav_parent` (`nav_parent`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `navigation`
ADD CONSTRAINT `navigation_ibfk_1` FOREIGN KEY (`nav_parent`) REFERENCES `navigation` (`nav_id`) ON DELETE CASCADE ON UPDATE CASCADE;


Как многие из вас уже догадались данная таблица имеет рекурсивный внешний ключ. Таблица контента привязывается к таблице навигации по внешнему ключу, но ее мы рассматривать не будем, т.к. это вещь вполне очевидная.

Реализация



В большинстве случаев можно эскейпить html в коде php и выводить его в нужный момент. Это приемлимо, если наш node имеет вид:

html:
<li>
<a href="#">Pangram</a>
</li>


php + html:
<?php
$node = "<li><a href=\"#\">Pangram</a></li>"
?>

Все хорошо, но что если нам потребуется ввести дополнительный код?

html:
<li class="menulayer" id="navigation_item_46">
<a href="#" onclick="myFunction(); return false;">Pangram</a>
</li>


php + html:
<?php
$node = "<li class=\"menulayer\" id=\"navigation_item_46\"><a href=\"#\" onclick=\"myFunction(); return false;\">Pangram</a></li>"
?>

А еще что-нибудь добавить? Думаю, что ваш верстальщик будет долго материться недоволен, т.к. мало кому захочется ковыряться в php коде, тем более не своем.

Но решение существует. Нужно использовать хэлпер.

Класс хелпера

<?php
class MY_View_Helper_NavigationTree{
private $tree;
public $view;

public function setView(Zend_View_Interface $view){
$this->view = $view;
}

public function scriptPath($script){
return $this->view->getScriptPath($script);
}

/**
* @access public
* @param array собственно, само дерево
* @param integer айди узла, содержащего поддерево
* @param array аргументы
* @return mixed
*/
public function navigationTree($tree, $id, array $args){
$this->tree = $tree;
return $this->getTree($id, $args);
}

/**
* @access private
* @param integer айди узла, содержащего поддерево
* @param array аргументы для вида
* @return mixed
*/

private function getTree($id, array $args){
$nodes = array();
foreach ($this->tree as $node){
if($node['nav_id'] != 1){
if($node['nav_parent'] == $id){
$nodes[] = $node;
}
}
}

return $this->view->partial('navigation/_partial/item.phtml', array(
'nodes' => $nodes,
'tree' => $this->tree,
'baseUrl' => $args['baseUrl']
));
}
}
?>


Контроллер

public function indexAction(){
$menu = new navigation();
$this->view->tree = $menu->fetchAll();
}



Для соответствующего экшена реализуем вид и вызовем наш хэлпер.

Вызов «корня»

<?= $this->navigationTree($this->tree, 1, array('baseUrl' => $this->baseUrl))?>


Вложенный вид

<? foreach($this->nodes as $item) : ?>
<li class="menulayer" id="navigation_item_<?= $item['nav_id'] ?>">
<a href="#" onlclick="myFunction(); return false;">
<?= $this->escape($item['nav_title']) ?>
</a>
<ul id="treeitem_<? echo $item['nav_id']?>">

<?= $this->navigationTree($this->tree, $item['nav_id'], array('baseUrl' => $this->baseUrl)) ?>
</ul>
</li>
<? endforeach ?>


В итоге, мы можем без проблемм модифицировать наш html код.
У меня получилось примерно следующее:
image

P.S. отдельное спасибо хабраюзеру onthefly за подготовку материала.
Теги:
Хабы:
+7
Комментарии8

Публикации

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн