Я разрабатываю систему управления контентом, и у меня возникла проблема с дочерними родительскими отношениями элементов в CMS.
В основном у меня есть система, которая может создавать страницы, и когда страница создается, вы можете выбрать родительскую страницу для поднавигации. Это все нормально и денди, пока я не попытаюсь создать навигацию из БД.
Я не уверен, что какое-то соединение будет лучше, но я предпочитаю получать все данные в массиве и манипулировать массивом с помощью php.
Мой массив результатов из БД выглядит так:
Array ( [0] => Array ( [id] => 27 [name] => home [link] => home.html [parent] => 0 ) [1] => Array ( [id] => 30 [name] => about [link] => about.html [parent] => 27 ) )
Мне нужно пройти через массив, подобный этому, который может иметь любое количество навигации и разумно сортировать его в своих родительских дочерних отношениях. Я смог это сделать, но только на одном уровне. Он должен управлять детьми с детьми с детьми и т. Д. С бесконечным количеством слоев и выводить его на неупорядоченные вложенные списки HTML.
<ul> <li> <a>Nav</a> <ul> <li> <a>Subnav</a> <ul> <li> <a>Sub Sub nav</a> </li> </ul> </li> </ul> <li> <ul>
И т.д. …
Я не думаю, что вы должны попасть в объекты. Плюс я думаю, что это просто дополнительная работа для создания объектов и т. Д. По-моему, вы должны прокручивать массив и генерировать многомерный массив, представляющий навигационную иерархию, а затем циклически сгенерировать результирующий массив для генерации вашего HTML. Я сделал образец кода для вас, он работает так, как вы хотите, но вы, вероятно, захотите внести некоторые изменения.
функции
// Generate your multidimensional array from the linear array function GenerateNavArray($arr, $parent = 0) { $pages = Array(); foreach($arr as $page) { if($page['parent'] == $parent) { $page['sub'] = isset($page['sub']) ? $page['sub'] : GenerateNavArray($arr, $page['id']); $pages[] = $page; } } return $pages; } // loop the multidimensional array recursively to generate the HTML function GenerateNavHTML($nav) { $html = ''; foreach($nav as $page) { $html .= '<ul><li>'; $html .= '<a href="' . $page['link'] . '">' . $page['name'] . '</a>'; $html .= GenerateNavHTML($page['sub']); $html .= '</li></ul>'; } return $html; }
** использование образца **
$nav = Array ( Array ( 'id' => 27, 'name' => 'home', 'link' => 'home.html', 'parent' => 0 ), Array ( 'id' => 30, 'name' => 'about', 'link' => 'about.html', 'parent' => 27 ) ); $navarray = GenerateNavArray($nav); echo GenerateNavHTML($navarray);
Вероятно, вы можете сделать обе вещи за один шаг, но я думаю, что сначала создать многомерный массив. Удачи!
Решение Saad Imran работает хорошо, за исключением того, что вы хотите, чтобы в одном списке было несколько элементов навигации. Мне пришлось изменить несколько строк, чтобы заставить его создать проверенный список элементов. Я также добавил отступы, чтобы сделать сгенерированный код более удобочитаемым. Я использую пробелы, но это можно легко изменить на вкладки, если вы предпочитаете, просто замените 4 пробела на "\t"
. (обратите внимание, что вы должны использовать двойные кавычки, а не одинарные кавычки, иначе php не заменяет символ табуляции, а фактически a \ t)
Я использую это в codeigniter 2.1.0 с суперфишей (PHP5)
function GenerateNavHTML($nav, $tabs = "") { $tab=" "; $html = "\n$tabs<ul class=\"sf-menu\">\n"; foreach($nav as $page) { //check if page is currently being viewed if($page['link'] == uri_string()) { $html .= "$tabs$tab<li class=\"current\">"; } else { $html .= "$tabs$tab<li>"; } $html .= "<a href=\"$page[link]\">$page[name]</a>"; //Don't generate empty lists if(isset($page['sub'][0])) { $html .= $this->GenerateNavHTML($page['sub'], $tabs.$tab); } $html .= "</li>\n"; } $html .= $tabs."</ul>\n"; return $html; }
Я получал (переключился на ol для разъяснения)
1. Home 1. About Us 1. Products 1. sub-product 1 1. sub-product 2 1. Contact
теперь я получаю
1. Home 2. About Us 3. Products 1. sub-product 1 2. sub-product 2 4. Contact
Красиво сгенерированный HTML
<ul class="sf-menu"> <li class="current"><a href="index.html">Home</a></li> <li><a href="about.html">About Us</a></li> <li><a href="products.html">Products</a> <ul class="sf-menu"> <li><a href="products-sub1.html">sub-product 1</a></li> <li><a href="products-sub2.html">sub-product 2</a></li> </ul> </li> <li><a href="contact.html">Contact</a></li> </ul>
Самый простой способ сделать это, вероятно, будет использовать объекты. Их можно легко манипулировать, а также легко создавать из массива, который вы получаете из базы данных.
Например, каждый объект имеет:
Вам понадобится статическая функция, которая сможет узнать, какой объект имеет определенный идентификатор базы данных. Это делается во время создания нового объекта, помещая ссылку в статический список. Затем этот список можно вызвать и проверить во время выполнения.
Остальное довольно просто:
$arr = get_array_from_database(); foreach($arr as $node){ $parent_object = get_parent_object($node_id); $parent_object.subnodes[] = new NodeObject($node); }
Что касается возврата объектов в список, это лучше всего сделать рекурсивно;
function return_in_list($objects) { foreach($objects as $node) { echo '<li>'; echo '<a>' + node.link + '</a>'; if(node.subnodes.length > 0) { echo '<ul>'; return_in_list($node.subnodes); echo '</ul>'; } puts '</li>' } }
Я работаю над одним и тем же проектом, и я не нашел нужным использовать объекты. База данных в значительной степени заботится о структуре, а функции php могут сделать все остальное. Мое решение было иметь родительское поле для страниц, которое указывает на имя раздела, как и у вас, но также добавить родительское поле для таблицы разделов, чтобы разделы могли указывать на другие разделы в качестве родителей. Он по-прежнему очень управляем, потому что есть только два родительских поля, которые нужно отслеживать, по одному для каждой таблицы, и я могу вложить в свою структуру столько уровней, сколько необходимо в будущем.
Поэтому для динамического создания дерева я собираюсь рекурсивно проверять родителей, пока не нажму нуль, что указывает на то, что текущий элемент находится на корне doc. Таким образом, нам не нужно знать какие-либо детали текущей структуры страницы в коде функции, и мы можем сосредоточиться только на добавлении и упорядочении страниц в mysql. Поскольку на другом плакате появилось меню html, я подумал, что добавлю здесь пример для динамического маршрута, потому что темы настолько похожи.
ДАННЫЕ
// Sample 3 x 2 page array (php / html pages) // D1 key = page name // D2 element 1 = page name for menu display // D2 element 2 = parent name (section) $pages = Array ( 'sample-page-1.php' => Array ( 'M' => 'page 1', 'P' => null ), 'sample-page-2.php' => Array ( 'M' => 'page 2', 'P' => 'hello' ), 'sample-page-3.php' => Array ( 'M' => 'page 3', 'P' => 'world' ) ); // Sample 2 x 1 section array (parent directories) // D1 key = section name // D2 element = parent name (if null, assume root) $sections = Array ( 'hello' => null, 'world' => 'hello' ); $sep = ' > '; // Path seperator $site = 'test.com'; // Home string
ФУНКЦИИ
// Echo paragraph to browser function html_pp ( $text ) { echo PHP_EOL . '<p>' . sprintf ( $text ) . '</p>' . PHP_EOL; } // Get breadcrumb for given page function breadcrumb ( $page ) { // Reference variables in parent scope global $pages; global $sections; global $sep; global $site; // Get page data from array $menu = $pages [ $page ] [ 'M' ]; $parent = $pages [ $page ] [ 'P' ]; if ( $parent == null ) { $path = $site . $sep . $menu; } else { $path = $site . $sep . get_path ( $parent ) . $sep . $menu; } return $path; } // Trace ancestry back to root function get_path ( $parent ) { // Reference variables in parent scope global $sections; global $sep; if ( $sections [ $parent ] == null ) { // No more parents return $parent; } else { // Get next parent through recursive call return get_path ( $sections [ $parent ] ) . $sep . $parent; } }
ПРИМЕНЕНИЕ
// Get breadcrumbs by page name $p1 = 'sample-page-1.php'; $p2 = 'sample-page-2.php'; $p3 = 'sample-page-3.php'; html_pp ( $p1 . ' || ' . breadcrumb ( $p1 ) ); html_pp ( $p2 . ' || ' . breadcrumb ( $p2 ) ); html_pp ( $p3 . ' || ' . breadcrumb ( $p3 ) ); // or use foreach to list all pages foreach ( $pages as $page => $data) { html_pp ( $page . ' || ' . breadcrumb ( $page ) ); }
ВЫВОД
sample-page-1.php || test.com> стр. 1
sample-page-2.php || test.com> hello> стр. 2
sample-page-3.php || test.com> hello> мир> страница 3