In-Portal Developers Guide

This is a wiki-based Developers Guide for In-Portal Open Source CMS. The purpose of this guide is to provide advanced users, web developers and programmers with documentation on how to expand, customize and improve the functionality and the code the In-Portal software. Please consider contributing to our documentation writing effort.

K4:Работа классом EditPickerHelper

From In-Portal Developers Guide

Jump to: navigation, search
Работа с формами Работа с формами
Статьи в этой категории
thumb|left|Изображение блока "inp_edit_picker" на форме редактирования.

Блок "inp_edit_picker" представляет из себя два поля в одном из которых находятся выбранные элементы, а во втором все доступные элементы за исключением уже выбранных. Данный блок позволяет выбрать несколько элементов одновременно и перенести их во второй список.

Класс EditPickerHelper автоматизирует обработку данных, полученных из блока "inp_edit_picker".

Contents

Использование на шаблоне

Блок "inp_edit_picker" является стандартным начиная с Core v 4.2.2. Использовать его в шаблоне можно следующим образом:

<inp2:m_RenderElement
	name="inp_edit_picker" prefix="sample-prefix" field="OptionField" title="la_fld_OptionField"
	optprefix="option-prefix" option_key_field="OptionId" option_value_field="OptionTitle"
	size="10" style="CSS definitions"
/>

Ниже приведено описание параметров блока "inp_edit_picker". Параметры "name", "prefix", "field", "title" и "style" являются стандартными для всех блоков, используемых на формах редактирования, поэтому в данной статье они описаны не будут.

параметр описание параметра
optprefix (string) Префикс, данные которого будут использованы для заполнения списка доступных и выбранных опций.
option_key_field (string) Поле, объявленное в unit config префикса опций, которое содержит идентификатор (ID) опции.
option_value_field (string) Поле, объявленное в unit config префикса опций, которое содержит название опции.
size (int) Количество показываемых опций без боковой полосы прокрутки. По умолчанию данный параметр равен 15.

Базовая настройка

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

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

$config = Array(
	'Prefix' => 'sample-prefix',
 
	'Fields' => Array (
		'OptionField' => Array (
			'type' => 'string',
			'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %1$s FROM ' . TABLE_PREFIX . 'OptionTable',
			'option_key_field' => 'OptionId', 'option_title_field' => 'OptionTitle',
			'required' => 1, 'not_null' => 1, 'default' => 0
		),
	),
 
	'Grids' => Array (
		'Default' => Array (
			'Icons' => Array ('default' => 'icon16_custom.gif'),
			'Fields' => Array(
				'OptionField' => Array (
					'title' => 'la_col_OptionField', 'data_block' => 'grid_picker_td',
					'filter_block' => 'grid_picker_filter', 'header_block' => 'grid_column_title_no_sorting'
				),
			),
		),
	),
);

Учитывая форму хранения значений в поле OptionField ему не представляется возможным сделать осмысленную сортировку. В следствие чего используется блок "grid_column_title_no_sorting", который убирает возможность сортировки по полю.

Image:Tipbox Icon.gif В случае, когда данные будут храниться в отдельной таблице поле должно быть виртуальным.


Прописать в шаблоне редактирования тег, использующий данное поле. К данному моменту результатом использования блока "inp_edit_picker" будут заполненные списки доступных и выбранных опций, правда в обоих из них будет полных список опций. Для того, чтобы выбранные опции показывались правильно, нужно в обработчике событий используемого префикса опций (в данной статье это "option-prefix") переписать метод SetCustomQuery. Сутью переписывания метода является добавления фильтра по выбранным и доступным опциям:

/**
 * Applies edit picker filters
 *
 * @param kEvent $event
 */
function SetCustomQuery(&$event)
{
	$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
	/* @var $edit_picker_helper EditPickerHelper */
 
	$edit_picker_helper->applyFilter($event, 'OptionId');
}

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

Хранение данных в связанной таблице

У связанной таблицы должен быть свой конфигурационный файл и обработчик событий, так как она должна быть подчинённым префиксом относительно главного. В данной статье главный префикс это "sample-prefix".

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

