Действие: PHP код

Иногда возникает необходимость расширить стандартные возможности бизнес-процессов, а для этого в коробке есть большой набор инструментов, одним из которых является действие “PHP код”.

Мы настоятельно не рекомендуем использовать это активити в релизах, поскольку данное действие помимо своих сильных сторон имеет очевидные слабые стороны.

Преимущества:

  • Позволяет расширять возможности бизнес-процессов
  • Занимают минимальное время на разработку

Недостатки:

  • Некорректно описанный код может заблокировать процесс
  • При наличии активити в схеме бизнес-процесса, редактировать бизнес-процесс могут только сотрудники с правами на изменение физических файлов портала (административный доступ)
  • Большие активити с течением времени сложно поддерживать

Правила

В случае если вы решили писать активити старайтесь следовать правилам:

  1. Чем меньше кода тем проще его отладить. Старайтесь использовать код который можно отладить и без активити.
  2. Оборачивайте код в try-catch блок ожидая Throwable. Таким образом вы предотвратите неожиданные и необъяснимые падения.
  3. Записывайте все что может быть важно. Успешное выполнение, ошибка или неожиданное поведение.
  4. Не используйте код, который интерпретируется парсером битрикса (например {ID} автоматически заменяемый)
  5. Не опирайтесь на глобальные переменные. Код может выполнять как на странице, так и на cron - переменная с текущим пользователем может быть пуста или заполнена не тем сотрудником. Идентификатора сайта может не быть.

Журналирование

Для того чтобы делать записи в журнал бизнес-процесса существует специальный сервис журналирования (TrackingService) и быстрая log-функция \CBPActivity::WriteToTrackingService. Так как любое действие (активити) является наследником этого класса, то обращаться к нему можно через $this часть.

Сигнатура метода:

/**
 * @param string $message      Message to log
 * @param int    $modifiedBy   Who modifier
 * @param int    $trackingType Tracking type
 * @type void
 */
\CBPActivity::WriteToTrackingService($message = "", $modifiedBy = 0, $trackingType = -1): void

Параметрами данного метода являются:

  • $message (string) - Текстовая строка, которая будет записана в журнал бизнес-процесса.
  • $modifiedBy (int) - Идентификатор сотрудника, который будет записан в журнал. 0 - соответствует системе.
  • $trackingType (enum) - Тип сообщения (см. Типы сообщений).

Пример записи обычного сообщения в журнал:

$this->WriteToTrackingService(
	"Some message!",
	0,
	\CBPTrackingType::Report
);

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

Типы сообщений

Зарегистрированные типы сообщений хранятся константами в классе CBPTrackingType, однако констант в классе гораздо больше чем отображаемых в журнале сообщений.

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

Отображаемые сообщения:

  • \CBPTrackingType::Error - Ошибки в процессе работы
  • \CBPTrackingType::Report - Примечания в процессе работы
  • \CBPTrackingType::Custom - Сообщения неопределенного типа
  • \CBPTrackingType::FaultActivity - Критическая ошибка при работе действия

Шаблон активити

try
{
	// ... code here ...
}
catch( \Throwable $e )
{
	$this->WriteToTrackingService(
		sprintf("Error %s on line %s in file %s",
			$e->getMessage(),
			$e->getLine(),
			$e->getFile()
		),
		0,
		CBPTrackingType::FaultActivity
	);
}

Окружение

В действиях бизнес-процесса часто необходимо взаимодействовать с окружением - переменными процесса, параметрами, константами, глобальными константами и переменными, полями документа. Самое очевидное, что приходит на ум всем - использовать подстановку переменных через стандартный редактор.

Представим самый обычный код:

$testMessage = "Entity id: {{Название компании}}";

$this->WriteToTrackingService($testMessage);

Код выглядит, запуститься и даже будет выдавать результат, однако в данном случае в нем кроется часовая бомба. В чем проблема? Представим грубо, что любая заменя это просто набор str_replace, т.е. переменные будут заменены как есть. Что произойдет если в заменяемой фразе будет кавычка? Например: в названии компании указано значение ООО "Супер сила"

Таким образом код выглядит следующим образом:

$testMessage = "Entity id: ООО "Супер сила"";

$this->WriteToTrackingService($testMessage)

Заметили синтаксическую ошибку? Именно - указанный фрагмент будет вызывать фатальную ошибку. Теперь когда вы поняли почему нельзя работать с автозаменой давайте разберем техники как этого обойти.

Парсинг

Из курса по бизнес-процессам нам известно о существование таких элементов как парсер (выполняет автозамену) и калькулятор выражений (парсит и вычисляет значения). За парсинг значений отвечает метод \CBPActivity::parseValue($value, $convertToType = null), тогда у нас есть возможность использовать ее для своих нужд.

$this->ParseValue('{'.'=Document:TITLE}')

Правда тут есть одна неприятность: необходимо использовать не отображаемое значение, а реальное. Так например {{ID}} станет {=Document:ID}. Тогда {{Название компании}} станет {=Document:TITLE}.

Таким образом наш преобразованный код будет выглядеть так:

$testMessage = "Entity id: ".$this->ParseValue('{'.'=Document:TITLE}');

$this->WriteToTrackingService($testMessage);

Почему мы не написали ParseValue('{=Document:TITLE}') ? Дело в том, что в таком случае сработала бы автозамена и мы получили такую же ошибку, как и ранее, поэтому мы сознательно разделили нашу запись чтобы автозамена значений битрикса не сработала.

Полезные ссылки

  1. Исключения
  2. Бизнес-процессы: Произвольный PHP код в бизнес-процессе
  3. Действие: PHP код