Недавно пришлось писать меню для CMS  (именно для той о которой я писал в пред идущем посте Хитрости PHP: Якорная вставка функций я еще много про эту CMS расскажу). Думаю многие  сталкивались с такой задачей, это не сложный скрипт. Я решил сделать меню, максимально универсально.

Основные требования которые я перед собой поставил при написание меню:

  1. Возможность быстро и удобно менять внешний вид меню (вертикальное, горизонтальное, выпадающее и тп.), с минимальным присутствием программиста.
  2. Возможность выводить в меню, пункты модулей (например модуль “новости”, рубрики новостей должны быть подразделами, хотя сами рубрики хранятся отдельно).


Первый пункт я решил, разделив создание меню на две функции, обе рекурсивный. Первая создает многомерный массив вида:

1
2
3
4
5
6
7
8
9
$menu[]=array(
		'id'=>$m['id'], // идентификатор страницы
		'pid'=>$m['pid'], // идентификатор родительной страницы
		'name'=>$m['name'], // название страницы
		'chpu'=>$chpu.'/'.$m['name_ufl'], //адрес страницы
		'lavel'=>$lavel, // номер папки в ЧПУ которой соответствует пункт в меню
		'select'=>($module[$lavel-1]==$m['name_ufl'] ? 'yes' : 'no'), // идентификатор находится ли пользователь в это разделе/подразделе
		'sub'=>(empty($fun) ? menu_array($m['id'],$lavel+1,$chpu.'/'.$m['name_ufl']) : $fun(0,$lavel+1,$chpu.'/'.$m['name_ufl'])) // здесь находится такой же массив с подразделами, эту конструкцию опишу подробнее
		);

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

Со вторым пунктом было сложнее так как вариантов решений было много. Точнее сам алгоритм подходил один, для решения этой задачи - при вызове очередной рекурсии если страница является модулем, вызвать не саму функцию, а функцию модуля, которая создаст массив подразделов. Очень удобное решение,  можно создавать подразделы как из базы данных, так и просто выводить статичный массив с подразделами. Но в этом случае есть одно - “НО”. Как мы узнаем как программист назвал функцию создающую массив подразделов этого модуля? Можно сказать, что именно из-за этого вопроса и писалась эта статья. :)

И так, что мы имеем - путь к папке модуля и необходимость получения инфомации. Изменение, добавление и удаления информации средствами ПО нам не нужно, по этому запихивать название функции в настройки модуля в MySql я категорически не хотел (если все такие мелочи хранить в БД получится большая таблица с частыми запросам к ней, нам это не надо).

Решил я эту задачу так - ввел стандарт в CMS если модуль вставляет что-либо в меню, то нужно создать в папке с модулем файл menu.php который возвращает название функции пример:

<php
	return "menu_news";
?>

А перед добавлением элемента в массив идет проверка, является ли страница массивом, включена ли поддержка подразделов модулей и существует ли файл menu.php. Если все верно в переменную $fun инклудится название функции для создания подразделов этого модуля, проверяется на то, что такая функция объявлена, если нет то переменной $fun присваивается пустая строка.

		$fun='';
		if(!empty($m['module']) and $setting_menu['include_module']=='yes' and file_exists("./modules/".$m['module']."/menu.php"))
		{
			$fun=include("./modules/".$m['module']."/menu.php");
			if(!function_exists($fun))
				$fun='';
		}

Дальше идет код по созданию массива, в элемент с ключом ’sub’ добавляется результат следующей рекурсии или функции модуля в зависимости от того пуста переменная $fun или нет.

8
		'sub'=>(empty($fun) ? menu_array($m['id'],$lavel+1,$chpu.'/'.$m['name_ufl']) : $fun(0,$lavel+1,$chpu.'/'.$m['name_ufl']))

В заключение могу сказать, описанный метод хорош только если данные не нужно изменять, а всего лишь приравнять к неопределенной переменной….
P.S. В следующем посте я расскажу как меня пытались кинуть, и что нужно делать в таких случаях.