D7. ORM Вадим Думбравану руководитель проектов Object-relational mapping Недостатки текущего похода в API • На каждую сущность программируется свой GetList, Update, Add, Delete • Различающийся набор параметров • Разный синтаксис полей фильтров • События могут быть не предусмотрены • Разный код под разные БД (Add) Object-relational mapping Что мы хотим улучшить в ORM • Однотипные операции выборки и сохранения в БД для всех сущностей (параметры, фильтры, результаты) • Минимальное количество кода для новых сущностей • Стандартные события добавления/ изменения/ удаления Object-relational mapping Реализация • сущности (Bitrix\Main\Entity\Base) • поля сущностей (Bitrix\Main\Entity\Field и его наследники) • датаменеджер (Bitrix\Main\Entity\DataManager) use Bitrix\Main\Entity; class CultureTable extends Entity\DataManager { public static function getTableName() { return 'b_culture'; } public static function getMap() { return array( 'ID' => array( 'data_type' => 'integer', 'primary' => true, 'autocomplete' => true, Object-relational mapping Описание сущности • Название сущности состоит из собственно названия сущности и обязательного суффикса Table. • Класс должен быть наследован от Bitrix\Main\Entity\DataManager. • Должны быть перекрыты два абстрактных метода getFilePath() и getMap() • Метод getTableName() может быть определен и должен вернуть название таблицы. Если метод не определен, то базовая сущность попытается получить имя таблицы автоматически. Object-relational mapping Поля сущности • Поле имеет название (соответствует БД), тип и ряд атрибутов • Можно указать первичный ключ • Можно указать обязательность и маску • Поле может быть вычисляемым • Поле может быть ссылкой на другую сущность 'VAT_RATE_PRC' => array( 'data_type' => 'float', 'expression' => array( '100 * %s', 'VAT_RATE' ) ), 'ORDER' => array( 'data_type' => 'Order', 'reference' => array( '=this.ORDER_ID' => 'ref.ID' ) ), Object-relational mapping Датаменеджер • • • • • CultureTable::update($ID, $arFields) CultureTable::add($arFields) CultureTable:: delete ($ID) и наш любимый CultureTable::getList($arParams) есть также базовый checkFields(Result $result, array $data, $id = null) Все методы статические. Сущность может переопределить эти базовые методы, если это необходимо. Object-relational mapping Выборка данных • Статический метод getList() с массивом параметров: • • • • • • • 'select' – массив выбираемых в SELECT полей; 'filter' – массив условий фильтра для WHERE; 'group' – массив полей для группировки; 'order' – массив сортировки; 'limit' – ограничение количества записей; 'offset' – смещение начала выборки; 'count_total' – нужно ли считать количество записей • Метод возвращает объект CDBResult старого ядра. В ближайшем будущем метод будет возвращать объект нового ядра DbResult. Object-relational mapping Выборка данных $cultureList = CultureTable::getList(array( 'select' =>array('ID', 'NAME'), 'order' => array('NAME' =>'ASC'), 'filter'=>array('CHARSET'=>'Windows-1251'), )); • Сортировка может быть по нескольким полям. • Фильтр задается в расширенном синтаксисе, который применяется в инфоблоках. • Использование параметров, неизвестных методу, приведет к выбросу исключения. • Для выборки одной записи по первичному ключу может применяться метод getById() Object-relational mapping Выборка данных • Можно использовать цепочку вызовов методов объекта запроса вместо статического метода. $main_query = new Entity\Query(CultureTable::getEntity()); $main_query->setSelect(array('*')); $main_query->setFilter(array('=ID' => $arParams['ROW_ID'])); $row = $main_query->exec()->Fetch(); Object-relational mapping Модификация данных • Статические методы add(), update(), delete() • Вызывают соответствующие события. • Производят встроенную проверку полей сущностей, вызывая метод checkFields(). • Возвращают объекты типов Bitrix\Main\Entity\AddResult, UpdateResult и DeleteResult. Назначение этих объектов – сообщить об успешности операции и дать доступ к ошибкам. Object-relational mapping Проверка данных • Метод checkFields() проверяет поля на обязательные значения (атрибут поля сущности required) и соответствие маске (атрибут format). • Для дополнительных проверок класс сущности может переопределить этот метод. • В случае ошибки метод должен добавить ошибку в объект результата. Ошибка может быть либо общая для всей сущности, либо относиться к конкретному полю. $result->addError(new Entity\EntityError("Нельзя изменить запись номер 1.")); $result->addError(new Entity\FieldError('NAME', 'Поле «имя» очень странное.')); Object-relational mapping События • Датаменеджер при модификации данных отправляет события. • Названия событий строятся автоматически и имеют вид <КодСущности> On( Before|<пусто>| After)( Add| Update| Delete), например CultureOnBeforeDelete. • Отменить операцию могут только обработчики событий OnBefore. OnBeforeUpdate(array("id"=>$primary, "fields"=>$data)) checkFields() OnUpdate(array("id"=>$primary, "fields"=>$data)) update OnAfterUpdate(array("id"=>$primary, "fields"=>$data)) Спасибо за внимание! Вопросы?