Условие (condition) в модуле Бизнес Процессы
Готовый код можно скачать в моем репозитории на GitFlic.
В рамках шаблона Бизнес Процессов помимо действий или activity есть еще и условия или condition. Условия это особый подвид активити, который может быть использован в блоках Условие и Цикл, наряду с Полем документа, PHP код, Смешанное и Истина.
Мы будем рассматривать условие на примере штатного условия codecondition, все сводится к PHP коду который должен отдать true.
Расположение
Порядок поиска является приоритетным, директории будут перебираться последовательно пока не будет найдена директория с условием. Condition, могут располагаться в следующих местах:
/local/activities/local/activities/custom/bitrix/activities/custom/bitrix/activities/bitrix/bitrix/modules/bizproc/activities
Файловая структура
Для нашего случая будет использоваться название действия phpcodecondition, по сути я скопировал штатный condition который выполняит PHP код, в случае если PHP код отдаст true, выполнение пойдет дальше.
-
-
-
-
.description.phpproperties_dialog.phptestcodeactivity.php
.description.phpсодержит мета-информацию описывающую наше действие, аналог.description.phpв компонентахicon.gifаватаркаphpcodeactivity.phpсодержит основную логику нашего активити, аналогclass.phpв компонентахproperties_dialog.phpсодержит код для визуального отображения, аналогtemplate.phpв компонентах
-
-
-
Файл .description.php
Основная задача файла, установить переменную $arActivityDescription как массив описывающий действие:
/local/activities/phpcodecondition/.description.php<?php
use Bitrix\Main\Localization\Loc;
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
die();
}
$arActivityDescription = [
'NAME' => Loc::getMessage('BPC_DESCR_NAME'),
'DESCRIPTION' => Loc::getMessage('BPC_DESCR_DESCR'),
'TYPE' => 'condition',
'FILTER' => [
'EXCLUDE' => CBPHelper::DISTR_B24,
],
];
Рассмотрим все возможные ключи массива $arActivityDescription:
NAME(string) локализованное название действия, отображается в списке действий, а так же в заголовке всплывающего окна настроекDESCRIPTION(string) локализованное описание действия, отображается во всплывающем окне настроекTYPE(string or array) тип действия, в случае условия может принимать толькоcondition, в случае действия может быть либоactiviy, либоrobot_activityлибо массивом из этих же элементовCLASS(string) название php-класса обработчика действия, должен совпадать с названием директорииJSCLASS(string) название js-класса обработчика действия, по умолчаниюBizProcActivityCATEGORY(array) опциональное описание раздела для отображения в дизайнере БП в случаеTYPE=activityROBOT_SETTINGS(array) опциональное описание раздела для отображения в роботах в случаеTYPE=robot_activityFILTER(array) структура описывающая условия отображения действияRETURN(array) структура описывающая возвращаемые значенияADDITIONAL_RESULT(array) набор из кодов свойств действия, возвращающихся как дополнительные значения, которые могут быть переданы в другие действия во время выполнения бизнес-процесса
CATEGORY
Для размещения свое действия в дизайнере бизнес-процесса необходимо указать в каком разделе оно будет отображаться. Обычно разрабатываемые действия отображаются в категории «Другое», что можно описать как:
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;
}
// ...
}
Файл phpcodeactivity.php
Мы создаем простое условие, родительским классом в данном случае будет являться Activity, а наш класс должен иметь префикс CBP.
В классе нашего активити нам необходимо:
__constructописать конструктор, задав значения по-умолчанию для наших свойствExecuteметод который будет выполняться в запущенном бизнес-процессеGetPropertiesDialogотображение диалога настроекGetPropertiesDialogValuesсохранение введенных значений
/local/activities/phpcodeactivity/phpcodeactivity.php<?php
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
die();
}
use Bitrix\Main\Localization\Loc;
class CBPPhpCodeCondition extends CBPActivityCondition
{
public $condition = '';
public function __construct($condition)
{
// записываем PHP выражение
$this->condition = $condition;
}
// метод который будет выполняться в запущенном бизнес-процессе, доступны свойства обьявленные в конструкторе
public function Evaluate(CBPActivity $ownerActivity)
{
// выполним php код
@eval("\$result = " . $this->condition . ";");
// вернем результат выполнения кода
return CBPActivityExecutionStatus::Closed;
// возможные варианты ответа
// CBPActivityExecutionStatus::Executing; действие еще не завершило свою работу
// CBPActivityExecutionStatus::Closed; действие завершило свою работу
// CBPActivityExecutionStatus::Faulting; ошибка при выполнении действия, прекратить выполнение бизнес-процесса
}
// валидация
public static function validateProperties($value = null, CBPWorkflowTemplateUser $user = null)
{
$arErrors = [];
if ($user == null || !$user->isAdmin()) {
$arErrors[] = [
'code' => 'perm',
'message' => Loc::getMessage('BPCC_NO_PERMS'),
];
}
return array_merge($arErrors, parent::validateProperties($value, $user));
}
// диалог настроек, показываем поля формы для заполнения
public static function GetPropertiesDialog(
$documentType,
$arWorkflowTemplate,
$arWorkflowParameters,
$arWorkflowVariables,
$defaultValue,
$arCurrentValues = null
)
{
$runtime = CBPRuntime::GetRuntime();
if (!is_array($arCurrentValues)) {
$arCurrentValues = ['condition_php_code' => ($defaultValue == null ? '' : $defaultValue)];
}
// инклудим файл который выведет html-верстку, штатно это делается через менеджер текущего выполнения
return $runtime->ExecuteResourceFile(
__FILE__,
'properties_dialog.php',
['arCurrentValues' => $arCurrentValues]
);
}
// сохранение введенных значений в поля формы
public static function GetPropertiesDialogValues(
$documentType,
$arWorkflowTemplate,
$arWorkflowParameters,
$arWorkflowVariables,
$arCurrentValues,
&$arErrors
)
{
$arErrors = [];
if (!array_key_exists('condition_php_code', $arCurrentValues) || $arCurrentValues['condition_php_code'] == '') {
$arErrors[] = [
'code' => '',
'message' => Loc::getMessage('BPCC_EMPTY_CODE'),
];
return null;
}
$arErrors = self::validateProperties(
$arCurrentValues['condition_php_code'],
new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser)
);
if (count($arErrors) > 0) {
return null;
}
return $arCurrentValues['condition_php_code'];
}
}