Компонент NodusCatalog

Компонент: Нодус Каталог

Для удобства в Нодус Каталоге вводятся дополнительные базовые понятия типов данных и таксономий.

Базовые понятия

Товары

Товары - это особый тип данных, который устанавливается вместе с Нодус Каталогом. В отличие от базовых типов данных имеет собственный административный контроллер.

Товар

Товар - это материал типа Товары.

Товарные группы

Товарные группы, или просто группы - это особый словарь таксономии, который отвечает за представление дерева структуры каталога и разделение характеристик по товарам. В отличие от базовых словарей таксономии имеет собственный административный контроллер.

Товарная группа

Товарная группа, или просто группа - это термин словаря Товарных групп.

Производители

Производители - так же особый словарь таксономии, который отвечает за представление списка производителей товара. В отличие от базовых словарей таксономии имеет собственный административный контроллер.

Производитель

Производитель - это термин словаря Производителей.

Характеристика

Характеристика - это атрибут Товара, специфичный для определенной Товарной группы. Список характеристик Товаров той или иной Группы задаётся на странице редактирования Группы. В отличии от свойств, которые описываются в классе типа данных Товары, характеристики не разделяются между разными Товарными группами.

Начало работы

Сразу после установки компонента мы получаем новый тип данных "Единица каталога товаров" (название можно изменить под собственные нужды, переопределив метод title типа данных Товаров), и все наши товары мы будем добавлять именно как материалы этого типа. В нём описываются свойства, общие для всех (или большинства) видов товаров. По умолчанию, помимо стандартных для всех типов данных полей, добавляются Изображение, Описание, Цена и флажок, показывающий наличие товара, а также выпадающие списки Производитель и Товарная группа для привязки к соотвествующим словарям. Отличие от остальных типов данных состоит в том, что расположен этот тип данных (вместе со всеми своими шаблонами) в папке NodusCatalog'a (app/Item/Type.php), и перед определением массива полей/вкладок желательно получить родительские значения (parent::fields()/parent::tabs()) и уже этот массив изменять и возвращать. Из полей по умолчанию для работы каталога критично только наличие поля Товарная группа.

#  NodusCatalog/app/Item/Type.php

...
  public function fields()
  {
	$fields = parent::fields();
	....
	$fields['super'] = array(...);
	$fields['brand_id']['title'] = 'Брэнд';
	....
	return $fields;
  }
...

Добавление и редактирование Характеристик

Итак тип данных уже создан за нас, так же как и общие для товаров свойства. Теперь обратимся сразу к словарю "Каталог Товаров: товарные группы" и создадим в нём группы, соответствующие типам продаваемых товаров. Попасть в словарь можно либо обычным для Нодуса способом (Словари->Каталог товаров: товарные группы), либо через меню Компоненты->Каталог->Группы. Второй вариант предпочтительней, так как выведет вас на специальный режим администирования групп.

По умолчанию считается, что именно этот словарь определяет структуру каталога и дерево разделов будет строиться именно по его терминам, но это не обязательное условие. Вы можете пользоваться им в качестве простого классификатора, а структуру каталога формировать любым удобным способом. Основное назначение словаря - разграничить характеристики товаров, а не формировать структуру.

При редактировании терминов есть вкладка "Реквизитный состав", в которой и будут храниться свойства товаров данной группы. Они описываются ввиде массива, в формате, совместимом с CMS.Fields:

В случае с нашим примером описание полей может выглядеть следующим образом

#ручки
// Явно указываем тип input
body_color = {
	caption = Цвет корпуса
	type = string
}
// Также получим input, но короткий
length = {
	caption = Длина
	type = number
}

// И снова будет input, как поле по умолчанию.
color = {
	caption = Цвет чернил
}
#записные книжки
cover = {
	caption = Материал обложки
}

// Тут будет выпадающий список, построенный по терминам словаря notebooktypes
type = {
	caption = Тип
	type = select
	taxonomy = notebooktypes
}

