Примеры

В данном разделе приведены некоторые типовые примеры работы API модуля simai.storage с пояснениями.

Примеры работы с классами второго уровня

Произведем несколько стандартных операций с хранилищем. Если что-то в описанных примерах непонятно, то нужно смотреть раздел документации «Классы 2 уровня».

Создаем новое хранилище:

$storage_id = \SIMAI\Storage\Storage::add(
array(
	'STORAGE_ID'=>'test_storage',// код хранилища (обязателен)
	'ACTIVE'=>'Y',// активность хранилища
	'SORT'=>'100',// показатель сортировки
	'SITE_ID'=>array('s1'),// привязка к сайтам (обязательна)
	'ACCESS'=>array('1'=>'X', '2'=>'R'),// уровень доступа групп
		'ELEMENT_ACCESS'=>'N',// возможность раздельного доступа для элементов
		'LOG'=>'N',// логирование действия хранилищ
	)
);
// Системные свойства заголовка и шаблонов URLсоздались автоматически, поскольку мы не указали обратного в параметрах
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Задаем для нашего хранилища свойство «заголовок» – это свойство системное и создано автоматически:

$res = \SIMAI\Storage\Property::setPropValue(
	'test_storage', // код хранилища
	0, // параметр $element_id=0 означает, что значение свойства задается для самого хранилища, а не его элемента
	'TITLE', // код свойства
	array('ru' => 'Новое тестовое хранилище', 'en' => 'New test storage') // заголовок на разных языках
);
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Для записей хранилища создадим еще одно свойство - файловое для присвоения записям картинки:

$file_property_id = \SIMAI\Storage\Property::add(
	array(
		'STORAGE_ID'=>'test_storage', // код хранилища
		'CODE'=>'PICTURE', // код свойства
		'TYPE'=>'file', // тип свойства
		'SETTINGS'=>array(
			'file_type' => 'I', // тип файлов - изображения
			'file_ext' => 'jpg,jpeg,png,gif,bmp', // допустимые расширения
		), // набор доп. параметров, для каждого типа свойств этот набор свой
		'MULTIPLE'=>'N', // не множественное свойство
		'MULTILANGUAGE'=>'N', // не мультиязычное свойство
		'SORT'=>'200', // показатель сортировки
		'STORAGE_USE'=>'N', // не используется для самого хранилища
		'SECTION_USE'=>'N', // не используется для разделов
		'ITEM_USE'=>'Y', // используется для записей
		'SYSTEM'=>'N', // свойство не системное
		'LANGUAGE'=>array('ru'=>'Картинка', 'en'=>'Picture'), // языковые заголовки свойства
	)
);
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Добавим в наше хранилище раздел, установим его заголовок и обновим для него поля сортировки и поиска:

$section_id = \SIMAI\Storage\Element::add(
	'test_storage', // код хранилища
	array(
		'ACTIVE'=>'Y', // активность элемента
		'SORT'=>'500', // показатель сортировки
		'TYPE'=>'S', // это раздел, а не запись
	)
);
// Поскольку это раздел, то \SIMAI\Storage\Element::tree_resortвызовется из этого добавления автоматически
// Установим заголовок раздела
$res = \SIMAI\Storage\Property::setPropValue(
	'test_storage', // код хранилища
	$section_id, // ид раздела
	'TITLE', // код свойства
	array('ru' => 'Новый тестовый раздел', 'en' => 'New test section') // заголовки на разных языках
);
// Поля сортировки и поиска для таблицы элементов нужно обновлять принудительно
\SIMAI\Storage\Property::UpdateStorageElementSorts('test_storage', $section_id); // заполняемполясортировки
\SIMAI\Storage\Search::UpdateStorageElementSearch('test_storage', $section_id); // заполняемполяпоиска

//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Теперь добавим в этот раздел новую запись, установим для заголовок и картинку, после чего обновим для нее поля сортировки и поиска:

