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

Заметки

Пустое значение поля в CRM может быть не null

Почему пустое поле CRM в Bitrix24 не всегда стоит проверять только через null.

В CRM-полях Bitrix24 пустое значение не всегда приходит как null. Перед проверками лучше привести значение к понятному внутреннему состоянию.

Суть проблемы

В коде легко написать проверку только на null, а потом получить ошибку в логике, потому что поле пришло пустой строкой, нулём или вообще отсутствует в массиве.

Коротко

Пустое значение CRM-поля лучше не проверять одной универсальной проверкой.

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

  • null;
  • пустая строка '';
  • строка '0';
  • число 0;
  • пустой массив;
  • отсутствующий ключ в массиве.

Из-за этого проверки вроде $value === null или empty($value) могут дать не тот результат.

Где встречается

Чаще всего это всплывает при работе с пользовательскими полями CRM:

  • в сделках;
  • в лидах;
  • в контактах и компаниях;
  • в смарт-процессах;
  • в обработчиках событий CRM;
  • в фильтрах для выборки сущностей;
  • при сравнении старого и нового значения поля.

Отдельно стоит быть внимательным с полями типа Да/Нет. В рабочей логике такое поле удобнее воспринимать не как простой bool, а как состояние.

Проверка значений

Надёжнее сначала привести значение к своему формату, а уже потом использовать его в условиях.

Не проверять только на null

Проверка только на null слишком узкая. Она не поймает пустую строку и отсутствующий ключ, если значение берётся из массива CRM-полей.

<?php

$field_value = $deal_data['UF_CRM_EXAMPLE_FIELD'] ?? null;

if ($field_value === null) {
    // Сработает только для null или отсутствующего ключа.
}

Проверка через empty() тоже не всегда подходит, потому что для PHP значения 0 и '0' тоже считаются пустыми.

<?php

$field_value = $deal_data['UF_CRM_EXAMPLE_FIELD'] ?? null;

if (empty($field_value)) {
    // Сюда попадут null, '', 0, '0', false и пустой массив.
}

Поле Да/Нет

У поля типа Да/Нет в прикладной логике может быть три состояния:

  • значение не заполнено;
  • выбрано «Да»;
  • выбрано «Нет».

Поэтому его лучше не проверять как обычный true или false. Иначе можно случайно смешать «Нет» и «не заполнено».

<?php

$field_value = $deal_data['UF_CRM_EXAMPLE_BOOLEAN'] ?? null;

if ($field_value) {
    // Так лучше не делать для CRM-поля Да/Нет.
}

Безопаснее явно определить, что для текущей задачи считается «Да», что считается «Нет», а что считается незаполненным значением.

Пример нормализации

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

<?php

use Bitrix\Main\Loader;

const CRM_MODULE_ID = 'crm';
const DEAL_ID = 0;
const YES_NO_FIELD = 'UF_CRM_EXAMPLE_BOOLEAN';

const VALUE_EMPTY = 'empty';
const VALUE_YES = 'yes';
const VALUE_NO = 'no';

Loader::includeModule(CRM_MODULE_ID);

$deal_data = fetchDealData(DEAL_ID);
$field_value = $deal_data[YES_NO_FIELD] ?? null;
$field_state = normalizeYesNoValue($field_value);

if ($field_state === VALUE_EMPTY) {
    // Поле не заполнено.
}

if ($field_state === VALUE_YES) {
    // Выбрано Да.
}

if ($field_state === VALUE_NO) {
    // Выбрано Нет.
}

/**
 * Получает данные сделки.
 */
function fetchDealData(int $deal_id): array
{
    if ($deal_id <= 0) {
        return [];
    }

    $deal_result = CCrmDeal::GetListEx(
        [],
        ['ID' => $deal_id],
        false,
        false,
        ['ID', YES_NO_FIELD]
    );

    $deal_data = $deal_result ? $deal_result->Fetch() : false;

    return is_array($deal_data) ? $deal_data : [];
}

/**
 * Приводит значение поля Да/Нет к внутреннему состоянию.
 */
function normalizeYesNoValue(mixed $field_value): string
{
    if ($field_value === null || $field_value === '') {
        return VALUE_EMPTY;
    }

    if ($field_value === true || $field_value === 1 || $field_value === '1' || $field_value === 'Y') {
        return VALUE_YES;
    }

    if ($field_value === false || $field_value === 0 || $field_value === '0' || $field_value === 'N') {
        return VALUE_NO;
    }

    return VALUE_EMPTY;
}

Главная идея — не раскидывать проверки по всему коду, а один раз привести значение к понятному формату и дальше сравнивать уже его.

Источники