В этой статье мы разберём, как создать собственный провайдер данных для UI Entity Selector в Битрикс24 и подключить его к штатному компоненту без использования REST API. Это позволит выводить нужные вам сущности — например, компании-партнёры из CRM — прямо в диалоговых окнах.
1. Структура модуля
Для начала создадим модуль в папке /local/modules/custom.provider
. Организуем внутри следующую файловую структуру:
custom.provider/
├── install/
│ └── index.php
├── lib/
│ └── Provider/
│ └── PartnersCompanyProvider.php
├── .settings.php
└── include.php
2. Файл install/index.php
В файле install/index.php
опишем регистрацию и удаление модуля:
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
class custom_provider extends CModule
{
public $MODULE_ID = 'custom.provider';
public $MODULE_VERSION;
public $MODULE_VERSION_DATE;
public $MODULE_NAME;
public $MODULE_DESCRIPTION;
public function __construct()
{
$this->MODULE_NAME = 'Кастомный провайдер данных';
$this->MODULE_DESCRIPTION = 'Модуль для регистрации кастомного провайдера UI Entity Selector';
}
public function DoInstall()
{
RegisterModule($this->MODULE_ID);
return true;
}
public function DoUninstall()
{
UnRegisterModule($this->MODULE_ID);
return true;
}
}
3. Провайдер PartnersCompanyProvider
В классе lib/Provider/PartnersCompanyProvider.php
реализуем логику выборки компаний-партнёров из CRM:
<?php
namespace Provider;
use Bitrix\Main\Loader;
use Bitrix\UI\EntitySelector\BaseProvider;
use Bitrix\UI\EntitySelector\Dialog;
use Bitrix\UI\EntitySelector\Item;
use Bitrix\UI\EntitySelector\SearchQuery;
use Bitrix\Crm\CompanyTable;
use Bitrix\UI\EntitySelector\Tab;
use Exception;
/**
* Class PartnersCompanyProvider
*
* Провайдер для выбора компаний-партнёров из CRM.
*
* @package Provider
*/
class PartnersCompanyProvider extends BaseProvider
{
/**
* Лимит выборки компаний.
*/
protected const LIMIT = 20;
/**
* Конструктор класса.
*
* @param array $options Опции для провайдера (например, onlyWithEmail и filter).
*/
public function __construct(array $options = [])
{
$this->options = $options;
parent::__construct();
}
/**
* Проверяет доступность провайдера.
*
* @return bool Возвращает true, если модуль crm подключен.
*/
public function isAvailable(): bool
{
return Loader::includeModule('crm');
}
/**
* Возвращает фильтр по наличию EMAIL.
*
* Если передана опция onlyWithEmail, возвращает фильтр, исключающий компании без EMAIL.
*
* @return array Массив фильтров.
*/
protected function getEmailFilter(): array
{
return ($this->options['onlyWithEmail'] ?? false)
? ['!EMAIL' => '']
: [];
}
/**
* Возвращает дополнительный фильтр, переданный в опциях.
*
* Например, 'filter' => ['UF_CRM_1739464513474' => 'Булочки'].
*
* @return array Массив дополнительных фильтров.
*/
protected function getAdditionalFilter(): array
{
return $this->options['filter'] ?? [];
}
/**
* Выполняет запрос к базе для получения списка компаний по заданному фильтру.
*
* @param array $filter Фильтр для запроса.
* @param array $order Порядок сортировки.
* @param int $limit Лимит выборки.
* @return array Список компаний.
*/
protected function fetchCompanies(array $filter, array $order = [], int $limit = self::LIMIT): array
{
try {
return CompanyTable::getList([
'filter' => $filter,
'select' => ['ID', 'TITLE', 'EMAIL'],
'limit' => $limit,
'order' => $order
])->fetchAll();
} catch (Exception $e) {
// При необходимости можно добавить логирование ошибки
return [];
}
}
/**
* Получает элементы по заданным идентификаторам.
*
* @param array $ids Список идентификаторов компаний.
* @return array Массив объектов Item.
*/
public function getItems(array $ids): array
{
$filter = array_merge(
['ID' => $ids],
$this->getEmailFilter(),
$this->getAdditionalFilter()
);
$companies = $this->fetchCompanies($filter);
$items = [];
foreach ($companies as $company) {
$items[] = $this->makeItem($company);
}
return $items;
}
/**
* Заполняет диалог выбора компаний.
*
* Добавляет вкладку и элементы компаний в диалог.
*
* @param Dialog $dialog Экземпляр диалога выбора.
* @return void
*/
public function fillDialog(Dialog $dialog): void
{
$dialog->addTab(new Tab([
'id' => 'custom_company',
'title' => 'Партнеры',
'stub' => true,
]));
$filter = array_merge(
$this->getEmailFilter(),
$this->getAdditionalFilter()
);
// Запрашиваем компании с сортировкой по ID в обратном порядке
$companies = $this->fetchCompanies($filter, ['ID' => 'DESC']);
foreach ($companies as $company) {
$dialog->addItem($this->makeItem($company));
}
}
/**
* Возвращает выбранные элементы по их идентификаторам.
*
* @param array $ids Список идентификаторов.
* @return array Массив объектов Item.
*/
public function getSelectedItems(array $ids): array
{
return $this->getItems($ids);
}
/**
* Выполняет поиск компаний и заполняет диалог результатами.
*
* Добавляет дефолтные элементы и найденные элементы в диалог.
*
* @param SearchQuery $searchQuery Объект запроса поиска.
* @param Dialog $dialog Экземпляр диалога выбора.
* @return void
*/
public function doSearch(SearchQuery $searchQuery, Dialog $dialog): void
{
// Добавляем дефолтные элементы
$this->fillDialog($dialog);
$filter = array_merge(
['%TITLE' => $searchQuery->getQuery()],
$this->getEmailFilter(),
$this->getAdditionalFilter()
);
$companies = $this->fetchCompanies($filter);
foreach ($companies as $company) {
$dialog->addItem($this->makeItem($company));
}
}
/**
* Создает объект Item для заданной компании.
*
* @param array $company Массив данных компании.
* @return Item Объект Item для диалога.
*/
protected function makeItem(array $company): Item
{
$companyId = (int)$company['ID'];
return new Item([
'id' => $companyId,
'entityId' => 'company',
'title' => $company['TITLE'],
'subtitle' => $company['EMAIL'] ?? '',
'linkTitle' => 'Подробнее',
'customData' => [
'id' => (string)$companyId,
'entityInfo' => $this->createEntityInfo($companyId, $company),
'email' => $company['EMAIL'] ?? '',
'entityId' => $companyId,
'entityType' => 'company',
'name' => $company['TITLE'],
],
'tagOptions' => [
'title' => $company['TITLE'] . ' (' . ($company['EMAIL'] ?? '') . ')'
],
'tabs' => [
'custom_company',
'mail_crm_recipient',
],
]);
}
/**
* Создает массив данных для entityInfo.
*
* @param int $companyId Идентификатор компании.
* @param array $company Массив данных компании.
* @return array Массив с информацией о компании.
*/
protected function createEntityInfo(int $companyId, array $company): array
{
return [
'id' => $companyId,
'type' => 'company',
'typeName' => 'COMPANY',
'typeNameTitle' => 'Компания',
'place' => 'company',
'hidden' => false,
'title' => $company['TITLE'],
'url' => "/crm/company/details/{$companyId}/",
'image' => "/bitrix/images/crm/entity_provider_icons/company.svg",
'permissions' => [
'canUpdate' => true,
],
];
}
}
4. Регистрация провайдера
Добавим файл .settings.php
для подключения нашего провайдера к UI Entity Selector:
<?php
return [
'ui.entity-selector' => [
'value' => [
'entities' => [
[
'entityId' => 'custom_company',
'provider' => [
'moduleId' => 'custom.provider',
'className' => '\\Provider\\PartnersCompanyProvider'
],
],
],
],
],
];
Инициализируем автозагрузку в include.php
:
<?php
\Bitrix\Main\Loader::registerAutoLoadClasses(
'custom.provider',
[
'\\Provider\\PartnersCompanyProvider' => 'lib/Provider/PartnersCompanyProvider.php',
]
);
5. Внедрение в компонент
Чтобы использовать провайдер в форме отправки e-mail, добавим в ваш шаблон скрипт /local/templates/components/bitrix/main.mail.form/templates/.default/script.js
:
entitiesDialog.push({
id: 'custom_company',
dynamicLoad: true,
dynamicSearch: true,
options: {
onlyWithEmail: true,
filter: {
'UF_CRM_1739464513474': 'Булочки'
}
}
});
Теперь при открытии диалога отправки письма появится вкладка «Партнёры», где будут показаны только те компании, у которых заполнён Email и задано пользовательское поле UF_CRM_1739464513474
со значением «Булочки».
