У больших проектов есть большая проблема — рано или поздно его содержимое превращается в хаос (в большей части это относится к бэкэнду, ибо на фронте обычно все в порядке). С ростом проекта усложняется его иерархическая структура, что затрудняет контроль или работу, поэтому стоит воспользоваться вполне очевидной вещью — вывод навигации в виде дерева. Довольно удобно, когда все содержимое вашего проекта отображается в иерархическом виде, вы так не думаете?
Реализовать навигацию по дереву. Вложенность дерева неограничена.
Как многие из вас уже догадались данная таблица имеет рекурсивный внешний ключ. Таблица контента привязывается к таблице навигации по внешнему ключу, но ее мы рассматривать не будем, т.к. это вещь вполне очевидная.
В большинстве случаев можно эскейпить html в коде php и выводить его в нужный момент. Это приемлимо, если наш node имеет вид:
html:
php + html:
Все хорошо, но что если нам потребуется ввести дополнительный код?
html:
php + html:
А еще что-нибудь добавить? Думаю, что ваш верстальщик будетдолго материться недоволен, т.к. мало кому захочется ковыряться в php коде, тем более не своем.
Но решение существует. Нужно использовать хэлпер.
Для соответствующего экшена реализуем вид и вызовем наш хэлпер.
В итоге, мы можем без проблемм модифицировать наш html код.
У меня получилось примерно следующее:
P.S. отдельное спасибо хабраюзеру onthefly за подготовку материала.
Задача
Реализовать навигацию по дереву. Вложенность дерева неограничена.
База данных
Таблица 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
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 код.
У меня получилось примерно следующее:
P.S. отдельное спасибо хабраюзеру onthefly за подготовку материала.