Проблема большинства проектов заключается в отсутствии ясности. Я хочу показать как потратив немного времени можно внести эту ясность. Давайте разберем структуру компонента, которую я предлагаю использовать в проекте BoolRental и способ работы с сущностями.
Стандартный датаменеджер предоставляет исчерпывающий функционал для работы с сущностями, но мне не нравится, что объект сущности не является таковым в классическом смысле.
Я предпочитаю работать с элементами предметной области в явном виде, классы таблиц использовать в качестве репозиториев, а операции вставки, обновления и удаления поручить менеджеру управления сущностями.
Шаг 1 создание сущностей
Как сказано выше, я предпочитаю работать с конкретными объектами, название и свойства которых соответствуют элементам предметной области и не содержат ничего лишнего.
Рассмотрим структуру файлов компонента с которой будем работать:
- local/php_interface/classes/Aclips/BookRental/
-- Entity
---- Element.php
---- ...
- Internal
---- ElementTable.php
---- ...
В директории Entity хранятся классы сущностей;
В Internal — классы, описывающие таблицы сущностей.
Файлам из директории Internal была посвящена предыдущая статья, а вот содержимое Entity я хочу показать на примере сущности «издание»
<?php
namespace Aclips\BookRental\Entity;
/**
* Class Edition
* Сущность Издание
* @package Aclips\BookRental\Entity
*/
class Edition
{
/**
* Идентификатор издания
* @var int|null
*/
public ?int $id = null;
/**
* Название издания
* @var string|null
*/
public ?string $name = null;
/**
* Год публикации
* @var int|null
*/
public ?integer $publishingYear = null;
/**
* Идентификатор издательства
* @var int|null
*/
public ?integer $publishingHouseId = null;
/**
* Идентификатор жанра
* @var int|null
*/
public ?int $genreId = null;
/**
* Идентификатор файла обложки
* @var int|null
*/
public ?int $bookCoverId = null;
/**
* Описание издания
* @var string|null
*/
public ?string $description = null;
}Обновлённое описание EditionTable.php
<?php
namespace Aclips\BookRental\Internal;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields\IntegerField;
use Bitrix\Main\ORM\Fields\StringField;
use Bitrix\Main\ORM\Fields\TextField;
class EditionTable extends DataManager
{
public static function getTableName()
{
return "a_bookrental_editions";
}
public static function getMap()
{
return [
(new IntegerField('ID'))
->configurePrimary()
->configureAutocomplete(),
(new StringField('NAME'))
->configureRequired(),
(new IntegerField('PUBLISHING_YEAR'))
->configureRequired(),
(new IntegerField('PUBLISHING_HOUSE_ID'))
->configureRequired(),
(new IntegerField('GENRE_ID'))
->configureRequired(),
(new IntegerField('BOOK_COVER_ID')),
(new TextField('DESCRIPTION')),
];
}
}
Шаг 2 установка bitrix-entity-manager
В качестве менеджера управления сущностями я использую библиотеку enoffspb/bitrix-entity-manager, разработанную совместно с коллегой по цеху.
На момент написания статьи библиотеку еще не добавили в composer. Установка из github репозитория через composer выглядит следующим образом:
Файл local/php_interface/composer.json
{
"name": "aclips/bookRental",
"type": "project",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/enoffspb/bitrix-entity-manager"
}
],
"require": {
"enoffspb/bitrix-entity-manager": "dev-main"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
}
}UPD библиотека добавлена в composer
{
"name": "aclips/bookRental",
"type": "project",
"require": {
"enoffspb/bitrix-entity-manager": "dev-main"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
}
}Устанавливаем пакеты в директории local/php_interface
composer install
или
php ./composer.phar install
в зависимости от того, как был установлен composer.
Установка через composer: пакет enoffspb/bitrix-entity-manager (версия dev-main)
Шаг 3 конфигурирование проекта
Сущности готовы, репозитории созданы, EntityManager установлен. Теперь нужно все это собрать воедино.
Чтобы не собирать конфигурационный массив и не создавать объект EntityManager в коде всякий раз, когда нам потребуется выполнить какую-либо операцию над сущностью я создам функцию, я оберну весь процесс в функцию и буду обращаться к ней.
use enoffspb\BitrixEntityManager\EntityManagerInterface;
use enoffspb\BitrixEntityManager\BitrixEntityManager;
/**
* Получение EntityManager для работы с сущностями BookRental
* @return BitrixEntityManager
*/
function getlEntityManager(): EntityManagerInterface
{
$entitiesConfig = [
\Aclips\BookRental\Entity\Edition::class => [
'tableClass' => \Aclips\BookRental\Internal\EditionTable::class,
],
];
$config['entitiesConfig'] = $entitiesConfig;
return new BitrixEntityManager($config);
}Начиная с версии 20.5.400 в bitrix24 появился сервис локатор, который идеально подходит для инициализации сервисов, в т.ч. менеджера управления сущностями.
В статье «Как я настраиваю проект после установки» я упоминал про регистрацию служб в сервис локаторе при рассмотрении структуры директории php_interface.
В нашем случае файл kernel.php примет следующий вид:
<?php
use Bitrix\Main\DI\ServiceLocator;
if (class_exists('\Bitrix\Main\DI\ServiceLocator')) {
$serviceLocator = ServiceLocator::getInstance();
$serviceLocator->addInstanceLazy('aclips.bookrental.entityManager', [
'constructor' => static function () use ($serviceLocator) {
$entitiesConfig = [
\Aclips\BookRental\Entity\Edition::class => [
'tableClass' => \Aclips\BookRental\Internal\EditionTable::class,
],
];
$config['entitiesConfig'] = $entitiesConfig;
return new \enoffspb\BitrixEntityManager\BitrixEntityManager($config);
}
]);
}
Проверим, что все в порядке на примере создания нового элемента
use Bitrix\Main\DI\ServiceLocator;
use Aclips\BookRental\Entity\Edition;
$serviceLocator = ServiceLocator::getInstance();
// Получение сервиса
$entityManager = $serviceLocator->get('aclips.bookrental.entityManager');
// Создание объекта "издание"
$edition = new Edition();
// Заполняем свойства объекта
$edition->name = 'Котенок Шмяк и большая тыква';
$edition->publishingYear = 2020;
$edition->publishingHouseId = 1;
$edition->genreId = 3;
$edition->description = 'Приключения котёнка Шмяка...';
// Сохранение в базу
if($entityManager->save($edition)) {
// Получаем объект из репозитория
$processRepository = $entityManager->getRepository(Edition::class);
$smyakEdition = $processRepository->getById($edition->id);
print "Название публикации: ".$smyakEdition->name;
// Название публикации: Котенок Шмяк и большая тыква
}Порядок!
При дальнейшей работе над проектом всегда будет ясно о чем идёт речь. Мы избавились в коде от операций над сущностями через DataManager, делегировав их менеджеру управления сущностями, сделали сущности удобными и понятными, благодаря чему сигнатуры будут определены строже.