$config = Array (
	'Prefix' => 'sample-prefix-child',
	'Hooks' => Array (
		Array (
			'Mode' => hAFTER,
			'Conditional' => false,
			'HookToPrefix' => '#PARENT#',
			'HookToSpecial' => '*',
			'HookToEvent' => Array('OnAfterItemCreate', 'OnAfterItemUpdate'),
			'DoPrefix' => '',
			'DoSpecial' => '*',
			'DoEvent' => 'OnSaveChildren',
		),
	),
 
	'ForeignKey' => 'ParentId',
	'ParentTableKey' => 'ParentId',
	'ParentPrefix' => 'parent',
	'AutoDelete' => true,
	'AutoClone' => true,
 
	'Fields' => Array (
		'ChildId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
		'ParentId' => Array ('type' => 'int', 'not_null' => 1, 'required' => 1, 'default' => 0),
		'OptionId' => Array ('type' => 'int', 'not_null' => 1, 'required' => 1, 'default' => 0),
	),
);

В обработчике событий подчинённого префикса прописать тело hook:

/**
 * [HOOK] Saves changes from edit picker
 *
 * @param kEvent $event
 */
function OnSaveChildren(&$event)
{
	$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
	/* @var $edit_picker_helper EditPickerHelper */
 
	$edit_picker_helper->SaveValues($event, 'OptionField', 'OptionId');
}

В конфигурационном файле главного префикса нужно прописать его связку с подчинённым префиксом:

$config = Array (
	'SubItems' => Array('sample-prefix-child'),
);

Добавить в обработчик событий главного префикса загрузку значений в блок "inp_edit_picker" из подчинённой таблицы:

/**
 * Loads edit picker data
 *
 * @param kEvent $event
 */
function OnAfterItemLoad(&$event)
{
	parent::OnAfterItemLoad($event);
 
	$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
	/* @var $edit_picker_helper EditPickerHelper */
 
	$edit_picker_helper->LoadValues($event, 'OptionId', 'sample-prefix-child.OptionId');
}

В обработчике тегов (TagProcessor) переписать метод PrepareListElementParams, который будет использоваться для вывода данных (из тэга PrintList) из связанной таблицы в списке главного префикса:

function PrepareListElementParams(&$object, &$block_params)
{
	$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
	/* @var $edit_picker_helper EditPickerHelper */
 
	$event = new kEvent($object->getPrefixSpecial() . ':OnAfterItemLoad');
	$edit_picker_helper->LoadValues($event, 'OptionField', 'sample-prefix-child.OptionId');
}

После этого, для каждой записи в списке, выбранные в поле OptionField опции будут выводиться через запятую.

Фильтрация в списке

На данный момент нету стандартного фильтра, который будет корректно осуществлять фильтрацию данных по связанной таблице. Из-за этого надо будет переписать класс "kSearchHelper", который зарегистрирован в фабрике классов под pseudo "SearchHelper".

Для начала нужно создать класс наследник:

class ESearchHelper extends kSearchHelper {
 
	function getCustomFilterSearchClause(&$object, $field_name, $filter_type, $field_options)
	{
		if ($field_name == 'OptionField' && $filter_type == 'options') {
			extract( $this->getFieldInformation($object, $field_name) );
			$field_value = strlen($field_options['submit_value']) ? $this->Conn->qstr($field_options['submit_value']) : false;
			if ($field_value) {
				$sub_sql = 'SELECT children.ParentId
							FROM ' . $this->Application->getUnitOption('sample-prefix-child', 'TableName') . ' children
							WHERE children.OptionId = ' . $field_value;
				$filter_value = $object->TableName . '.' . $object->IDField . ' IN (' . $sub_sql . ')';
			}
 
			$field_options['sql_filter_type'] = $sql_filter_type;
			$field_options['value'] = $filter_value;
 
			return $field_options;
		}
 
		return parent::getCustomFilterSearchClause($object, $field_name, $filter_type, $field_options);
	}
}

Файл будет называться "e_search_helper.php" (согласно правилу назначения имён) и находиться в директории "custom/units/sections".

Потом нужно зарегистрировать новый класс в фабрике классов:

$config = Array (
	'RegisterClasses' => Array (
		Array ('pseudo' => 'SearchHelper', 'class' => 'ESearchHelper', 'file' => 'e_search_helper.php'),
	),
);

См. также