alphabet = {
	caption = Алфавит
	type = checkbox
}
#тетради
cover_type = {
	caption = Тип обложки
	type = select
	taxonomy = workbookcovers
}

pages = {
	caption = Страниц
}

line_type = {
	caption = Тип линовки
	type = select
	items = {
		0 = Без линовки
		1 = Клетка
		2 = Линовка мелкая
		3 = Линовка крупная
	}
}

Теперь создаем новую запись с типом Единица каталога товаров, идем на вкладку Характеристики и ничего там не видим. Потому что для того, чтобы подцепить поля записи, нужно обязательно привязать её к товарной группе (вкладка Параметры). После сохранения записи на вкладке Характеристики будут доступы все описанные нами поля.

Собственно после заполнения этих полей и сохранения записи на неё можно посмотреть по её адресу. Для использования внутри шаблона у объекта записи появляются свойства с соответствующими названиями и плюс свойство catalog, которое может предоставить доступ к контейнерам соответствующих полей по их коду.

	// Перед применением всего ниже перечисленного, следует проверить наличие такого поля у записи и что каталог не пуст

	if ($item->catalog && !$item->catalog->is_empty()) {

		// Получение значения поля не многим отличается от Нодуса
		echo $item->catalog->field('cover_type')->render();

		// Помимо стандартных свойств, в поле также хранится его заголовок
		echo $item->catalog->field('cover_type')->caption

		// Объект каталога также можно обходить, как маcсив.
		foreach ($item->catalog as $code => $field) {
			echo $field->caption . ':' . $field->render();
		}

	}

По умолчанию дерево каталога доступно по адресу /catalog/. Для отображения дерева словаря в произвольном месте, можно воспользоваться хелпером

#где-то в шаблоне

// отрисует полное дерево каталога
<?= $this->nodus_catalog->sections();?>

// Отрисует ветку каталога, для указанных узлов. $id - id или мнемокод термина каталога
<?= $this->nodus_catalog->section(Component_Nodus::taxonomy_term($id))?>

Для изменения внешнего вида дерева можно передать хелперу второй параметр - код шаблона (например fancy) и создать свой шаблон в папке NodusCatalog/app/views с названием fancy-section-list.

Для отображения в админе доступны все типы полей, имеющиеся в CMS.Fields, но есть одно "но" - обработаны и сохранены корректно будут только поля, отдающие значение в объект записи под своим кодом и сохраняющиеся в самой записи или вовсе не сохраняющие данные в базе. Все поля, которые сами обрабатывают свои значения (например, taxonomy_multilink) не будут обработаны и их значения не сохранятся. Как быть? Написать свои аналоги, которые при том же UI будут сохранять значения в таблицу значений каталога (например, поле catalog_taxonomy_multilink).

Отображение списка товаров

Список товаров - это список записей селектора, полученный штатными средствами Нодуса, что даёт возможность переопределять отображение списка в целом с использованием механизма отображения селекторов. В случае Каталога селектор по умолчанию имеет мнемокод filter. Т.е. вы можете как обычно поместить в папку Nodus/app/views/ файл selector-rows-filter.phtml и использовать его. Однако не всегда удобно перемещаться между компонентами, чтобы изменить шаблон, поэтому в Каталоге есть дополнительные способы стилизации списка: для этого необходимо создать следующую структуру каталогов NodusCatalog/app/views/selector/, и далее в ней создавать требуемые файлы:

// переопределяем шаблон для группы с id = 2
../app/components/NodusCatalog/app/views/selector/2/selector-rows.phtml

// переопределяем шаблон для группы с мнемокодом pencils
../app/components/NodusCatalog/app/views/selector/pencils/selector-rows.phtml

// переопределяем шаблон для селектора в целом
../app/components/NodusCatalog/app/views/selector/filter/selector-rows.phtml

// переопределяем отображение для первой страницы селектора в режиме teaser
../app/components/NodusCatalog/app/views/selector/filter/teaser-selector-rows-1.phtml

