Custom ORM Model (bookTable) - uniqcle/Bitrix GitHub Wiki
Сущность
- совокупность коллекции объектов, с присущей базовой низкоуровневой логикой. 1 сущность описывает одну таблицу в БД и связь с другими сущностями.
Type's Fields
DataField // Дата
DatetimeField // Дата и время
BooleanField // true/false
IntegerField // Целое число
FloatField // Число
EnumField // Значение из списка
StringField // Строка
TextField // Текст
SqlExpression
$result = BookTable::update(1, array(
'NAME' => 'Книга для теста измененная1',
//'WRITE_COUNT' => new \Bitrix\Main\DB\SqlExpression('?# +1', 'WRITE_COUNT')
// 'WRITE_COUNT' => new \Bitrix\Main\DB\SqlExpression( 'NOW()' )
));
1. Creating Entity Class (BookTable)
local/modules/uniqcle.d7/lib/book.php
namespace Uniqcle\D7;
use \Bitrix\Main\Entity;
use \Bitrix\Main\Type;
class BookTable extends Entity\DataManager
{
public static function getTableName(){
return 'b_book';
}
// Возвращает имя подключения к БД
/*public static function getConnectionName(){
return 'localhost';
}*/
public static function getMap(){
return array(
//ID
new Entity\IntegerField('ID', array(
'primary' => true,
'autocomplete' => true
)),
// Название
new Entity\StringField('NAME', array(
'required' => true
)),
// Год выхода
new Entity\IntegerField('RELEASED', array(
'required' => true
)),
// ISBN
new Entity\StringField('ISBN', array(
'required' => true,
'column_name' => 'ISBNCODE',
'validation' => function() {
return array(
new Entity\Validator\Unique,
function ($value, $primary, $row, $field) {
// value - значение поля
// primary - массив с первичным ключом, в данном случае [ID => 1]
// row - весь массив данных, переданный в ::add или ::update
// field - объект валидируемого поля - Entity\StringField('ISBN', ...)
$clean = str_replace(array('-',' '), '', $value);
if (preg_match('/^\d{1,13}$/', $clean)){
return true;
} else {
return 'Код ISBN должен содержать не более 13 цифр, разделенных дефисом или пробелами';
}
}
);
}
)),
// ФИО Автора
new Entity\StringField('AUTHOR'),
// Дата и время поступления книги в магазин
new Entity\DatetimeField('TIME_ARRIVAL', array(
'required' => true,
'default_value' => new Type\DateTime
)),
// Описание книги
new Entity\TextField('DESCRIPTION'),
// Сколько лет книги
new Entity\ExpressionField('AGE_YEAR',
'YEAR(CURDATE())-%s', array('RELEASED')
)
);
}
// Регистрация обработчика при установке модуля
public static function onBeforeUpdate(Entity\Event $event)
{
$result = new Entity\EventResult;
$data = $event->getParameter("fields");
if (isset($data['ISBN'])) {
$result->addError(new Entity\FieldError(
$event->getEntity()->getField('ISBN'),
'Запрещено менять ISBN код у существующих книг'
));
}
return $result;
}
}
2. Creating DB Table/ Drop Table
local/modules/uniqcle.d7/install/index.php
...
function InstallDB($install_wizard = true){
Loader::includeModule($this->MODULE_ID);
//Проверяем существует ли таблица в БД
if(!Application::getConnection()-> // В качестве параметра может быть \Academy\D7\BookTable::getConnectionName()
isTableExists( Base::getInstance('\Uniqcle\D7\BookTable')->getDBTableName() )){
Base::getInstance('\Uniqcle\D7\BookTable')->createDbTable(); // При описании ORM-сущности, создает таблицу в БД
}
}
function UnInstallDB($arParams = Array()){
Loader::includeModule($this->MODULE_ID);
Application::getConnection()-> // В качестве параметра \Academy\D7\BookTable::getConnectionName()
queryExecute('drop table if exists '.Base::getInstance('\Uniqcle\D7\BookTable')->getDBTableName());
Option::delete($this->MODULE_ID);
}
...
function var1()
{
$result = BookTable::add(array(
'NAME' => 'Название книги',
'RELEASED' => '2020',
'ISBN' => '978-0321127426',
'AUTHOR' => 'ФИО',
'TIME_ARRIVAL' => new Type\DateTime('04.09.2015 00:00:00'),
'DESCRIPTION' => 'Описание книги'
));
return $result;
}
\Uniqcle\D7\BookTable::add()
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmAdd extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('UNIQCLE_D7_MODULE_NOT_INSTALLED'));
}
//Корректное добавление записи
function var1()
{
$result = BookTable::add(array(
'NAME' => 'Книга для теста',
'RELEASED' => '2002',
'ISBN' => '978-0321127426',
'AUTHOR' => 'Сергей Покоев',
'TIME_ARRIVAL' => new Type\DateTime('04.09.2015 00:00:00'),
'DESCRIPTION' => 'тестовый текст
вторая строчка'
));
return $result;
}
//Добавление записи без обязательного поля "Название".
function var2()
{
$result = BookTable::add(array(
'RELEASED' => '2002',
'ISBN' => '978-0321127426',
'AUTHOR' => 'Сергей Покоев',
'TIME_ARRIVAL' => new Type\DateTime('04.09.2015 00:00:00'),
'DESCRIPTION' => 'тестовый текст
вторая строчка'
));
return $result;
}
//Добавление записи без указания поля, для которого установлено значение по умолчанию
function var3()
{
$result = BookTable::add(array(
'NAME' => 'Книга для теста',
'RELEASED' => '2002',
'ISBN' => '978-0321127426',
'AUTHOR' => 'Сергей Покоев',
'DESCRIPTION' => 'тестовый текст
вторая строчка'
));
return $result;
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
//все верно
$result = $this->var1();
//Не указал обязательное поле: название
//$result = $this->var2();
//Добавление используя поле по умолчанию.
//$result = $this->var3();
if ($result->isSuccess())
{
$id = $result->getId();
$this->arResult='Запись добавлена с id: '.$id;
}
else
{
$error=$result->getErrorMessages();
$this->arResult='Произошла ошибка при добавлении: <pre>'.var_export($error,true).'</pre>';
}
$this->includeComponentTemplate();
}
}
//Обновление записи. Обновляется только название. (нужно указать верный id)
$result = BookTable::update(1, array(
'NAME' => 'Книга для теста измененная',
));
\Uniqcle\D7\BookTable::update()
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmUpdate extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('UNIQCLE_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
//Обновление записи. Обновляется только название. (нужно указать верный id)
$result = BookTable::update(1, array(
'NAME' => 'Книга для теста измененная',
));
return $result;
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$result = $this->var1();
if ($result->isSuccess())
{
$id = $result->getId();
$this->arResult='Запись изменена с id: '.$id;
}
else
{
$error=$result->getErrorMessages();
$this->arResult='Произошла ошибка при изменении: <pre>'.var_export($error,true).'</pre>';
}
$this->includeComponentTemplate();
}
}
//Удаление записи (нужно указать верный id)
return BookTable::delete(1);
\Uniqcle\D7\BookTable::delete()
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmDelete extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('UNIQCLE_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
//Удаление записи (нужно указать верный id)
$result = BookTable::delete(1);
return $result;
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$result = $this->var1();
if ($result->isSuccess())
{
// Не можем узнать id удаленного элемента
$this->arResult='Запись была удалена';
}
else
{
$error=$result->getErrorMessages();
$this->arResult='Произошла ошибка при удалении: <pre>'.var_export($error,true).'</pre>';
}
$this->includeComponentTemplate();
}
}
BookTable::getList(array(
'select' => ... // имена полей, которые необходимо получить в результате
'filter' => ... // описание фильтра для WHERE и HAVING
'group' => ... // явное указание полей, по которым нужно группировать результат
'order' => ... // параметры сортировки
'limit' => ... // количество записей
'offset' => ... // смещение для limit
'runtime' => ... // динамически определенные поля
));
Выборка getList из BookTable
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetlist extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
$result = BookTable::getList(array(
'select' => array('ID','NAME_BOOK' =>'NAME', 'AUTHOR'), // имена полей, которые необходимо получить в результате
'filter' => array(), // описание фильтра для WHERE и HAVING
//'group' => array(), // явное указание полей, по которым нужно группировать результат
'order' => array('ID'=>'DESC'), // параметры сортировки
'limit' => 3, // количество записей
'offset' => 2, // смещение для limit
));
return $result;
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$result = $this->var1();
//Вариант 1 получения данных
/*while ($row = $result->fetch())
{
$this -> arResult[] = $row;
}*/
//Вариант 2 получения данных
$this -> arResult = $result->fetchAll();
$this->includeComponentTemplate();
}
}
runtime
динамически определяемое поле
Выборка с добавлением runtime
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetlistExpression extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('UNIQCLE_D7_MODULE_NOT_INSTALLED'));
}
// Динамический подсчет элементов и занесение в CNT
function var1()
{
$result = BookTable::getList(array(
'select' => array('CNT'),
'runtime' => array(
new Main\Entity\ExpressionField('CNT', 'COUNT(*)')
),
));
return $result->fetch();
}
// Подсчет кол-ва элементов. Более короткая запись
function var2()
{
$result = BookTable::getList(array(
'select' => array(
new Main\Entity\ExpressionField('CNT', 'COUNT(*)')
),
));
return $result->fetch();
}
// К сущености добавляется поле, как будтно оно было описано изначально в getMap().
// Добавить нужно в БД.
function var3()
{
$result = BookTable::getList(array(
'select' => array(
'ID','NAME', 'ACTIVITY'
),
'filter' => array('ACTIVITY' => 1),
'runtime' => array(
new Main\Entity\IntegerField('ACTIVITY'),
)
));
return $result->fetchAll();
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
//$this -> arResult = $this->var1();
//$this -> arResult = $this->var2();
$this -> arResult = $this->var3();
$this->includeComponentTemplate();
}
}
еще пример
$resOrder = Bitrix\Sale\OrderTable::getList(
array(
'filter' => array('=USER_ID' => 1),
'group' => array('PAYED'),
'runtime' => array(
new Bitrix\Main\Entity\ExpressionField('IDS', 'GROUP_CONCAT(%s)', array('ID')),
),
)
);
Standart Methods
$dbItems->fetch(); // или $dbItems->fetchRaw() получение одной записи, можно перебрать в цикле while ($arItem = $dbItems->fetch())
$dbItems->fetchAll(); // получение всех записей
$dbItems->getCount(); // кол-во найденных записей без учета limit, доступно если при запросе было указано count_total = 1
$dbItems->getSelectedRowsCount(); // кол-во полученных записей с учетом limit
getById($id)
выборка по первичному ключу
return BookTable::getById(7);
// или так
$result = BookTable::getList(array(
'filter' => array('=ID' => $id)
));
$row = $result->fetch();
getById($id)
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetbyid extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
// Выборка записи по id
return BookTable::getById(7);
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$this -> arResult = $this->var1()->fetch();
$this->includeComponentTemplate();
}
}
getByPrimary(array('ID' => $id))
в обоих методах мы можем как передатьid
в виде числа, так и явно указать какой элемент является ключом, передав массив. Массив необходимо использовать, если у вас есть несколькоprimary
полей. Если вы передаете в массиве элемент, который не является первичным ключом, то это будет ошибкой.
// Аналогичен выборке по id, но может выбирать динамические поля
return BookTable::getByPrimary(array('ID' => 7));
// аналогичны следующему вызову getList:
BookTable::getList(array(
'filter' => array('=ID' => 7)
));
getByPrimary($id)
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetbyid extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
// Аналогичен выборке по id, но может выбирать динамические поля
return BookTable::getByPrimary(array('ID' => 7));
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$this -> arResult = $this->var1()->fetch();
$this->includeComponentTemplate();
}
}
getRowById($id)
Возвращает массив
$row = BookTable::getRowById($id);
// аналогичный результат можно получить так:
$result = BookTable::getById($id);
$row = $result->fetch();
// или так
$result = BookTable::getList(array(
'filter' => array('=ID' => $id)
));
$row = $result->fetch();
getRowById($id)
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetbyid extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
// Выборка записи по id, возвращаем массив. fetch можно не использовать
return BookTable::getRowById(7);
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$this -> arResult = $this->var1();
$this->includeComponentTemplate();
}
}
getRow()
; производит выборку не по первичному ключу, а по каким-то другим параметрам. При этом возвращается только одна запись.
return BookTable::getRow(array(
'filter' => array('%=ISBN' => '978-032112261'),
'order' => array('ID')
));
// аналогичный результат можно получить так:
$result = BookTable::getList(array(
'filter' => array('%=TITLE' => 'Patterns%'),
'order' => array('ID')
'limit' => 1
));
$row = $result->fetch();
getRow()
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmGetbyid extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
// При этом возвращается только одна запись- массив
return BookTable::getRow(array(
'filter' => array('%=ISBN' => '978-032112261'),
'order' => array('ID')
));
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$this -> arResult = $this->var1();
$this->includeComponentTemplate();
}
}
Удобно если необходимо собрать запрос из разных частей.
Список методов Bitrix\Main\Entity\Query
setSelect(), setGroup() — устанавливает массив с именами полей
addSelect(), addGroup() — добавляет имя поля
getSelect(), getGroup() — возвращает массив с именами полей
setFilter() — устанавливает одно- или многомерный массив с описанием фильтра
addFilter() — добавляет один параметр фильтра со значением
getFilter() — возвращает текущее описание фильтра
setOrder() — устанавливает массив с именами полей и порядком сортировки
addOrder() — добавляет одно поле с порядком сортировки
getOrder() — возвращает текущее описание сортировки
setLimit(), setOffset() — устанавливает значение
getLimit(), getOffset() — возвращает текущее значение
registerRuntimeField() — регистрирует новое временное поле для исходной сущности
$q = new Main\Entity\Query(BookTable::getEntity()); // Экземпляр класса query. В конструктор эзекмпляр класса ORM сущности
$q->setSelect(array( // поля выборки
'ID',
'NAME_BOOK' =>'NAME',
'AGE_YEAR',
'WRITE_COUNT')
);
$q->setFilter(array( // описание фильтра для WHERE и HAVING
'WRITE_COUNT' => 0
)
);
$q->setOrder(array('ID'=>'DESC')); // параметры сортировки
$q->setLimit(3); // количество записей
$q->setOffset(2); // смещение для limit
$result = $q->exec();
return $result->fetchAll();
Main\Entity\Query
use \Bitrix\Main;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type;
use \Uniqcle\D7\BookTable;
class d7OrmQuery extends CBitrixComponent
{
/**
* проверяет подключение необходиимых модулей
* @throws LoaderException
*/
protected function checkModules()
{
if (!Main\Loader::includeModule('uniqcle.d7'))
throw new Main\LoaderException(Loc::getMessage('ACADEMY_D7_MODULE_NOT_INSTALLED'));
}
function var1()
{
$q = new Main\Entity\Query(BookTable::getEntity()); // Экземпляр класса query. В конструктор эзекмпляр класса ORM сущности
$q->setSelect(array( // поля выборки
'ID',
'NAME_BOOK' =>'NAME',
'WRITE_COUNT')
);
$q->setFilter(array( // описание фильтра для WHERE и HAVING
'WRITE_COUNT' => 0
)
);
$q->setOrder(array('ID'=>'DESC')); // параметры сортировки
$q->setLimit(3); // количество записей
$q->setOffset(2); // смещение для limit
$result = $q->exec();
return $result->fetchAll();
}
public function executeComponent()
{
$this -> includeComponentLang('class.php');
$this -> checkModules();
$this -> arResult = $this->var1();
$this->includeComponentTemplate();
}
}
В методе
getMap()
при создании сущности, добавляем параметрvalidation
standard validators
Entity\Validator\RegExp
– check by regular expression,
Entity\Validator\Length
– check the minimum/maximum line length,
Entity\Validator\Range
– check the minimum/maximum number value,
Entity\Validator\Unique
– check the uniqueness of a value.
// ISBN
new Entity\StringField('ISBN', array(
'required' => true,
'column_name' => 'ISBNCODE',
'validation' => function() {
return array(
new Entity\Validator\Unique,
);
}
)),
И при добавлении элемента выдает ошибку
string(203) "Произошла ошибка при добавлении:
array (
0 => 'Запись со значением "ISBN", равным "000000001", уже есть в базе данных',
)
Свой валидатор с возвращаемой callback-функцией
...
// ISBN
new Entity\StringField('ISBN', array(
'required' => true,
'column_name' => 'ISBNCODE',
'validation' => function() {
return array(
new Entity\Validator\Unique,
function ($value, $primary, $row, $field) {
// value - значение поля
// primary - массив с первичным ключом, в данном случае [ID => 1]
// row - весь массив данных, переданный в ::add или ::update
// field - объект валидируемого поля - Entity\StringField('ISBN', ...)
$clean = str_replace(array('-',' '), '', $value);
if (preg_match('/^\d{1,13}$/', $clean)){
return true;
} else {
return 'Код ISBN должен содержать не более 13 цифр, разделенных дефисом или пробелами';
}
}
);
}
)),
...