Нодус:Связи между материалами

Компонент: Nodus

А теперь давайте представим себе, что все коты в нашем каталоге - дрессированные. А если они дрессированные, то должен быть и дрессировщик, которого следует указывать при редактировании параметров кота и выводить на странице описания. Мы, конечно, можем создать словарь, в который занести Куклачева, Запашного и прочих. Однако может так оказаться, что дрессировщик по логике проекта - это нечто большее, чем термин словаря. Это полноценный материал с кучей информации. Т.е. нам нужно создать новый тип материала - trainer (дрессировщик), занести некий набор дрессировщиков, а потом при редактировании кота выбирать дрессировщика из списка.

Для этого в Нодусе предусмотрен механизм связей между материалами.

Единичная связь

Итак, у нас есть тип trainer, дрессировщики занесены. В типе cat создаем поле trainer:

'trainer' => array(
  'sqltype' => 'int index',
  'type' => 'nodus_items_select',
  'selector' => 'trainer',
  'caption' => 'Дрессировщик',
  'tab' => 'default',
),
  • Тип поля nodus_items_select обеспечивает единичную связь. Т.е. конкретному коту может быть сопоставлен только один дрессировщик.
  • Параметр selector указывает селектор, выдающий список дрессировщиков для выбора. В данном случае используется селектор по умолчанию, но никто не мешает создать какой-нибудь сложный селектор.

Как отобразить дрессировщика на странице кота

// Получаем контейнер значения
$trainer = $item->field('trainer');

// Выводим материал типа trainer в режиме отображения teaser (по умолчанию)
print $trainer;

// Выводим материал в произвольном режиме отображения
print $trainer->render($mode);

// Для более низкого уровня - получаем ID дрессировщика
$trainer_id = $trainer->id();

// Получаем имя дрессироващика
$trainer_name = $trainer->title();

// Получаем ссылку на полную страницу дрессировщика
$trainer_url = $trainer->url();

// Получаем весь материал в виде объекта
$trainer_item = $trainer->item();

Как вывести список котов на странице дрессировщика

Например, так:

// Получаем селектор, выдающий котов данного дрессировщика
$cats_selector = Component_Nodus::selector('cat')->column_eq('trainer',$item->id);

// Выводим полный список котов, используя хелпер
print $this->nodus->selector_rows($cats_selector);

// Выводим список, указывая особый режим отображения
print $this->nodus->selector_rows($cats_selector,array('mode' => 'for_trainer'));

// Если котов много, то можно вывести первые несколько
// (не забываем потом ссылку на весь список)
print $this->nodus->selector_rows($cats_selector,array(
  'mode' => 'for_trainer',
  'limit' => 3
));

// Получаем список котов в виде массива
// и делаем с ним что угодно
$cats_rows = $cats_selector->rows();

Множественная связь

А теперь представим себе. что у одного кота может быть несколько дрессировщиков (жалко животину, но иногда надо). Поэтому нужна множественная связь. Создаем аналогичное поле без параметра sqltype, но с типом nodus_items_multilink:

'trainers' => array(
	'type' => 'nodus_items_multilink',
	'selector' => 'trainer',
	'caption' => 'Дрессировщик',
	'tab' => 'default',
),

И спокойно себе отмечаем дрессировщиков галочками. Если список небольшой, то проблем с его использованием не возникнет. А если список досточно длинный? Тогда воспользуемся модифицированным вариантом данного типа - nodus_items_multilink_advanced. Поступаем аналогично, только в type указываем тип поля nodus_items_multilink_advanced.

'trainers' => array(
	'type' => 'nodus_items_multilink_advanced',
	'selector' => 'trainer',
	'caption' => 'Дрессировщик',
	'tab' => 'default',
),

Теперь, в поле «Дрессировщик», будет указана ссылка «Добавить связь». А при добавлении новой связи, откроется модальное окно со списком всех дрессировщиков и формой поиска.

Можно пойти и в обратную сторону: сделать поле cats у материала "Дрессировщик", в котором помечать галками котов. Но тут нужно смотреть по нуждам конкретного проекта и сделать так, как будет удобнее для администрирования.

Как вывести список дрессировщиков на странице кота

Двумя способами. Во-первых, используя возможности самого поля nodus_items_multilink:

// Выводим всех дрессировщиков в режиме отображения по умолчанию (teaser)
print $item->field('trainers');

// Выводим всех дрессировщиков в указанном режиме отображения
print $item->field('trainers')->render($mode);

// Выводим первых трех дрессировщиков в указанном режиме отображения
print $item->field('trainers')->limit(3)->render($mode);

Однако этим все возможности поля и ограничиваются. Изменить, например, порядок сортировки уже не получится. Более гибкий способ - получить селектор и работать уже с ним:

// Получаем селектор по-умолчанию для типа trainer
// и применяем модификатор - все привязанные к данному материалу
// по полю trainers.
$selector = Component_Nodus::selector('trainer')->tied_to($item,'trainers');

// Выводим полученных дрессировщиков хелпером
print $this->nodus->selector_rows($selector);

// Или получаем массив и делаем с ним что угодно
$trainers = $selector->rows();

Как вывести список котов на странице дрессировщика

Здесь только один способ - с селектором, т.к. у типа trainer нет поля, отвечающего за котов. Все аналогично предыдущему примеру, только вместо tied_to используем back_tied_to - нам нужна именно обратная свзяь:

$selector = Component_Nodus::selector('cat')->back_tied_to($item,'trainers');

Не перепутайте: вторым аргументом в функции back_tied_to в данном случае будет именно 'trainers', т.к. это - название поля, по которому идет связь. Впрочем, в простейшем случае второй параметр здесь (и в tied_to) можно опустить - тогда будут выбраны все привязанные материалы данного типа, не взирая на имя поля. Когда такое поле одно, разницы нет. А вот если будет два поля (например - "Основные дрессировщики" и "Дублирующие дрессировщики"), то имя поля указывать - обязательно.

Метки: Нодус
26.06.2014
Все статьи