Полный список всех доступных режимов переопределения можно посмотреть в Component_NodusCatalog_Filter_Selector::template();

Фильтрация

По всем каталожным (и не только) полям можно устроить фильтрацию. Для этого нужно совершить два действия: описать фильтр и отобразить его.

Описание фильтра

Для описания мы воспользуемся реквизитным составом словаря Товарных групп. В нем для каждого поля можно указать требуется ли фильтрация, и если да - то каким образом. Для этого при описании поля, добавим дополнительный параметр - filter, массив, описывающий правила фильтрации:

В нашем примере фильтр для ручек мог бы выглядеть так:

// фильтр по цене
price = {
	type = none
	caption = Цена
	filter = {
		type = range
		min = this
		max = this
	}
}

// фильтр по цвету с помощью простого текстового ввода
body_color = {
	caption = Цвет корпуса
	type = string
	filter = {
		type = input
	}
}
// фильтр по длине с помощью простого текстового ввода
length = {
	caption = Длина
	type = number
	filter = {
		type = input
	}
}

Отображение фильтра

Для отображения фильтра нужно знать, как минимум товарную группу, для которой мы будем рисовать форму фильтрации. В качестве первого аргумента нужно передать либо id, либо мнемокод либо целиком объект требуемой товарной группы. В любом нужном месте вызываем хелпер и любуемся результатом.

#где-то в шаблоне
// рисуем форму фильтра для группы с кодом pens так
<?= $this->nodus_catalog->filter_form('pens');?>
// или так, предполагая, что id группы ручек - 1
<?= $this->nodus_catalog->filter_form(1);?>
// или так
$group = CMS::component('NodusCatalog')->group('pens');
// много кода ...
$best = $group->taxonomy()->do_something();
// много кода ...
<?= $this->nodus_catalog->filter_form($group);?>

// получить объект текущей группы можно из WS::env()->nodus_catalog_group
// так что этот код будет рисовать форму фильтра для текущей группы
<?php if (WS::env()->nodus_catalog_group) { ?>
	<?= $this->nodus_catalog->filter_form(WS::env()->nodus_catalog_group);?>
<?php } ?>

Адреса

Все результаты фильтрации будут выводиться на страницу с адресом термина соотвествующей товарной группы, если у него включен отклик и есть адрес, иначе, они будут откликаться по адресу, взятому из селектора фильтра.

Настройка

Если завести несколько записей и посмотреть, как работает фильтр, то можно заметить несколько неудобств - все поля используют нежесткий поиск,и поэтому поиск по длине 1 вернет и ручки с длиной 10 и 11 и 21 и т.д. Избежать этого нам помогут опции поля. Так же вводить искомый цвет не очень удобно, поэтому сразу изменим и поле для фильтрации

// фильтр по цене
price = {
	type = none
	caption = Цена
	filter = {
		type = range
		min = this
		max = this
	}
}

// фильтр по цвету с помощью выпадающего списка
body_color = {
	caption = Цвет корпуса
	type = string
	filter = {
		type = select
	}
}
// фильтр по длине с помощью простого текстового ввода
length = {
	caption = Длина
	type = number
	filter = {
		type = input
		strict = true // теперь фильтр по этому полю будет искать строгое =, а не LIKE
	}
}

Можно заметить ключевое слово none в самом верху описания поля price. Дело в том, что эти поля и так присутствуют у товара и их не требуется дополнительно выводить во вкладке "Характеристики". Указав none мы говорим каталогу, что редактирование полей не предполагается.

Фильтр по умолчанию

В примере выше мы настроили фильтр по полям Цена, Цвет корпуса и Длина только для ручек. А что делать, если нужно дать возможность все товары фильтровать по цене или названию? Можно, конечно, в каждую товарную группу добавить описание этих полей для фильтра, но это не удобно. Лучше воспользоваться методом default_filter типа данных товара. Например

