← Назад к справке

Пользовательские действия

Файлы действия

Основные файлы пользовательского действия бизнес-процесса: .description.php, языковые файлы, класс действия, свойства, Execute и результаты.

Дизайнер бизнес-процессов берёт название, категорию и результаты из .description.php. Выполнение идёт через PHP-класс действия и метод Execute().

Описание действия

Файл .description.php нужен дизайнеру бизнес-процессов. Без него блок не появится в списке действий или появится некорректно.

Главный .description.php

В описании остаётся служебная переменная $arActivityDescription. Это ожидаемый формат Битрикса, поэтому здесь не нужно переименовывать её под общий стиль проекта.

<?php

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
    die();
}

$arActivityDescription = [
    'NAME' => 'CRM: расширенный поиск элемента',
    'DESCRIPTION' => 'Ищет первый элемент CRM или смарт-процесса с наименьшим ID по выбранным полям.',
    'TYPE' => 'activity',
    'CLASS' => 'CrmAdvancedFindActivity',
    'JSCLASS' => 'BizProcActivity',
    'CATEGORY' => [
        'ID' => 'document',
        'OWN_ID' => 'crm',
        'OWN_NAME' => 'CRM',
    ],
];
Ключ Назначение
NAME Название блока в дизайнере.
DESCRIPTION Короткое описание блока.
TYPE Обычно activity.
CLASS Имя класса без префикса CBP.
JSCLASS JS-класс дизайнера. Для обычного блока подходит BizProcActivity.
CATEGORY Раздел, где блок будет лежать в дизайнере.
RETURN Дополнительные результаты действия.

CATEGORY

Категория определяет место блока в дизайнере. Для CRM-действия логично держать его в CRM-разделе.

'CATEGORY' => [
    'ID' => 'document',
    'OWN_ID' => 'crm',
    'OWN_NAME' => 'CRM',
],

RETURN

RETURN описывает результаты, которые можно выбрать в следующих блоках бизнес-процесса.

'RETURN' => [
    'Found' => [
        'NAME' => 'Найден',
        'TYPE' => 'bool',
    ],
    'ItemId' => [
        'NAME' => 'ID найденного элемента',
        'TYPE' => 'int',
    ],
    'Count' => [
        'NAME' => 'Количество найденных элементов в выборке',
        'TYPE' => 'int',
    ],
    'ErrorText' => [
        'NAME' => 'Текст ошибки',
        'TYPE' => 'string',
    ],
],

В действии расширенного поиска есть дополнительные результаты ResultField01ResultField10. Они нужны, чтобы каждое выбранное поле было отдельным результатом, а не одним JSON.

for ($index = 1; $index <= 10; $index++) {
    $suffix = str_pad((string) $index, 2, '0', STR_PAD_LEFT);

    $arActivityDescription['RETURN']['ResultField' . $suffix] = [
        'NAME' => 'Выбранное поле ' . $suffix,
        'TYPE' => 'string',
    ];
}

Языковой файл

Название и описание можно вынести в lang/ru/.description.php. Для внутреннего блока это не обязательно, но структура получается чище.

<?php

$MESS['CRM_ADVANCED_FIND_NAME'] = 'CRM: расширенный поиск элемента';
$MESS['CRM_ADVANCED_FIND_DESC'] = 'Ищет первый элемент CRM или смарт-процесса с наименьшим ID по выбранным полям.';

Класс действия

Класс наследуется от CBPActivity. Основная логика находится в Execute().

arProperties

В arProperties задаются входные настройки и результаты. Название arProperties служебное, его не переименовывают.

class CBPCrmAdvancedFindActivity extends CBPActivity
{
    public const RESULT_FIELD_COUNT = 10;

    public function __construct($name)
    {
        parent::__construct($name);

        $this->arProperties = [
            'Title' => '',
            'EntityTypeId' => '',
            'ConditionsJson' => '[]',
            'SelectFields' => '',

            'Found' => false,
            'ItemId' => 0,
            'Count' => 0,
            'ErrorText' => '',
        ];
    }
}

Коды свойств должны совпадать с тем, что сохраняется в GetPropertiesDialogValues(). После запуска блока в шаблонах эти коды становятся частью настроек процесса.

Execute

Execute() запускается при выполнении блока. Метод должен вернуть CBPActivityExecutionStatus::Closed.

public function Execute()
{
    $this->clearRuntimeResults();

    try {
        if (!Loader::includeModule('crm')) {
            throw new RuntimeException('Не удалось подключить модуль crm.');
        }

        $entity_type_id = (int) $this->EntityTypeId;

        if ($entity_type_id <= 0) {
            throw new RuntimeException('Не выбран тип CRM-сущности.');
        }

        // Основная логика действия.
    } catch (Throwable $exception) {
        $this->Found = false;
        $this->ItemId = 0;
        $this->Count = 0;
        $this->ErrorText = $exception->getMessage();
    }

    return CBPActivityExecutionStatus::Closed;
}

В поисковом блоке ошибка не останавливает бизнес-процесс. Текст ошибки записывается в ErrorText, а дальше процесс сам решает, что делать с результатом.

Результаты выполнения

Результаты записываются в свойства объекта действия. После завершения блока их можно использовать в следующих действиях бизнес-процесса.

$this->Found = $first_item_id > 0;
$this->ItemId = $this->Found ? $first_item_id : 0;
$this->Count = $this->Found ? 1 : 0;
$this->ErrorText = '';

Выбранные поля раскладываются по результатам ResultField01, ResultField02 и дальше до заданного лимита.

$property_name = 'ResultField' . str_pad((string) $result_index, 2, '0', STR_PAD_LEFT);
$this->{$property_name} = (string) $value;

Ошибки

Для блоков, которые работают внутри реальных процессов, часто безопаснее вернуть ошибку как результат, а не валить весь процесс PHP-исключением.

catch (Throwable $exception) {
    $this->Found = false;
    $this->ItemId = 0;
    $this->Count = 0;
    $this->ErrorText = $exception->getMessage();
}

Источники