// Добавим новую запись
$item_id = \SIMAI\Storage\Element::add(
	'test_storage', // код хранилища
	array(
		'ACTIVE'=>'Y', // активность элемента
		'SORT'=>'100', // показатель сортировки
		'TYPE'=>'I', // это запись, а не раздел
		'PARENT_ID'=>array($section_id), // привязки к род. разделам
	)
);

// Установим заголовок записи
$res = \SIMAI\Storage\Property::setPropValue(
	'test_storage', // код хранилища
	$item_id, // ид записи
	'TITLE', // код свойства
	array('ru' => 'Новая тестовая запись', 'en' => 'New test item') // заголовки на разных языках
);

// Присвоим значение файловому свойству для новой записи (загрузим картинку, допустим, в виде файла /upload/abc.jpg)
$res = \SIMAI\Storage\Property::setPropValue(
	'test_storage', // код хранилища
	$item_id, // ид записи
	'PICTURE', // код свойства
	array_merge(CFile::MakeFileArray($_SERVER["DOCUMENT_ROOT"]."/upload/abc.jpg"),array("module_id" => "simai.storage")) // значение - файловый массив
);

\SIMAI\Storage\Property::UpdateStorageElementSorts('test_storage', $item_id); // заполняем поля сортировки
\SIMAI\Storage\Search::UpdateStorageElementSearch('test_storage', $item_id); // заполняем поля поиска
// Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Предположим, что у нас в хранилище уже много элементов. Сделаем выборки:

$res_elements = \SIMAI\Storage\Element::getList(
	'test_storage', // код хранилища
	array(
		'filter' => array(
			'TYPE' => 'I', // выбрать только записи
			'%PARENT_IDS' => array('-1-', '-2-'), // выбрать только принадлежащие к разделам с идами 4 и 5
		),
		'order' => array(
			'SORT' => 'asc', // сортировать по показателю сортировки
		),
		'select' => array(
			'ELEMENT_ID',
			'ACTIVE', // в выборке только поля ида и активности
		),
	)
	// остальные параметры по умолчанию
);

while ($el_data = $res_elements ->fetch())
{
	echo '<pre>'; print_r($el_data); echo '</pre>';
}
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']
$res_elements = \SIMAI\Storage\Element::getList(
	'test_storage', // код хранилища
	array(
	'filter' => array(
			'ACTIVE' => 'Y', // выбрать только активные
			'%PROP_TITLE.PROP_TITLE' => 'тест', // выбрать только элементы, в заголовке которых есть подстрока «тест»
			'=PROP_TITLE.LANGUAGE_ID' => array('ru', ''), // фильтрация по свойству заголовка только среди русских и неязыковых значений
		),
		'order' => array(
			'PROP_TITLE' => 'asc', // сортировать по значениям свойства TITLE
		),
		'group' => array(
			'ELEMENT_ID', // группировать по ELEMENT_IDчтобы избежать дублирования строк выборки из-за подключения таблицы свойств
		),
	),
	array('TITLE'), // в фильтрах используется свойство TITLE
	false, // не проверять принадлежность к текущему сайту
	true, // проверять права доступа к элементам
	'ru' // сортировка по русскоязычным значениям
);

while ($el_data = $res_elements ->fetch())
{
	echo '<pre>'; print_r($el_data); echo '</pre>';
}
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

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

// Выберем значение файлового свойства из элемента (вернется массив, рассортированный по кодам свойств)
$values = \SIMAI\Storage\Property::GetPropValues(
	'test_storage', // код хранилища
	$item_id, // ид записи
	array('PICTURE'), // код свойства
	LANGUAGE_ID // Свойство не языковое, но установленный язык упростит возвращаемое значение
);

// Выведем полученную картинку через методы Универсальных свойств
CModule::IncludeModule("simai.property");
\SIMAI\Property::view(
	'file', // тип универсального свойства
	'', // шаблон универсального свойства, в нашем случае .default
	$values['PICTURE'], // файловый ид картинки
	array() // параметры универсального свойства, в данном случае - пустой массив
);
//Все ошибки можно увидеть в массиве $GLOBALS['SF_STORAGE_ERRORS']

