Дерево - очень удобная модель представления данных. Ее можно встретить повсюду в интерфейсах программ и сайтов. Файловая система, системный реестр Windows, меню в программах, каталоги товаров в интернет-магазинах - все это деревья. Неудивительно, что основным способом организации узлов в XS2 являются именно деревья. Узлы могут вкладываться друг в друга как файлы в директории. При этом узлы каких типов допускают вложения, а каких нет, определяет разработчик. Для того, чтобы познакомиться с деревьями узлов в XS2, решим следующую задачу. Сделаем так, чтобы на сайте редактор мог создавать произвольное количество новостных лент. На главной странице при этом будет выводится по одному блоку от каждой ленты, в каждом блоке будет транслироваться пять последних новостей из соответствующей ленты.
Прежде всего добавим в модуль "Новости" новый тип с названием "news_feed" с псевдонимом "Лента новостей" (если вы забыли, как создавать типы, загляните в Главу 2). Для этого типа не нужны дополнительные поля, нам вполне достаточно поля "Название". Теперь необходимо как-то указать, что узлы типа "Новостное сообщение" должно вкладываться в узлы типа "Лента новостей". Для этого щелкнем правой кнопкой мыши на только что созданный тип "Новостое сообщение" и в появившемся контекстном меню выберем пункт "Редактировать". В открывшейся справа форме редактирования типа отметим флажок "Является группой". Сразу под флажком появится список всех имеющихся в текущем модуле типов: в нашем случае это будут "Новостное сообщение" и "Новостная лента". Отметим флажок напротив "Новостного сообщения" и сохраним тип. Только что мы указали системе, что тип "Новостная лента" допускает вложение узлов типа "Новостное сообщение". Теперь необходимо создать пару узлов типа "Новостная лента" и в один из них перенести уже имеющиеся у нас новости.
В дереве проектов щелкнем левой кнопкой на пункте "Новости". В появившемся дереве модулей щелкнем правой кнопкой на корне дерева. На экране появится панель с выбором типа добавляемого узла. Обратите внимание, что ранее, когда в модуле "Новости" у нас был всего один тип, эта панель не появлялось. Панель с выбором типа появляется только в том случае, если для данного узла возможно несколько дочерних узлов. Для корневого узла любого модуля возможными дочерними типами являются все описанные в модуле типы. В этом отличие корневого узла от всех остальных, для которых список типов в панели определяется тем, какие флажки были выставлены в форме описания типа в секции "Является группой". Добавим в корень модуля новый узел типа "Новостная лента" с названием "Главная лента". Хорошо видно, что созданный узел допускает вложение других узлов - его иконка имеет вид папки. Теперь нам необходимо перенести в него все созданные до этого узлы типа "Новостное сообщение". Для этого нужно просто поочередно перетащить мышкой все узлы в узел "Главная лента". Теперь можно создать еще одну ленту, например, с названием "Новости партнеров". Щелкнув правой кнопкой на только что созданном узле "Новости партнеры" и выбрав пункт "Добавить узел", мы легко убедимся, что система сразу открывает справа форму для добавления новостного сообщения - это сработала наша галочка, выставленная в секции "Является группой" в описании типа "Новостная лента". Заметьте, что поскольку мы указали в качестве возможных дочерних узлов только тип "Новостное сообщение", система не показала панель с выбором добавляемого типа.
Добавив несколько узлов типа "Новостное сообщение", мы можем приступить к модификации шаблона главной страницы. Ее код теперь будет выглядеть так:
Конструкция в строке №6 должна быть вам уже понятна: с помощью функция xs2GetNodes мы возращаем все имеющиеся в модуле "Новости" ("news") узлы типа "Новостная лента" ("news_feed"). Далее, с помощью конструкции "foreach" мы организуем цикл по выбранным узлам типа "Новостная лента". В строке №12 используется новая для нас функция из XS2 API xs2GetChildren. Она возвращает дочерние узлы для узла, идентификационный номер которого указан в параметре ParId. Легко заметить, что параметры, которые мы использовали при вызове xs2GetChildren полностью совпадают с теми, что мы использовали при вызове xs2GetNodes в Листинге 4. Различия между этими двумя функциями состоит лишь в области поиска: если xs2GetNodes производит поиск узлов во всем модуле, то xs2GetСhildren только среди дочерних узлов заданного узла. Далее следует цикл по выбранным новостным сообщениям. Обратите внимание, что Smarty позволяет вкладывать циклы foreach внутрь друг-друга. В данном случае на внешнем цикле мы перебираем ленты, на внутреннем - для каждой ленты мы перебираем ее дочерние новостные сообщения.
Если теперь мы запустим в браузере главную страницу вашего сайта, мы должны увидить два блока, в каждом из которых показывается пять последних новостей из каждой созданной нами ленты.
Итак, мы научились организовывать вкладывание узлов в друг друга. Настраивая вкладывание типов друг в друга, вы фактически задаете конфигарацию дерева модуля. Обратите внимание, что система позволяет указывать в качестве возможных дочерних типов и тот тип, для которого производится настройка. То есть можно разрешить вкладывание новости внутрь новости, новостной ленты внутрь новостной ленты. Эта возможность часто оказывается очень полезной при проектировании сложной иерархии объектов с большим количеством типов.