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