====== Создание и вывод вложенных навигаций ====== ===== Проблема ===== Во фронтальной части требуется отобразить под-меню, которая состоит из дочерних элементов текущего элемента навигации. Допустим у нас есть навигация, называемая "continents" (путь /root/navigation/continents). В этой навигации мы выводим ссылки на определенные объекты-документы (/root/continents). В навигации "continents" есть дочерние элементы, для каждого континета (/root/navigation/continents/europe, /root/navigation/continents/america), а внутри них элементы для отдельных стран (/root/navigation/continents/europe/germany, /root/navigation/continents/europe/italy). Объекты, которые содержат данные по каждой стране, хранятся совсем в другой папке, нежели /root/continents, например /root/countries. Мы щелкаем на элемент навигации "continents", например europe, и требуется, что бы кроме контента текущей страницы (например, это объект-документ), вывелись бы ссылки на определенные элементы навигации, например, "Spain", "Italy", "Germany" со ссылками на совершенно другие документы. Тема обсуждалась на англоязычной ветке форума: http://limb-project.com/forum/viewtopic.php?t=75 ===== Вариант : таких объектов мало и максимальный уровень вложенности - 2 ===== Все зависит от того, как объекты организованы в дереве сайта и как много уровней навигации требуется отобразить. Допустим, что есть только 2 уровня объектов, таких объектов немного, а объекты навигации имеют те же самые идентификаторы, что и документы или другие объекты, которые навигация представляет. В этом случае мы можем создать специальный datasource, который будет загружать навигационный элемент, относящийся к текущему объекту, а затем дочерние навигационные элементы и возвращать именно их. Код будет выглядеть приблизительно так: class second_level_navigation_datasource extends datasource() { function & get_dataset() { $requested_object_data = fetch_requested_object(); $parent_navigation_item = fetch_one_by_path('/root/navigation/main/' . $requested_object_data['identifier']); if (!$parent_navigation_item) return new empty_dataset(); $counter = 0; $items = fetch_sub_branch($parent_navigation_item['path'], 'navigation_item', $counter); if (!$items) return new empty_dataset(); return new array_dataset($items); } } ===== Вариант: уровней вложенности слишком много ===== Пусть у нас есть ссылка вида /root/continents/europe. И нам необходимо вывести 2-же не одну навигацию, а две: по континентам и по странам европы. В этом случае больше пользы будет от рекурсивной загрузки элементов навигации. Ниже показан пример datasource класса, который грузит элементы навигации рекурсивно, начиная от определенного уровня, указанного в шаблоне, а далее до тех пор пока элементы пути текущего запроса находятся в дочерних элементах навигации (обратите внимание на строчку is_integer($res = $uri->compare_path($nav_uri))). require_once(LIMB_DIR . '/core/datasource/fetch_sub_branch_datasource.class.php'); class special_navigation_datasource extends fetch_sub_branch_datasource { function & _fetch(&$counter, $params) { $result =& parent :: _fetch($counter, $params); $uri = new uri($_SERVER['PHP_SELF']); foreach($result as $key => $data) { $nav_uri = new uri($data['url']); if ($uri->get_host() != $nav_uri->get_host()) continue; if(is_integer($res = $uri->compare_path($nav_uri))) { if($res >= 0) { $result[$key]['in_path'] = true; $params['path'] = $data['path']; $result[$key]['items'] = $this->_fetch(&$counter, $params); } if($res == 0) $result[$key]['selected'] = true; } } return $result; } } Теперь код шаблона: ===== Замечания ===== Проблемой может быть сихронизация идентификаторов элементов навигации и объектов, которые эти элементы навигации представляют. К сожалению, в Limb2 нет встроенных средств для того, чтобы делать это автоматически, поэтому реализацию придется делать руками или просто следовать четкому правилу - элемент навигации должен иметь тот же идентификатор, что и объект, который он представляет.