# components/NodusCatalog/app/Item/Type.php
public function default_filter()
{
	return array (
		'title' => array(
			'caption' => 'Название',
			'type' => 'input',
			'strict' => false,
		),
	);
}

Шаблоны форм и полей фильтра

Если вас не устраивают шаблоны форм фильтра, вы можете их переопределить, поместив желаемый шаблон по одному из путей

#переопределяет шаблон для всех фильтров с шаблоном, указанным при вызове хэлпера, например
# $this->nodus_catalog->filter_form($group, $template)
NodusCatalog/app/views/filter/{$template}/template.phtml

#переопределяет шаблон фильтра для одной группы, id или код которой вы передали хэлперу
NodusCatalog/app/views/filter/{$code|$id}$/template.phtml

#переопределяет форму всех фильтров для сайта
NodusCatalog/app/views/filter/default/template.phtml

Внутри формы можно воспользоваться хэлпером для отрисовки полей, который вернёт указанное в описании поле фильтра в текущем шаблоне

<?=$this->nodus_catalog->filter_field('field_name')?>

Шаблоны отображения каждого конкретного поля можно изменять двумя способами. Во-первых, как и для всех CMS.Fields вы можете изменить шаблон конкретного поля с помощью ключа template. Во-вторых, можно переопределить шаблон отображения для типов полей.

// Переопределяет шаблон поля одного типа для одной группы по её мнемокоду или id
NodusCatalog/app/views/filter/{$code|$id}/filter_widget/{$widget}/template.phtml

// Переопределяет шаблон поля одного типа для всех фильтров.
NodusCatalog/app/views/filter/default/filter_widget/{$widget}/template.phtml

Список полей для редактирования

Помимо стандартных есть несколько новых полей для использования при редактировании товара в административной части.

none - не требуется поле для редактирования свойства (нужно использовать, например, когда надо ввести обычное свойство товара (например, цену) в фильтр)

number - узкий input

text - текстовая область

string - обычный input.

select - выпадающий список для выбора одного термина словаря. От стандартного select отличается тем, что ему можно передать опцию taxonomy с указание словаря, из терминов которого будут взяты варианты для выбора.

multiselect - список из checkbox для выбора нескольких терминов словаря. Обязательно нужно указать опцию taxonomy c мнемокодом словаря, термины которого нужно выводить. В остальном это клон nodus_taxonomy_multiselect

Типы полей фильтра

При выводе формы используется механизм CMS.Fields, поэтому, теоретически, можно пользоваться всеми доступными полями, но для фильтрации нужно создать соотвествующую обёртку, которая сумеет объяснить, как получить значение из запроса и как нужно учесть его при фильтрации. Поэтому на текущий момент список полей для фильтрации ограничен следующими:

input

Создает обычное текстовое поле для фильтрации нестрогим соответствием. Можно передать опцию type=hard, чтобы сделать поиск строгим соответствием.

select

Создает выпадающий список для выбора одного значения из списка. По умолчанию список строится из всех возможных значений данного поля, однако если код поля (field_code) совпадает с мнемокодом одного из существующих словарей, то список будет построен из терминов данного словаря.

Можно передать несколько опций:

  • taxonomy - если передать мнемокод словаря, то список будет построен из терминов данного словаря. Для ссылки на словарь Товарных групп можно воспользоваться словом this
  • term - если передать id термина словаря, то список будет построен только из терминов, вложенных в указанный. Для ссылки на текущий термин можно воспользоваться словом this
  • null - отвечает за первый элемент списка, который приравнивается к "неважно". По умолчанию его нет. Если передать произвольный текст, то будет использован он, если передать слово empty, то будет пустой первый элемент

checkboxes

Создаёт список галочек для выбора нескольких значений. Логика его использования схожа с select'ом, только для него не имеет смысла опция null, и он может принять две дополнительные опции val и text, которые работают только вместе и в первой должно храниться значение, а во второй текстовое имя, которое будет использоваться для построения одного единственного checkbox'а

radio

