← Назад к заметкам

Заметки

Как передать массив в итератор БП

Как подготовить множественную переменную для итератора бизнес-процесса: преобразовать строку, JSON или результат REST в массив значений.

Итератор работает не с произвольной строкой, а с множественной переменной БП. Если из REST или PHP-активити пришёл JSON, строка через запятую или многострочный текст, сначала нужно превратить это в массив, записать в множественную переменную и уже её выбрать в настройках итератора.

Задача

В бизнес-процессе часто нужно пройтись по списку значений: ID сделок, элементов смарт-процесса, пользователей, строк из внешней системы или результатам REST-запроса.

Для этого в БП есть конструкция «Итератор». Она берёт множественную переменную и выполняет вложенные действия для каждого значения из этой переменной.

Проблема появляется, когда список приходит не как готовая множественная переменная, а как строка:

  • 101, 102, 103;
  • многострочный текст;
  • JSON-массив;
  • ответ REST с массивом внутри result;
  • строка, которую вернула PHP-активити или внешняя система.

В таком виде отдавать данные в итератор не стоит. Сначала нужно подготовить массив и записать его в переменную БП, которая настроена как множественная.

Что ждёт итератор

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

В PHP-активити такую переменную можно заполнить массивом:

$items = [
    101,
    102,
    103,
];

$this->SetVariable('IteratorItems', $items);

После этого в настройках итератора выбирается переменная IteratorItems. Внутри итератора каждое действие будет работать с очередным значением.

Важно не путать массив и строку, которая внешне похожа на массив:

$this->SetVariable('IteratorItems', '[101,102,103]');

Это строка. Для итератора нужен не такой текст, а реальные отдельные значения:

$this->SetVariable('IteratorItems', [
    101,
    102,
    103,
]);

Поэтому основная работа перед итератором — привести входные данные к массиву и записать его в множественную переменную через SetVariable.

Строка с разделителями

Самый частый вариант — список приходит строкой через запятую, точку с запятой или переносы строк. Так бывает после ручного ввода, REST-активити, внешнего обработчика или старого PHP-действия.

Если значения разделены запятыми:

$source = '101, 102, 103';

$items = preg_split('/[,;\n\r]+/', $source);

$items = array_map('trim', $items);
$items = array_filter($items, static function ($item): bool {
    return $item !== '';
});

$this->SetVariable('IteratorItems', array_values($items));

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

Для многострочного текста можно оставить только разбор переносов:

$source = trim((string)$this->GetRootActivity()->GetVariable('SourceText'));

$items = preg_split('/\r\n|\r|\n/', $source);

$items = array_map('trim', $items);
$items = array_filter($items, static function ($item): bool {
    return $item !== '';
});

$this->SetVariable('IteratorItems', array_values($items));

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

JSON из REST или PHP-активити

Если список пришёл как JSON, его нужно декодировать через json_decode. Нельзя просто записать JSON-строку в множественную переменную и ждать, что итератор сам разберёт её на элементы.

Простой JSON-массив:

$json = '[101, 102, 103]';

$items = json_decode($json, true);

if (!is_array($items)) {
    $items = [];
}

$items = array_values(array_filter($items, static function ($item): bool {
    return $item !== null && $item !== '';
}));

$this->SetVariable('IteratorItems', $items);

Иногда внешний обработчик или REST-ответ возвращает не сам массив, а объект с ключом result:

$json = '{"result":[101,102,103]}';

$data = json_decode($json, true);

$items = [];

if (is_array($data) && isset($data['result']) && is_array($data['result'])) {
    $items = $data['result'];
}

$this->SetVariable('IteratorItems', array_values($items));

Если источник может быть разным — массив, JSON, строка через запятую или пустое значение — удобнее сделать одну функцию нормализации:

function normalizeIteratorItems(mixed $value): array
{
    if ($value === null || $value === '') {
        return [];
    }

    if (is_array($value)) {
        return array_values(array_filter($value, static function ($item): bool {
            return $item !== null && $item !== '';
        }));
    }

    $string_value = trim((string)$value);

    if ($string_value === '') {
        return [];
    }

    $decoded_value = json_decode($string_value, true);

    if (json_last_error() === JSON_ERROR_NONE) {
        if (is_array($decoded_value)) {
            if (isset($decoded_value['result']) && is_array($decoded_value['result'])) {
                return normalizeIteratorItems($decoded_value['result']);
            }

            return normalizeIteratorItems($decoded_value);
        }

        return [$decoded_value];
    }

    $items = preg_split('/[,;\n\r]+/', $string_value);

    $items = array_map('trim', $items);
    $items = array_filter($items, static function ($item): bool {
        return $item !== '';
    });

    return array_values($items);
}

$root_activity = $this->GetRootActivity();

$source_value = $root_activity->GetVariable('SourceValue');
$iterator_items = normalizeIteratorItems($source_value);

$this->SetVariable('IteratorItems', $iterator_items);

Такой код хорошо подходит для PHP-активити перед итератором. На вход можно передать значение из переменной БП, строку из REST-действия или уже готовый массив. На выходе получится обычный массив для множественной переменной.

Пользователи и другие типы

Тип переменной важен. Если итератор должен проходить по строкам, создавайте множественную строковую переменную. Если по числам — числовую. Если по пользователям — переменную типа «Пользователь».

Для пользователей часто нужен формат user_ID, а не просто число. Например:

$user_ids = [
    1,
    2,
    3,
];

$user_values = [];

foreach ($user_ids as $user_id) {
    $user_id = (int)$user_id;

    if ($user_id > 0) {
        $user_values[] = 'user_' . $user_id;
    }
}

$this->SetVariable('IteratorUsers', $user_values);

Такой массив можно записать в множественную переменную типа «Пользователь» и потом использовать её в итераторе или других действиях БП. В справке Bitrix24 для PHP-кода тоже используется массив пользователей в формате user_1 и user_2.

Для списков и пользовательских полей важно передавать не красивое название значения, а тот формат, который ожидает переменная или следующее действие. Иногда это ID пункта, иногда строковый код, иногда значение вида user_5.

Главное правило простое: итератор не должен заниматься разбором строки. Перед ним лучше поставить отдельное PHP-действие, которое нормализует входные данные и записывает чистый массив в множественную переменную. Тогда сам итератор остаётся простым и предсказуемым.