Нодус:Таксономия
Таксономия в Нодусе представляет собой систему словарей. Словари состоят из терминов, причем словари бывают как линейными, так и древовидными. Количество словарей, которые можно создать, ограничивается только вычислительными мощностями системы.
Для начала давайте заведем справочник пород кошек, и будем указывать породу для каждой кошки. Для этого пойдем в каталог app/components/Nodus/app/Taxonomy и создадим в нем модуль Component.Nodus.App.Taxonomy.Breeds:
// app/components/Nodus/app/Taxonomy/Breeds.php Core::load('Component.Nodus.Taxonomy'); class Component_Nodus_App_Taxonomy_Breeds extends Component_Nodus_Taxonomy implements Core_ModuleInterface { public function title() { return 'Породы'; } }
Этого уже достаточно, чтобы в системе появился новый словарь. Однако он будет линейным, а мы хотим древовидный. Поэтому добавим в наш класс функцию is_tree:
// app/components/Nodus/app/Taxonomy/Breeds.php Core::load('Component.Nodus.Taxonomy'); class Component_Nodus_App_Taxonomy_Breeds extends Component_Nodus_Taxonomy implements Core_ModuleInterface { public function is_tree() { return true; } }
Теперь идем по адресу /admin/nodus/taxonomy/ и видим наш только что созданный словарь. Заходим в него и заполняем:
Начиная с версии компонента 3.0.44, реализована возможность отклика термина по адресу (метод has_page()
).
// app/components/Nodus/app/Taxonomy/Breeds.php Core::load('Component.Nodus.Taxonomy'); class Component_Nodus_App_Taxonomy_Breeds extends Component_Nodus_Taxonomy implements Core_ModuleInterface { public function has_page() { return false; } }
По умолчанию флаг отклика включен, и страница формируется автоматически. Данный метод позволяет на программном уровне отключить формирование страницы и отклика. Соответственно в администраторе сайте данная функция будет не доступна.
При формировании страницы термина реализована настройка полей для мета-тегов. Вкладка будет подключаться автоматически при включенном флаге отклика.
Приоритет вывода мета-тегов сохраняется.
Привязка материала к словарю
Открываем модуль Component.Nodus.App.Datatype.Cat.Type и добавляем новое поле:
// app/components/Nodus/app/Datatype/Cat/Type.php 'breed' => array( 'sqltype' => 'int index', 'type' => 'nodus_taxonomy_select', 'taxonomy' => 'breeds', 'caption' => 'Порода', 'tab' => 'default', ),
- sqltype: привязка материала - простая. Т.е. нам достаточно хранить только идентификатор выбранного термина. А поскольку мы в дальнейшем будем делать выборки по этому значению, то не забываем указать индекс. Поэтому - "int index".
- type: в качестве типа поля указываем nodus_taxonomy_select - этот тип поля обеспечивает простую привязку материала к словарю.
- taxonomy: здесь указываем мнемокод словаря.
После этого редактируем всех своих кошек и указываем для каждой породу.
Выборка материалов по термину
В общем случае эта задача решается так: создаем селектор с аргументом (ID термина), у которого в маппере наличествует условие where по полю "breed" в соответствии с переданным аргументом. Однако, для наиболее распространенных задач существует способ удобнее: воспользуемся автоматически созданным селектором.
Прежде всего необходимо при редактировании термина установить флажок "Отклик". Это означает, что для данного термина будет создана страница со списком материалов, с ним связанных. Для этой страницы можно также вручную установить полный URL. Если этого не сделать, то будет использован URL по умолчанию - на основании идентификатора термина(/term/id/).
Следующий шаг: указать, что именно выбирать. Ведь никто не мешает связывать с одним и тем же словарем материалы разных типов, а также в одном типе создавать несколько разных полей, связывающих материал с одним и тем же словарем. Т.е. для корректной выборки нам нужно указать тип материала и имя поля в этом типе. Для этого в классе Component.Nodus.App.Taxonomy.Breeds создадим функцию select_by:
// app/components/Nodus/app/Taxonomy/Breeds.php public function select_by() { return 'cat:breed'; }
То, что находится до двоеточия, - это мнемокод типа. То, что после, - имя поля. И теперь при запросе адреса термина из словаря breeds мы увидим список кошек данной породы.
Выборка по вложенным терминам
Теперь рассмотрим такую ситуацию. У нас есть набор кошек, у которых выставлены породы - сиамские, персидские, сибирские. Но словарь - древовидный, и данные термины являются вложенными в термин более высокого уровня - "Породистые". При заходе на адрес этого более высокого термина мы не получаем ничего, т.к. конкретно к нему не привязано ни одной кошки - они все привязаны к вложенным терминам. А у нас стоит задача показать все материалы привязанные к данному термину, а также ко всем терминам, вложенным в него.
Чтобы этого добиться, нам нужно включить в словаре опцию select_items_for_childs:
// app/components/Nodus/app/Taxonomy/Breeds.php public function select_items_for_childs() { return true; }
Как отобразить термин словаря в шаблоне материала
Если нужно просто отобразить ссылку на термин словаря, то делаем вот так:
// app/components/Nodus/app/Datatype/Cats/full.phtml print $item->field('breed');
Однако, этот способ отображает только одну ссылку - на конечный термин. А если словарь древовидный, и нужно отобразить всю "дорожку" как в "хлебных крошках", то делаем так:
// app/components/Nodus/app/Datatype/Cats/full.phtml print $item->field('breed')->render(' >> ');
В качестве аргумента в render передаем разделитель ссылок в "дорожке". Для особых случаев можно использовать низкоуровневые возможности:
// Получаем термин в виде объекта $term = $item->field('breed')->term(); // Получаем id, текст и адрес термина $id = $term->id; $title = $term->title; $url = $term->url(); // Получаем "дорожку" терминов в виде массива $terms = $item->field('breed')->trail();
Множественная привязка
Бывают такие словари, к терминам которых материалы привязываются множественно. Т.е. мы выбираем не один термин, а отмечаем флажками несколько. Словарь "Породы" таким свойством вряд ли обладает, но давайте таки представим себе ситуацию, что вышел указ: "В целях предотвращения дискриминации упразднить наименование "беспородный", и разрешить котам и кошкам принадлежать к нескольким породам одновременно". В этом случае поступаем аналогично предыдущему варианту за некоторым исключением:
- Тип поля указываем nodus_taxonomy_multilink
- Параметр sqltype у поля опускаем, т.к. связи хранятся в специальной связующей таблице (создастся автоматически)
'breeds' => array( 'type' => 'nodus_taxonomy_multilink', 'taxonomy' => 'breeds', 'caption' => 'Порода', 'tab' => 'default', ),
Кроме того, есть ограничения:
- Невозможно создать два поля для связи одного и того же типа с одним и тем же словарем
- Не работает опция select_items_for_childs - в данном случае придется привязывать материал как к основному термину, так и к терминам более высокого уровня.
Как отобразить список привязанных терминов в шаблоне материала
Простой способ - воспользоваться возможностями поля:
// Отображаем список терминов в виде по умолчанию print $item->field('breeds'); // Отображаем список терминов в своем шаблоне print $item->field('breeds')->render($template_path);
По умолчанию список терминов отображается в шаблоне app/components/Nodus/lib/Fields/TaxonomyMultilink/ul.phtml. Если нужно по-другому, то скопируйте этот шаблон куда-нибудь (переименуйте если надо), перепишите под себя и укажите путь к нему в render.
Низкоуровневые возможности тоже есть кое-какие:
// Получаем массив идентификаторов терминов $ids = $item->field('breeds')->ids(); // Получаем массив терминов $terms = $item->field('breeds')->terms();
Добавление таксономии в навигацию
Часто требуется сделать так, чтобы дерево словаря было внедрено в навигацию сайта. Делается это просто, причем двумя способами:
Таксономия, вложенная в существующий узел навигации
Допустим, у нас есть узел навигации "Кошки". Нам требуется, чтобы дерево словаря "Породы" было внутри этого узла (как саблинки). Для этого в доппараметрах узла пишем параметр sub:
sub = nodus breeds
Добавление в навигацию только одной ветви
Допустим, у нас есть древовидный словарь, и нам нужно его добавить в навигацию не полностью, а только одну ветвь - т.е. все, что начинается от одного конкретного термина. Это иногда требуется если словарь в навигации лежит не единым деревом, а разбит на части и разбросан по навигации - иногда и такое бывает. Для этого потребуется узнать числовой идентификатор термина - посмотрите в админке. После чего добавляем в навигацию:
sub = nodus terms 576
где 576 - это идентификатор термина, все потомки которого будут добавлены в навигацию в этот узел.
Таксономия в корневом уровне навигации
Теперь представим себе, что узла "Кошки" не существует, а ссылки на породы должны быть непосредственно в корневом уровне навигации. В этом случае идем в настройки и редактируем переменную "navigation". Там у нас уже есть строчка %nodus. Добавим еще одну, которая прицепит к навигации словарь:
%nodus %nodus breeds
При выводе навигации "словарные" узлы легко отфильтровать: во всех будет установлен параметр "taxonomy", а также параметр конкретного словаря, в данном случае - "taxonomy_breeds".