Работа с классами первого уровня

Классы первого уровня, такие как StorageTable, PropertyTable, PropertyLanTable и т.д. в основном наследуются от Bitrix\Main\Entity\DataManager с некоторыми дополнениями, поэтому к ним применимы стандартные приемы работы с ORM в ядре D7.

Учебный курс по ORM можно найти по ссылке

https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&CHAPTER_ID=05748

Сущности, определяемые этими классами, лежат в пространстве имен SIMAI\Storage, соответственно обращение к базовым классам и их методам должно включать указание пространства имен. Например, \SIMAI\Storage\StorageTable::add()

Несколько особняком стоят сущности, создаваемые для таблицы свойств и таблицы элементов каждого хранилища. Они создаются непосредственно в процессе работы, поэтому не принадлежат к пространству имен SIMAI.

Рассмотрим пример работы с сущностью таблицы элементов методами ORM.

Допустим, у нас стоит задача посчитать количество элементов хранилища test_storage с ELEMENT_ID<100 и мы по какой-то причине не хотим использовать класс Element.

В этом случае мы можем работать непосредственно с сущностью элемента, предварительно создав ее:

// посчитаем, сколько в хранилище элементов с ELEMENT_ID<100
// сначала создадим сущность, опирающуюся на таблицу элементов
$el_entity = \SIMAI\Storage\StorageTable::compileElementsEntity('test_storage'); // создадим сущность, опирающуюся на таблицу элементов хранилища test_storage
if ($el_entity)
{
	$el_entity_data_class = $el_entity->getDataClass(); // имя базового класса сущности
	$res = $el_entity_data_class::getList(array(
		'select' => array('CNT'), // в выборке только виртуальное поле, содержащее COUNT(ELEMENT_ID), заданное в runtime
		'filter' => array('<ELEMENT_ID' => 10), // условие
		'runtime' => array(
			new \Bitrix\Main\Entity\ExpressionField('CNT', 'COUNT(ELEMENT_ID)') // создание для выборки виртуального поля, содержащего COUNT(ELEMENT_ID)
		)
	));

	if ($arr = $res->fetch())
	{
		$count_els = intval($arr['CNT']); // получаем результат подсчета
		echo $count_els;
	}
}
//Все ошибкиможноувидетьв массиве$GLOBALS['SF_STORAGE_ERRORS']

Работа с событиями (с примерами)

События, определяемые методами классов второго уровня, работают через \Bitrix\Main\EventManager

Список событий:

