Skip to content

Orm

Orm - Object-relational mapping - Объектно-реляционное отображение - технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования. Другими словами Orm позволяет работать не с массивами данных (строками таблицы в БД), а с объектами. Подробнее про приемущества работы с объектами

База данных

 

С точки зрения realweb.api и bitrix каждый отдельный инфоблок представляет собой отдельную таблицу

Класс базы данных содержит основной запрос к БД. Класс должен реализовывать следующие методы:

Имеет ряд часто используемых методов:

  • public static function getObjectCollection(?Pagination $obNav = null): Collection - получение коллекции сущностей, параметры запроса передаются в объекте пагинации
  • public static function getObject(?Pagination $obNav = null): Entity - получение сущности, параметры запроса передаются в объекте пагинации
  • public static function getByPrimary($mPrimary): Entity - получение сущности по первичному ключу, если сущность не найдена возвратит новую сущность.
  • public static function getAll(?Pagination $obNav = null): array - получение массива данных из БД, параметры запроса передаются в объекте пагинации
  • public static function getRow(?Pagination $obNav = null): ?array - получение строки данных из БД в виде массива (или null), параметры запроса передаются в объекте пагинации

Запрос в БД

Метод получения запроса getQuery должен возвращать объект класса \Realweb\Api\Model\Orm\Query. Данный класс расширяет стандартный \Bitrix\Main\ORM\Query\Query и обладает дополнительными методами (для удобства составления запросов)

  • public function registerFileField(string $field, bool $withSize = false): self - Добавление в запрос пути к файлу
  • public function registerFileSizeField(string $strFieldName): self - Добавление в запрос пути к файлу с параметрами высоты и ширины
  • public function whereCustom(string $field, $value, string $condition = '='): self - Добавление условия равенства, в зависимости от входящих данных

Коллекция

Коллекция представляет собой экземпляр класса \Realweb\Api\Model\Data\Collection и необходим для хранения списка сущностей. Коллекция - контейнер для хранения массива объектов сущностей. Позволяет искать сущности по первичному (и не только) ключу. Каждая сущность должна обладать таким уникальным ключом (В общем случае ID)

В отличие от массива сущностей обладает рядом преимуществ: поиск по уникальному "ключу" (В большинстве случаев это ID), манипуляции со списком сущностей, также, как и массив итерабельна

Должна реализовывать метод public function addItem($obItem): self - добавление сущности в контейнер.

Имеет встроенные методы:

  • public function getByKey($strKey) - Поиск сущности по первичному ключу
  • public function deleteByKey($strKey): self - Удаление сущности по первичному ключу
  • public function count(): int - количество сущностей в контейнере
  • public function getCollection(): array - получение массива сущностей в коллекции
  • public function getKeys(): array - получение уникальных ключей сущностей
  • public function current() - текущий элемент коллекции
  • public function toJson(): array - последовательно вызывает метод toJson, складывает результат в массив и возвращает его

Также, может иметь магические методы toJson*. В таком случае, класс сущности в коллекции также должен реализовывать этот метод.

Для операции с сущностями внутри коллекции (например, получение каких либо связанных с каждой сущностью данных) стоит использовать методы process*

Пример
php
use Realweb\Api\Module\Catalog;

$obCollection = Catalog\Model\Section\Database::getObjectCollection($obNav);
$obCollection->processPoints();

class Collection extends \Realweb\Api\Model\Iblock\Section\Collection
{
	/**
	 * @return Entity[]
	 */
	public function getCollection(): array
	{
		return parent::getCollection();
	}

	public function getByKey($strKey): ?Entity
	{
		return parent::getByKey($strKey);
	}

	public function processPoints(): void
	{
		if ($this->count() > 0) {
			$obPoints = (new \Realweb\Api\Module\Points\Controller\ElementController())
				->setParam('iblock_section_ids', $this->getKeys())
				->getCollection()
			;
			foreach ($obPoints->getCollection() as $obPoint) {
				if ($obSection = $this->getByKey($obPoint->getIblockSectionId())) {
					$obSection->getElements()->addItem($obPoint);
				}
			}
		}
	}
}

Внимание!

Не стоит использовать контейнер и хранить в кеше коллекции с большим количество сущностей (~1000 и более)

Пример коллекции элементов

Таблицы

Для работы со своими таблицами (Или с таблицами битрикс, для которых еще нет orm представления в ядре битрикса) следует использовать класс \Realweb\Api\Model\Orm\DataManager.

Он наследуется от стандартного \Bitrix\Main\ORM\Data\DataManager, но обладает преимуществом простого и понятного сохранения структуры таблицы.

Таблица в БД синхронизируется с описанной в классе таблицы схемой. Новые поля появятся, удаленные исчезнут (вместе с созданными внешними ключами, если таковые были)

Для всех полей учитываются следующие методы:

  • configureSize - размер поля
  • configureNullable - возможность хранения null значения
  • configureDefaultValue - значение по умолчанию
  • configureAutocomplete - автокомплит поля (ID)
  • configurePrimary - первичный ключ