Создает радио-кнопку для выбора одного значения. Логика использования совпадает с select'ом

range

Создает двойной ползунок для выбора диапазона значений (например, для сортировки по цене).

После установки Нодус Каталога это поле становится также доступно для обычного использования.

Можно передать следующие опции:

  • min - минимальное значение ползунка. Можно передать число или ключевое слово this, чтобы выбрать минимальное из значений поля. По умолчанию 0.
  • max - максимальное значение ползунка. Можно передать число или ключевое слово this, чтобы выбрать максимальное из значений поля. По умолчанию 10000.
  • step - шаг изменения ползунка. Можно передать число. По умолчанию 1.

Сравнение товаров

Для данного типа материалов реализована функция сравнения товаров. Одновременно можно выделить любое количество товаров и только одной категории.

Вывод производится с использованием следующего метода хелпера:

// app/components/NodusCatalog/app/Item/full.phtml
	...
	// отрисовывается  поле с галкой
	<?= $this->nodus_catalog_comparison->link($item) ?>
	...

Если требуется выводить больше информации: список сравниваемых товаров, количество этих товаров, то необходимо добавить следующий метод:

// app/components/NodusCatalog/app/Item/full.phtml
	...
	// отрисовывается  поле с галкой
	<?= $this->nodus_catalog_comparison->link($item) ?>
	// отрисовывается список товаров для сравнения
	<?= $this->nodus_catalog_comparison->items_list($item->group_id) ?>
	...

Соответственно вывод поля для сравнения можно организовать не только на странице c описанием товара (шаблон full.phtml), но и для каждой позиции в списке товаров в шаблоне teaser.phtml.

Сравнение товаров производится на отдельной странице. Вывод свойств товаров организован в табличном виде для удобства сравнения. Предусмотрен фильтр просмотра только тех свойств товара, которые различаются.

Дополнительные методы сортировки полей

  • first($num) - метод возвращает первые несколько элементов каталога по заданному количеству ($num), переданному в качестве аргумента.
// вывод первых трех названий атрибутов товара в шаблоне
<source lang="php">
foreach ($item->catalog->first(3) as $code => $field) { ?>
	<tr>
		<td><?= $field->caption ?></td>
		<td><?= $field->render() ?></td>
	</tr>
  • with_parameter($parameter) - метод позволяет проводить сортировку и выводить список атрибутов товара по заданному параметру. Для этого при описании реквизитного состава необходимо задать произвольный параметр какому-либо атрибуту. Например,
...
color = {
	caption = Окрас
	type = select
	taxonomy = haircolor
	in_list = 1
}
...

где in_list - признак атрибута для последующей сортировки.

Затем в шаблоне указывается параметр сортировки.

...
<?php foreach ($item->catalog-> with_parameter('in_list') as $code => $field) { ?>
		<tr>
			<td><?= $field->caption ?></td>
			<td><?= $field->render() ?></td>
		</tr>
...
  • without_parameter($parameter) - выводиться будут только те атрибуты, у которых не отмечен признак $parameter.
...
// вывод всех атрибутов, у которых не обозначен признак in_list
<?php foreach ($item->catalog-> without_parameter('in_list') as $code => $field) { ?>
		<tr>
			<td><?= $field->caption ?></td>
			<td><?= $field->render() ?></td>
		</tr>
...
  • lang($lang = '') - вывод атрибутов по языковому признаку. При описании атрибутов необходимо указывать признак с выбранным языком - lang = ru/en/др.. При сортировке будут выбраны и выведены те атрибуты, у которых обозначен признак lang с заданным значением и те атрибуты, у которых данный признак вообще не установлен.
...
<?php foreach ($item->catalog->lang('ru') as $code => $field) { ?>
		<tr>
			<td><?= $field->caption ?></td>
			<td><?= $field->render() ?></td>
		</tr>
...

Если в методе не указан аргумент, то для сортировки будет выбран текущий язык в качестве аргумента.

23.07.2014
Все статьи