Действия
Table of Contents
Все, что исполняется в бизнес-процессе, является действием (по-другому активити
), а сам бизнес-процесс представляет собой набор вложенных действий. Каждое такое действие в рамках шаблона бизнес-процесса имеет уникальное имя.
С точки зрения кода действие — это php-класс, который наследуется от абстрактного класса CBPActivity
или его потомков. Его название класса должно начинаться с подстроки CBP
и может состоять из латинских букв и цифр.
Например:
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
class CBPMyActivity1
extends \CBPActivity
{
// . . .
}
В дистрибутиве по умолчанию есть несколько десятков различных действий (Activity
) для использования их в шаблонах бизнес-процессов.
Для любопытных рекомендуем изучить работу некоторых базовых действий для составления полной картины:
-
CBPCompositeActivity
- абстрактный базовый класс составных действий, т.е. действий, которые могут содержать в себе дочерние действия. -
CBPSequenceActivity
- Последовательно запускает набор дочерних действий. -
CBPCodeActivity
- самое простое действие - запускает на выполнение произвольный PHP-код. -
CBPSetVariableActivity
- устанавливает значения переменных бизнес-процесса. -
CBPDelayActivity
- Реализует ожидание, откладывая выполнение на определенный срок. -
CBPHandleExternalEventActivity
- Реализует действие, которое ожидает внешнее событие. Бизнес-процесс останавливается до получения данного внешнего события. -
CBPIfElseActivity
иCBPIfElseBranchActivity
- реализуют функционал условия и ветки условия. -
CBPWhileActivity
- Реализует функционал цикла. -
CBPListenActivity
- Реализует ожидание одного из нескольких возможных событий. Когда одно из событий происходит, остальные перестают ожидать событий и отменяются. -
CBPParallelActivity
- Параллельно запускает набор дочерних действий.
Несмотря на наличие большого количества поставляемых по-умолчанию действий иногда возникает потребность в создании собственных.
Классификация действий
С точки зрения выполнения бизнес-процесса каждое действие можно классифицировать на простые и комплексные. Комплексные (композитные) могут состоять из нескольких простых действий.
Дополнительно действия можно разделить по характеру выполнения на немедленные, задания и событийные.
- Немедленные - выполняются в рамках бизнес-процесса, не блокируют процесс выполнения в нормальном режиме работы.
- Событийные - выполняются, проверяют условие (необходимость) ожидания события, ставят процесс на паузу до наступления события или даты окончания ожидания.
- Задания - выполняются, останавливают свое выполнение до выполнения задания сотрудников или даты окончания ожидания.
По-умолчанию любое действие является немедленным.
Для того чтобы сделать действие событийным, оно должно реализовывать интерфейсы IBPEventActivity
и IBPActivityExternalEventListener
, о событийных действиях мы поговорим позже.
Задания в свою очередь можно рассматривать как событийное действие с дополнительными возможностями - нужно наследоваться от CBPCompositeActivity
, содержать дополнительные методы и реализовывать те же интерфейсы, что и событийная модель.
Создание своего действия
Свои действия располагаются в одной из директорий (перечислены в порядке приоритета от корня сайта):
-
/local/activities
-
/local/activities/custom
-
/bitrix/activities/custom
-
/bitrix/activities/bitrix
-
/bitrix/modules/bizproc/activities
Каждое действие располагается в отдельной директории и ее название должно совпадать с именем класса действия, но без первых символов CBP
. Кроме того имя директории должно быть записано строчными буквами (в нижнем регистре).
В директории действия могут располагаться и другие необходимые действию файлы: файл с описанием, локализация, изображения или ресурсы. Рассмотрим содержимое директории действия.
.description.php
В файле .description.php
описывается переменная $arActivityDescription
которая содержит мета-описание необходимое для корректной работы действия.
Пример:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();
$arActivityDescription = array(
"NAME" => GetMessage("MYACTIVITY_DESCR_NAME"),
"DESCRIPTION" => GetMessage("MYACTIVITY_DESCR_DESCR"),
"TYPE" => "activity",
"CLASS" => "MyActivity",
"JSCLASS" => "BizProcActivity",
"CATEGORY" => array(
"ID" => "other",
),
);
?>
Рассмотрим все возможные ключи массива $arActivityDescription
:
-
NAME
(string) - Локализованное название действия - отображается в списке действий, а так же в заголовке всплывающего окна настроек -
DESCRIPTION
(string) - Локализованное описание действия - отображается во всплывающем окне настроек -
TYPE
(string or array)- Тип действия. В случае условия может принимать толькоcondition
, в случае действия может быть либоactiviy
, либоrobot_activity
либо массивом из этих же элементов -
CLASS
(string) - название php-класса обработчика действия. Должен совпадать с названием директории -
JSCLASS
(string) - название js-класса обработчика действия. По-умолчаниюBizProcActivity
. -
CATEGORY
(array) - опциональное описание раздела для отображения в дизайнере БП в случаеTYPE=activity
-
ROBOT_SETTINGS
(array) - опциональное описание раздела для отображения в роботах в случаеTYPE=robot_activity
-
FILTER
(array) - структура описывающая условия отображения действия -
RETURN
(array) - структура описывающая возвращаемые значения -
ADDITIONAL_RESULT
(array) - набор из кодов свойств действия, возвращающихся как дополнительные значения, которые могут быть переданы в другие действия во время выполнения бизнес-процесса.
CATEGORY
Для размещения свое действия в дизайнере бизнес-процесса необходимо указать в каком разделе оно будет отображаться. Обычно разрабатываемые действия отображаются в категории “Другое”, что можно описать как:
'CATEGORY' => [
'ID' => 'other',
]
Это является минимально необходимым описанием для размещения действия в панели редактора шаблона бизнес-процесса.
Однако иногда бывает полезным создать собственный раздел. Для этого в категории необходимо указать еще несколько ключей: OWN_ID
(string) - симв. код нового раздела и OWN_NAME
(string) - отображаемое название раздела
Например, так:
'CATEGORY' => [
'ID' => 'own_super_group',
'OWN_ID' => 'own_super_group',
'OWN_NAME' => 'My own super group',
],
ROBOT_SETTINGS
Аналогично структуре CATEGORY
есть структура описывающая расположение карточки робота в интерфейсе выбора роботов:
'ROBOT_SETTINGS' => [
'GROUP' => ['elementControl'],
'SORT' => 2800,
],
Описание структуры:
-
GROUP
- набор групп в которых отображается робот. -
SORT
- приоритет отображения робота в группе.
Список доступных групп (на момент написания статьи):
-
clientCommunication
- Коммуникация с клиентом -
informingEmployee
- Информирование сотрудников -
employeeControl
- Контроль сотрудников -
paperwork
- Оформление документов -
payment
- Оплата товаров и услуг -
delivery
- Управление доставкой -
repeatSales
- Повторные продажи -
ads
- Запуск рекламы -
elementControl
- Управление элементом -
clientData
- Данные о клиентах -
taskManagement
- Управление задачами -
modificationData
- Хранение и изменение данных -
digitalWorkplace
- Автоматизация рабочих мест -
other
- Другие роботы
FILTER
Некоторые действия имеют смысл только в определенных документах, поэтому существует специальные ограничения для сокрытия и показа таких действий. За подобную работу отвечает ключ FILTER
, который может содержать 2 ключа:
-
INCLUDE
- описывает типы документов к которым применимо данное активити -
EXCLUDE
- описывает типы документов к не применимо данное активити
Например, разрешить действие только для шаблонов по сделкам:
"FILTER" => [
'INCLUDE' => [
['crm', 'CCrmDocumentDeal'],
]
],
RETURN
Действие может возвращать значения в ходе своего выполнения. Для описания возвращаемых значений в мета-описании действия необходимо использовать ключ RETURN
, содержащий структуры возвращаемых значений.
Например:
'RETURN' => [
'ElementId' => [
'NAME' => 'Displayed name for ElementId property',
'TYPE' => 'int',
],
'ErrorMessage' => [
'NAME' => 'Displayed name for Error message',
'TYPE' => 'string',
],
],
Доступные типы (TYPE
) возвращаемых значений описаны константами в классе Bitrix\Bizproc\FieldType
.
Например:
-
FieldType::BOOL
(bool
) -
FieldType::DATE
(date
) -
FieldType::DATETIME
(datetime
) -
FieldType::DOUBLE
(double
) -
FieldType::FILE
(file
) -
FieldType::INT
(int
) -
FieldType::SELECT
(select
) -
FieldType::INTERNALSELECT
(internalselect
) -
FieldType::STRING
(string
) -
FieldType::TEXT
(text
) -
FieldType::USER
(user
) -
FieldType::TIME
(time
)
Значения возвращаемые в
RESULT
без перечисления вADDITIONAL_RESULT
недоступны для использования в других действиях бизнес-процессов.
ADDITIONAL_RESULT
Возвращаемые значения действия (RESULT
) имеют ряд недостатков:
- Они должны быть объявлены явно, т.е. нет возможности динамически определять их состав
- Их нельзя использовать при настройке других действий бизнес-процессов
Чтобы избежать этой ситуации, разработчики добавили специальный ключ ADDITIONAL_RESULT
, содержащий перечисление кодов свойств действия, которые будут транслированы в дизайнер бизнес-процессов и могут быть использованы для вставки в параметры других действий через инструмент “Вставка значения”.
Пример использования в мета-файле:
'ADDITIONAL_RESULT' => [
'FieldsMap'
],
В самом FieldsMap
должен содержаться ассоциативный массив, в качестве ключей которого должны выступать свойства действия, а значениями - описание типа значения.
В качестве примера рассмотрим действие “Получить информацию об элементе списка” (GetListsDocumentActivity
).
В мета-описании файла определено возвращаемое значение FieldsMap
.
Рассмотрим части файла связанные непосредственно с обработкой FieldsMap
:
class CBPGetListsDocumentActivity extends CBPActivity
{
// ...
public function __construct($name)
{
// ..
$this->arProperties = [
// ...
"Fields" => null,
"FieldsMap" => null,
];
}
// ..
public function ReInitialize()
{
// ...
$fields = $this->Fields;
if ($fields && is_array($fields))
{
foreach ($fields as $field)
{
$this->{$field} = null;
}
}
}
// ...
public function Execute()
{
// ...
$map = $this->FieldsMap;
// ...
$this->SetPropertiesTypes($map);
$values = [];
foreach ($map as $id => $field)
{
// ...
$this->arProperties[$id] = $document[$id];
}
// ...
}
// ...
public static function GetPropertiesDialogValues($documentType, $activityName, &$arWorkflowTemplate,
&$arWorkflowParameters, &$arWorkflowVariables, $arCurrentValues, &$errors)
{
// ..
$properties['FieldsMap'] = self::buildFieldsMap($properties['DocumentType'], $properties['Fields']);
$arCurrentActivity = &CBPWorkflowTemplateLoader::FindActivityByName($arWorkflowTemplate, $activityName);
$arCurrentActivity["Properties"] = $properties;
// ..
}
// ...
private static function buildFieldsMap(array $documentType, $fields)
{
// ...
$map = [];
foreach ($fields as $field)
{
// ...
$map[$field] = \Bitrix\Bizproc\FieldType::normalizeProperty($documentFields[$field]);
// ...
}
return $map;
}
// ...
}
Файл класса
В указанной главе мы рассмотрим лишь базовые методы для создания действия (не робота), рассмотрим обязательные параметры и доступные настройки.
В классе нашего активити нам необходимо:
- Описать конструктор
__construct
, задав значения по-умолчанию для наших свойств - Разработать код для метода
Execute
- это тот метод, который будет выполняться в запущенном бизнес-процессе - Разработать код для методов
GetPropertiesDialog
иGetPropertiesDialogValues
- методы используемые для отображения диалога настроек и сохранения введенных значений
Предположим, наша задача состоит в разработки действия которое будет записывать информацию в определенный (заранее созданный файл /dump.txt
).
В конструкторе мы определим необходимые переменные:
public function __construct($name)
{
parent::__construct($name);
$this->arProperties = [
"Title" => "",
"MyText" => ""
];
}
Мы выполнили родительский метод конструктора (совместимость с CBPActivity
), а так же определили заранее свойства с которыми будем работать.
-
Title
- название активити -
MyText
- текст который будем записывать в файл
Поскольку мы хотим задавать этот текст в настройках нашего действия необходимо вначале реализовать методы которые нужны для работы активити в дизайнере бизнес-процесса. Статический метод GetPropertiesDialog
должен вернуть html верстку, которая будет встроена в диалог настроек.
public static function GetPropertiesDialog(
$documentType,
$activityName,
$arWorkflowTemplate,
$arWorkflowParameters,
$arWorkflowVariables,
$arCurrentValues = null,
$formName = "",
$form,
$currentSiteId,
$arWorkflowConstants
)
{
// .. code here
}
Нам не обязательно нужно формировать html-верстку прямо в этом файле - мы можем подключить любой файл для формирования. Штатно это делается через менеджер текущего выполнения, например так:
$runtime = \CBPRuntime::GetRuntime();
return $runtime->ExecuteResourceFile(
__FILE__,
"properties_dialog.php",
array(
"arCurrentValues" => $arCurrentValues,
"formName" => $formName,
)
);
В результате выполнения данного фрагмента будет подключен файл properties_dialog.php
в директории файла __FILE__
и внутри него будут доступны переменные arCurrentValues
и formName
.
В нашем случае действие будет выглядеть так:
public static function GetPropertiesDialog(
$documentType,
$activityName,
$arWorkflowTemplate,
$arWorkflowParameters,
$arWorkflowVariables,
$arCurrentValues = null,
$formName = "",
$form,
$currentSiteId,
$arWorkflowConstants
)
{
$runtime = \CBPRuntime::GetRuntime();
if ( !is_array($arWorkflowParameters) )
$arWorkflowParameters = [];
if ( !is_array($arWorkflowVariables) )
$arWorkflowVariables = [];
if ( !is_array($arCurrentValues) )
{
$arCurrentValues = ["my_text" => ""];
$arCurrentActivity= &CBPWorkflowTemplateLoader::FindActivityByName(
$arWorkflowTemplate,
$activityName
);
if ( is_array($arCurrentActivity["Properties"]) )
{
$arCurrentValues["my_text"] = $arCurrentActivity["Properties"]["MyText"];
}
return $runtime->ExecuteResourceFile(
__FILE__,
"properties_dialog.php",
array(
"arCurrentValues" => $arCurrentValues,
"formName" => $formName,
)
);
}
Теперь когда мы реализовали метод открытия диалога необходимо реализовать метод отвечающий за сохранение введенных значений. В классе действия за это отвечает статический метод GetPropertiesDialogValues
Пример:
public static function GetPropertiesDialogValues(
$documentType,
$activityName,
&$arWorkflowTemplate,
&$arWorkflowParameters,
&$arWorkflowVariables,
$arCurrentValues,
&$arErrors,
$arWorkflowConstants,
)
{
$arErrors = [];
$runtime = \CBPRuntime::GetRuntime();
if ( mb_strlen($arCurrentValues["my_text"]) <= 0 )
{
$arErrors[] = [
"code" => "emptyCode",
"message" => GetMessage("MYACTIVITY_EMPTY_TEXT"),
];
return false;
}
$arProperties = ["MyText" => $arCurrentValues["my_text"]];
$arCurrentActivity = &CBPWorkflowTemplateLoader::FindActivityByName(
$arWorkflowTemplate,
$activityName
);
$arCurrentActivity["Properties"] = $arProperties;
return true;
}
Осталось только описать метод, который будет срабатывать во время выполнения действия:
public function Execute()
{
file_put_contents($_SERVER["DOCUMENT_ROOT"]."/dump.txt", $this->MyText, FILE_APPEND);
// Возвратим исполняющей системе указание, что действие завершено
return \CBPActivityExecutionStatus::Closed;
}
Активити в результате своей работы должно вернуть один из следующих статусов:
-
CBPActivityExecutionStatus::Executing
- действие еще не завершило свою работу -
CBPActivityExecutionStatus::Closed
- действие завершило свою работу -
CBPActivityExecutionStatus::Faulting
- ошибка при выполнении действия, прекратить выполнение бизнес-процесса
properties_dialog.php
Код в файле properties_dialog.php
отвечает за отображение настроек активити дизайнере бизнес-процессов.
Поскольку на момент написания статьи дизайнер использует табличную верстку, то содержимое диалога так же должно состоять из контента с табличной версткой
Пример:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
?>
<tr>
<td align="right" width="40%"><span style="color:#FF0000;">*</span> :</td>
<td width="60%">
<textarea name="my_text" id="id_my_text " rows="5" cols="40"><?= htmlspecialchars($arCurrentValues["my_text"]) ?></textarea>
<input type="button" value="..." onclick="BPAShowSelector('id_my_text', 'string');">
</td>
</tr>
В рамках диалога можно использовать любой набор переменных определенный и переданный в него через метод GetPropertiesDialog
.
В текущем примере пользователь, настраивающий действие в редакторе, может ввести в поле my_text явное значение или выбрать одно из значений с помощью диалога, открывающегося по управляющей кнопке-бургеру слева.
robot_properties_dialog.php
Подобно properties_dialog.php
, файл robot_properties_dialog.php
отвечает за отображение настроек робота.
Пример:
<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
/** @var \Bitrix\Bizproc\Activity\PropertiesDialog $dialog */
$elementId = $dialog->getMap()['ElementId'];
?>
<div class="bizproc-automation-popup-settings">
<span class="bizproc-automation-popup-settings-title"><?=htmlspecialcharsbx($elementId['Name'])?>: </span>
<?=$dialog->renderFieldControl($elementId)?>
</div>