Для полей, у которых отсутствует метод configureSize можно указать новый параметр size

Пример
php

namespace Realweb\Api\Module\User\Model\Transaction;

use Realweb\Api\Model\Orm\DataManager;

/**
 * Class \Realweb\Api\Module\User\Model\Transaction\Table
 */
class Table extends DataManager
{
	public static function getTableName(): string
	{
		return 'realweb_user_transaction';
	}

	public static function getMap(): array
	{
		return array(
			(new \Bitrix\Main\Entity\IntegerField('ID'))
				->configurePrimary()->configureAutocomplete(),
			(new \Bitrix\Main\Entity\IntegerField('USER_ID_FROM')),
			(new \Bitrix\Main\Entity\IntegerField('USER_ID_TO')),
			(new \Bitrix\Main\Entity\DatetimeField('DATE_TIME')),
			(new \Bitrix\Main\Entity\IntegerField('AMOUNT')),
			(new \Bitrix\Main\Entity\TextField('MESSAGE')),
			(new \Bitrix\Main\Entity\StringField('CODE')),
			(new \Bitrix\Main\Entity\StringField('PHONE')),
			(new \Bitrix\Main\Entity\IntegerField('SUCCESS')),

			((new \Bitrix\Main\ORM\Fields\Relations\Reference(
				'USER_FROM',
				\Realweb\Api\Model\User\Table\UserTable::class,
				\Bitrix\Main\ORM\Query\Join::on('this.USER_ID_FROM', 'ref.ID')
			))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)),
			((new \Bitrix\Main\ORM\Fields\Relations\Reference(
				'USER_TO',
				\Realweb\Api\Model\User\Table\UserTable::class,
				\Bitrix\Main\ORM\Query\Join::on('this.USER_ID_TO', 'ref.ID')
			))->configureJoinType(\Bitrix\Main\ORM\Query\Join::TYPE_LEFT)),
		);
	}

	public static function query(): \Realweb\Api\Model\Orm\Query
	{
		return new \Realweb\Api\Model\Orm\Query(static::getEntity());
	}
}
Сохранение(обновление) таблицы
php
\Realweb\Api\Module\User\Model\Transaction\Table::saveTable();

Пример таблицы

Индексы

Для того чтобы добавить индекс, необходимо зарегистрировать в таблице поле с классом \Realweb\Api\Model\Orm\Field\Index. Индексы могут быть по одному или по нескольким полям

Пример
php
public static function getMap(): array
{

	return array(
		(new \Bitrix\Main\ORM\Fields\IntegerField('ID'))
			->configurePrimary()
			->setParameter(self::PARAM_SIZE, 11)
			->configureAutocomplete(),
		(new \Bitrix\Main\ORM\Fields\DatetimeField('DATE_CREATE')),
		(new \Bitrix\Main\ORM\Fields\DatetimeField('DATE_EXEC')),
		(new \Bitrix\Main\ORM\Fields\StringField('NAME'))->configureSize(255),
		(new \Bitrix\Main\ORM\Fields\IntegerField('STATUS'))
			->setParameter(self::PARAM_SIZE, 1),
		(new \Bitrix\Main\ORM\Fields\IntegerField('ELEMENT_ID')),
		(new \Realweb\Api\Model\Orm\Field\Index('STATUS_ELEMENT_ID')) 
			->addField("STATUS") 
			->addField("ELEMENT_ID"), 
	);
}

Внешние ключи

Для того чтобы указать внешний ключ для поля, необходимо зарегистрировать в таблице поле с классом \Realweb\Api\Model\Orm\Field\ForeignKey и указать необходимые параметры.

  • setTableName - название таблицы для связи
  • setField - название поля текущей таблицы
  • setTableField - название поля в связываемой таблице
  • setOnDelete - поведение при удалении
Пример
php
public static function getMap(): array
{
	return array(
			(new \Bitrix\Main\ORM\Fields\IntegerField('ID'))
				->configurePrimary()
				->setParameter(self::PARAM_SIZE, 11)
				->configureAutocomplete(),
			(new \Bitrix\Main\ORM\Fields\DatetimeField('DATE_CREATE')),
			(new \Bitrix\Main\ORM\Fields\DatetimeField('DATE_EXEC')),
			(new \Bitrix\Main\ORM\Fields\StringField('NAME'))->configureSize(255),
			(new \Bitrix\Main\ORM\Fields\IntegerField('STATUS'))
				->setParameter(self::PARAM_SIZE, 1),
			(new \Bitrix\Main\ORM\Fields\IntegerField('ELEMENT_ID')),
			(new \Realweb\Api\Model\Orm\Field\ForeignKey('ELEMENT_ID_BITRIX')) 
				->setTableName(\Bitrix\Iblock\ElementTable::getTableName()) 
				->setField("ELEMENT_ID") 
				->setTableField("ID") 
				->setOnDelete(\Realweb\Api\Model\Orm\Field\ForeignKey::ON_DELETE_CASCADE), 
		);
}