Нодус:Таксономия

Компонент: Nodus

Таксономия в Нодусе представляет собой систему словарей. Словари состоят из терминов, причем словари бывают как линейными, так и древовидными. Количество словарей, которые можно создать, ограничивается только вычислительными мощностями системы.

Для начала давайте заведем справочник пород кошек, и будем указывать породу для каждой кошки. Для этого пойдем в каталог 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".

26.06.2014
Все статьи