Формирование меню
HTML-код меню обычно регулярный – то есть, состоит из повторяющихся последовательностей «начало блока – ссылка – конец блока». Обрамляющим ссылку блоком могут быть разные элементы, это зависит от дизайна страницы. Для простоты предположим, что главное меню у нас горизонтальное, под шапкой страницы, а меню раздела вертикальное, расположено в боковой колонке. В этом случае разделителем пунктов главного меню будет просто пробельный символ, а для меню раздела – перевод строки.
Не забываем, что вид ссылок в меню будет зависеть от режима ЧПУ (режим у нас задает переменная $urlmode в файле конфигурации). В каждом режиме формирование ссылок будет идти по-разному. Чтобы не плодить массу условных операторов, проще всего сделать по библиотечке формирования меню для каждого режима. А при выполнении центрального скрипта подгружать нужную библиотеку в зависимости от режима. Так и поступим. Файлы библиотек назовем так, чтобы в имени файла содержалось название режима – это нам позволит очень просто определить, какую библиотеку загружать.
Для начала сделаем формирование меню в режиме реальных ссылок, а преобразованием URL займемся позже. В директории /libs размещаем файл m_none.inc.php, содержащий функцию:
<?php function getmenu($var) { global $_pageid; $menu=array(); foreach ($var as $key=>$val) { if (((int)$val['some'] & 1) == 0) { if (((int)$val['some'] & 16) > 0) $href='"'.$val['knot'].'"'; else $href=($val['knot']!='/' ? '"main.php?'.$_pageid.'='.$val['knot'].'"':'"/"'); $menu[]='<a href='.$href.'>'.$val['name'].'</a>'; } } return ($menu); } ?>
Функция получает параметром ($var) массив выбранных для меню разделов и перебирает его в цикле, формируя строку ссылки для каждого раздела. В итоге она возвращает массив сформированных ссылок на разделы. Глобальная переменная $_pageid содержит название GET-параметра – идентификатора раздела. В файле конфигурации прописано значение 'id'.
Две первые строки в цикле foreach проверяют битовую маску статуса раздела. Взведенный 0-й разряд (значение 1) требует не включать раздел в меню. 4-й разряд (значение 16) означает скрипт стороннего разработчика, ссылка на который должна включаться в меню без изменений, как она есть. В этом случае алиасом раздела должна быть ссылка на скрипт вместе с маршрутом от корневой директории сайта (например, /forum/index.php).
В дальнейшем для формирования меню в других режимах нам потребуется написать аналогичные функции с тем же названием для статических ссылок двух видов и поместить их в файлы m_static.inc.php и m_subdir.inc.php. Тогда по наименованию режима из файла конфигурации скрипт может сформировать имя файла, из которого подгрузит нужный вариант функции.
Далее при разработке плагинов (карты сайта и многостраничных списков) нам потребуются дополнительные функции формирования ссылок. Их мы можем точно так же написать в трех вариантах для разных видов URL и поместить в те же библиотечные файлы. Таким образом мы получаем три библиотечки работы со ссылками, содержащие одни и те же функции для разных режимов работы движка.
На днях получил письмо с давно ожидаемым вопросом: как сделать все это для структуры сайта с тремя уровнями вложенности? В этом случае возникают сложности с навигацией, которые все внимательные читатели уже заметили на этом сайте. В разделе второго уровня, если у него есть подразделы-«потомки», приходится в качестве внутреннего меню показывать список этих потомков, а меню второго уровня уже нет, и это лишает навигацию удобства и наглядности.
Признаюсь честно: не стал возиться и сделал все максимально просто (собственно, и задачей себе ставил показать максимально простую конструкцию). Можно с помощью ранее описанных функций для фильтрации getlevel() и getsub() отфильтровать подразделы с тем же предком («братьев» текущего раздела) и подразделы третьего уровня – «потомков» текущего. А потом сформировать меню раздела как вложенный ненумерованный список – аналогично описанной далее карте сайта.
При этом можно не полениться и использовать описанный в статье «Структура данных, часть II» идентификатор ветви. Очень просто построить функцию фильтрации, которая будет выбирать только одну ветвь иерархии – раздел верхнего уровня, его потомков и потомков его потомков – по этому идентификатору. Потом из массива данных по ветви все теми же getlevel() и getsub() выбрать смежные и вложенные разделы для данного. При большом числе разделов на сайте такой подход позволит неплохо сократить затраты ресурсов на фильтрацию.
Но это уже домашнее задание для тех, кто разобрался в работе описанного движка и хочет идти дальше... или глубже, как посмотреть. :-) Этих людей ждет еще одно испытание: при построении карты сайта с глубиной вложения разделов больше двух очень трудно обойтись без рекурсивного обхода дерева разделов. На этом сайте карту строит именно рекурсивная функция, она же давно используется в позднейших двухуровневых версиях движка (три уровня нужны редко). Но можно обойтись и без рекурсии, последовательно выбирая ветви. Не буду говорить о том, лучше это или хуже – скажу только, что нет задачи, которую два разных программиста решили бы совершенно одинаково.