Как работать с Zend_Navigation написано в мануале, а вот как быть, если меню строится не из xml файла? Т.е. — динамически из базы?
Начнем подготовку.
основной bootstrap.php
protected function _initNavigation() {
$this->bootstrap('FrontController');
if ($this->_navigation === null) {
$front = $this->getResource('frontController');
$navigation = new Plugin_UserMenu();
$front->registerPlugin($navigation);
$this->_navigation = $navigation;
}
return $this->_navigation;
}
Plugin_UserMenu — наш плагин, который, собственно, и будет генерировать данные для навигации.
plugins/UserMenu.php
<?php
final class Plugin_UserMenu extends Zend_Controller_Plugin_Abstract {
protected $_view;
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$mapper = new Admin_Model_PagesMapper();
$oData = $mapper->fetchAllAsArray();
$data = Default_View_Helper_SelectParentIdCategories::Tree($oData);
$layout = Zend_Layout::getMvcInstance();
$this->_view = $layout->getView();
$container = new Zend_Navigation();
$container->setPages($data);
$this->_view->navigation($container);
}
}
Хитрость в fetchAllAsArray():
public function fetchAllAsArray() {
$where = $this->getDbTable()->select()
->where('lang_id = ?', Zend_Registry::get('uds_lang_id'))
->order('pr ASC');
$resultSet = $this->getDbTable()->fetchAll($where);
$entries = array();
foreach ($resultSet as $row) {
$entry['id'] = $row->id;
$entry['parent_id'] = $row->parent_id;
$entry['title'] = $row->title;
$entry['label'] = $row->title;
$entry['txt'] = $row->txt;
$entry['kw'] = $row->kw;
$entry['pic'] = $row->pic;
$entry['visible'] = $row->visible;
$entry['external_url'] = $row->external_url;
$entry['uri'] = $row->external_url;
$entries[] = $entry;
}
return $entries;
}
$entry['uri'] и $entry['label'] = $row->title используются именно для построения Zend_Navigation. Можно, конечно, при проектировании бд назвать поля таблицы сразу, как хочет zend, но не всегда удобно. По этому так.
Не забываем, что у нас меню использует древовидную структуру по parent_id. Из мануала Zend_Navigation можно посмотреть пример массива, в каком виде нужно его передавать для Zend_Navigation. Собственно, нам осталось лишь подготовить сам массив. На одном форуме, нашел прекрасную функцию, которая сортирует дерево типа parent_id с помощью всего одного запроса и без рекурсии. Эта функция и вызывывается Default_View_Helper_SelectParentIdCategories::Tree($oData);
Default_View_Helper_SelectParentIdCategories::Tree
<?
/* * *************************************************
* Выкидывает селект под парент id
*/
class Default_View_Helper_SelectParentIdCategories {
public function Tree($rows) {
$children = array(); // children of each ID
$ids = array();
$idName = 'id';
$pidName = 'parent_id';
// Collect who are children of whom.
foreach ($rows as $i => $r) {
$row = & $rows[$i];
//$d['label'] = $rows[$i]['title'];
//$row[] = $d;
$id = $row[$idName];
if ($id === null) {
continue;
}
$pid = $row[$pidName];
if ($id == $pid)
$pid = null;
$children[$pid][$id] = & $row;
if (!isset($children[$id]))
$children[$id] = array();
$row['pages'] = & $children[$id];
$ids[$id] = true;
}
// Root elements are elements with non-found PIDs.
$forest = array();
foreach ($rows as $i => $r) {
$row = & $rows[$i];
$id = $row[$idName];
$pid = $row[$pidName];
if ($pid == $id)
$pid = null;
if (!isset($ids[$pid])) {
$forest[$row[$idName]] = & $row;
}
//unset($row[$idName]);
//unset($row[$pidName]);
}
//echo '<pre>';
//print_r($forest);
return $forest;
}
/* * ******************************** */
}
Ну и вывод меню в layout:
<?php print( $this->navigation()->menu()->renderMenu() ); ?>
PS: Кто заметил Zend_Registry::get(‘uds_lang_id’)? Позже будет статья, как сделать мультиязычный сайт с неограниченным количеством языков.



