Примеры

В данном разделе приведены некоторые типовые примеры работы 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 для соответсвующих сущностей.