Событие Параметры Описание
События класса Storage
OnBeforeStorageAdd array $fields Вызывается перед добавлением хранилища, может быть использовано для отмены или модификации данных.
OnAfterStorageAdd string $primary array $fields Вызывается после добавления хранилища.
OnBeforeStorageUpdate string $primary array $fields Вызывается перед обновлением хранилища, может быть использовано для отмены или модификации данных.
OnAfterStorageUpdate string $primary array $fields Вызывается после обновления хранилища.
OnBeforeStorageDelete string $primary Вызывается перед удалением хранилища.
OnAfterStorageDelete string $primary Вызывается после удаления хранилища.
События класса Element
OnBeforeElementAdd string $storage_id array $fields Вызывается перед добавлением элемента хранилища, может быть использовано для отмены или модификации данных.
OnAfterElementAdd string $storage_id string $primary array $fields Вызывается после добавления элемента хранилища.
OnBeforeElementUpdate string $storage_id string $primary array $fields Вызывается перед обновлением элемента хранилища, может быть использовано для отмены или модификации данных.
OnAfterElementUpdate string $storage_id string $primary array $fields Вызывается после обновления элемента хранилища.
OnBeforeElementDelete string $storage_id string $primary Вызывается перед удалением элемента хранилища.
OnAfterElementDelete string $storage_id string $primary Вызывается после удаления элемента хранилища.
События класса Property
OnBeforePropertyAdd array $fields Вызывается перед добавлением свойства, может быть использовано для отмены или модификации данных.
OnAfterPropertyAdd string $primary array $fields Вызывается после добавления свойства.
OnBeforePropertyUpdate string $primary array $fields Вызывается перед обновлением свойства, может быть использовано для отмены или модификации данных.
OnAfterPropertyUpdate string $primary array $fields Вызывается после обновления свойства.
OnBeforePropertyDelete string $primary Вызывается перед удалением свойства.
OnAfterPropertyDelete string $primary Вызывается после удаления свойства.
События класса Set
OnBeforeSetAdd array $fields Вызывается перед добавлением набора, может быть использовано для отмены или модификации данных.
OnAfterSetAdd string $primary array $fields Вызывается после добавления набора.
OnBeforeSetUpdate string $primary array $fields Вызывается перед обновлением набора, может быть использовано для отмены или модификации данных.
OnAfterSetUpdate string $primary array $fields Вызывается после обновления набора.
OnBeforeSetDelete string $primary Вызывается перед удалением набора.
OnAfterSetDelete string $primary Вызывается после удаления набора.

Для примера рассмотрим работу с событиями при добавлении элемента.

Пример 1: запретим добавлять в хранилище test_storage элементы с показателем сортировки меньше 100 через событие OnBeforeElementAdd

//можно добавить обработчик, например, в init.php
// запретим добавлять в хранилище test_storage элементы с показателем сортировки меньше 100 через событие OnBeforeElementAdd
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
	'simai.storage',
	'OnBeforeElementAdd',
	function (\Bitrix\Main\Event $event)
	{
		$storage_id = $event->getParameter('storage_id');
		$data = $event->getParameter('fields');
		//SUCCESS по умолчанию
		$result = new \Bitrix\Main\EventResult($event->getEventType(), array('fields' => $data));
		if ($storage_id == 'test_storage' && isset($data['SORT']))
		{
			if ($data['SORT'] < 100)
			{
				//ERROR
				$result = new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, new \Bitrix\Main\Error('No sorts less than 100!', 'SF_STORAGE_WRONG_ADD1'), 'simai.storage');
			}
		}
		return $result;
	}
);

Теперь если попробовать добавить в хранилище элемент с SORT<100, добавления не произойдет:

\SIMAI\Storage\Element::add(
	'test_storage', // код хранилища
	array(
		'ACTIVE'=>'Y', // активность элемента
		'SORT'=>'50', // показатель сортировки меньше 100
		'TYPE'=>'I', // это запись, а не раздел
	)
);
//Результат с ошибкой будет присутсвовать в массиве $GLOBALS['SF_STORAGE_ERRORS']

Пример 2: после добавления элемента запишем код хранилища и ид элемента в файл /upload/el.log

// после добавления элемента запишем код хранилища и ид элемента в файл /upload/el.log
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
	'simai.storage',
	'OnAfterElementAdd',
	function (\Bitrix\Main\Event $event)
	{
		$storage_id = $event->getParameter('storage_id');
		$primary = $event->getParameter('primary');
		$data = $event->getParameter('fields');

		if (@file_put_contents($_SERVER["DOCUMENT_ROOT"]."/upload/el.log", $storage_id.','.$primary))
		{
			//SUCCESS
			$result = new \Bitrix\Main\EventResult($event->getEventType(), array('fields' => $data));
		}
		else
		{
			//ERROR
			$result = new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, new \Bitrix\Main\Error('testerr', 'SF_STORAGE_WRONG_ADD2'), 'simai.storage');
		}

		return $result;
	}
);

Что касается классов первого уровня, то к ним можно применять стандартные события Bitrix\Main\Entity\DataManager для соответсвующих сущностей.

Изменить статью