#best-practice

Советы с тегом "best-practice"

3 совета

Работа с Highload-блоками по имени вместо ID

Работа с Highload-блоками по имени вместо ID

Продолжаем тему избавления кодовой базы от ID при работе с сущностями Битрикс.

Проблема

Типичный код работы с Highload-блоками содержит жёстко прописанные ID:

        <?php
// Антипаттерн: ID зашит в код
$hlblock = HighloadBlockTable::getById(5)->fetch();
$entity = HighloadBlockTable::compileEntity($hlblock);

    

ID Highload-блока различается между окружениями: на dev-сервере это 5, на production — 12. При переносе кода приходится менять значения вручную или использовать конфигурационные файлы. Ситуация усугубляется, когда ID разбросаны по десяткам файлов проекта.

Решение

Метод HighloadBlockTable::resolveHighloadblock() принимает символьное имя HL-блока вместо числового ID. Имя задаётся при создании блока и остаётся неизменным при переносе между окружениями.

        <?php
use Bitrix\Highloadblock\HighloadBlockTable;
use Bitrix\Main\Loader;

Loader::includeModule('highloadblock');

// Правильно: используем символьное имя
$hlblock = HighloadBlockTable::resolveHighloadblock('Cities');

if ($hlblock !== null) {
    $entity = HighloadBlockTable::compileEntity($hlblock);
    $entityClass = $entity->getDataClass();
    
    $items = $entityClass::getList([
        'filter' => ['=UF_ACTIVE' => 1]
    ])->fetchAll();
}

    

Метод compileEntity также поддерживает имя

Символьное имя можно передавать напрямую в compileEntity() — метод внутри вызывает resolveHighloadblock():

        <?php
// Компиляция entity по имени — без промежуточных вызовов
$entity = HighloadBlockTable::compileEntity('Cities');
$entityClass = $entity->getDataClass();

$cities = $entityClass::getList()->fetchAll();

    

Константы для имён HL-блоков

Для централизованного управления именами создайте класс с константами:

        <?php
namespace App\Reference;

class HLBlock
{
    public const CITIES = 'Cities';
    public const REGIONS = 'Regions';
    public const COLORS = 'ProductColors';
    public const SIZES = 'ProductSizes';
}

    

Использование в коде:

        <?php
use App\Reference\HLBlock;

$entity = HighloadBlockTable::compileEntity(HLBlock::CITIES);
$entityClass = $entity->getDataClass();

    

При таком подходе IDE подсказывает доступные HL-блоки, а опечатки выявляются на этапе статического анализа.

Встроенное кеширование

Метод resolveHighloadblock() кеширует результат запроса на 24 часа. Повторные вызовы с тем же именем не обращаются к базе данных:

        <?php
// Первый вызов — запрос к БД, результат кешируется
$hlblock1 = HighloadBlockTable::resolveHighloadblock('Cities');

// Повторный вызов — данные из кеша ORM
$hlblock2 = HighloadBlockTable::resolveHighloadblock('Cities');

    

Валидация имени

Метод проверяет корректность символьного имени регулярным выражением /^[a-z0-9_]+$/i. При несуществующем или некорректном имени возвращается null:

        <?php
$hlblock = HighloadBlockTable::resolveHighloadblock('NonExistent');
// $hlblock === null

    

Итог

Замените числовые ID на символьные имена HL-блоков через resolveHighloadblock(). Код станет переносимым между окружениями без ручных правок, а централизованные константы обеспечат контроль над используемыми справочниками.

Безопасная работа с JSON через Bitrix\Main\Web\Json

Безопасная работа с JSON через Bitrix\Main\Web\Json

Проблема

При работе с JSON в 1С-Битрикс многие разработчики используют нативные функции json_encode() и json_decode() без должной обработки ошибок. Это приводит к silent-ошибкам: когда данные не кодируются корректно, функция возвращает false или null, но код продолжает выполняться. В результате возникают сложно диагностируемые проблемы с невалидными данными.

Решение

Класс Bitrix\Main\Web\Json предоставляет безопасные методы для работы с JSON, автоматически выбрасывая исключения при ошибках кодирования/декодирования.

Базовое использование

        use Bitrix\Main\Web\Json;
use Bitrix\Main\ArgumentException;

// Безопасное кодирование
try {
    $jsonString = Json::encode($data);
} catch (ArgumentException $e) {
    // Обработка ошибки кодирования
}

// Безопасное декодирование
try {
    $array = Json::decode($jsonString);
} catch (ArgumentException $e) {
    // Обработка ошибки декодирования
}

    

Преимущества класса

Класс автоматически использует оптимальные опции по умолчанию:

  • JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT — защита от XSS
  • JSON_UNESCAPED_UNICODE — корректная работа с кириллицей
  • JSON_INVALID_UTF8_SUBSTITUTE — замена невалидных символов UTF-8
  • JSON_THROW_ON_ERROR — автоматический выброс исключений

Валидация JSON

Класс предоставляет метод для проверки валидности JSON-строки:

        use Bitrix\Main\Web\Json;
use Bitrix\Main\Application;

$request = Application::getInstance()->getContext()->getRequest();
$jsonString = $request->getPost('json_data') ?? '';

if (!Json::validate($jsonString)) {
    throw new \Bitrix\Main\ArgumentException(
        "Невалидный JSON в параметре json_data"
    );
}

$data = Json::decode($jsonString);

    

Кастомные опции кодирования

Вы можете переопределить опции при необходимости:

        use Bitrix\Main\Web\Json;

// Форматированный вывод с отступами
$prettyJson = Json::encode(
    $data, 
    Json::DEFAULT_OPTIONS | JSON_PRETTY_PRINT
);

// Без экранирования слешей для URL
$jsonForApi = Json::encode(
    ['url' => 'https://example.com/path'],
    Json::DEFAULT_OPTIONS | JSON_UNESCAPED_SLASHES
);

    

Итог

Использование Bitrix\Main\Web\Json вместо нативных функций обеспечивает явную обработку ошибок и автоматическую защиту от XSS. Метод validate() позволяет безопасно проверять пользовательский ввод перед декодированием.

Правильная работа с Bitrix\Main\Result для обработки ошибок

Правильная работа с Bitrix\Main\Result для обработки ошибок

Проблема

Многие разработчики до сих пор возвращают булевы значения или массивы из своих методов, игнорируя стандартный класс Bitrix\Main\Result. Это приводит к неединообразной обработке ошибок, усложняет отладку и делает код несовместимым с современным API Битрикс.

Решение

Класс Result предоставляет стандартизированный способ возврата результатов операций с возможностью передачи ошибок и данных.

Базовое использование

        use Bitrix\Main\Result;
use Bitrix\Main\Error;

function processOrder(int $orderId): Result
{
    $result = new Result();
    
    // Проверка существования заказа
    if (!$order = getOrder($orderId)) {
        $result->addError(new Error('Заказ не найден', 'ORDER_NOT_FOUND'));
        return $result;
    }
    
    // Проверка статуса
    if ($order['STATUS'] === 'PAID') {
        $result->addError(new Error('Заказ уже оплачен', 'ORDER_ALREADY_PAID'));
        return $result;
    }
    
    // Успешная обработка
    $result->setData([
        'order_id' => $orderId,
        'amount' => $order['PRICE'],
        'timestamp' => time()
    ]);
    
    return $result;
}

    

Проверка результата

        $result = processOrder(123);

if ($result->isSuccess()) {
    $data = $result->getData();
    echo "Заказ обработан: " . $data['order_id'];
} else {
    // Получение всех ошибок
    foreach ($result->getErrors() as $error) {
        echo $error->getCode() . ': ' . $error->getMessage();
    }
    
    // Или только первой ошибки
    $error = $result->getError();
    echo $error->getMessage();
    
    // Или всех сообщений одним массивом
    $messages = $result->getErrorMessages();
}

    

Добавление множественных ошибок

        function validateOrderData(array $data): Result
{
    $result = new Result();
    $errors = [];
    
    if (empty($data['email'])) {
        $errors[] = new Error('Email обязателен', 'EMAIL_REQUIRED');
    }
    
    if (empty($data['phone'])) {
        $errors[] = new Error('Телефон обязателен', 'PHONE_REQUIRED');
    }
    
    if (!empty($errors)) {
        $result->addErrors($errors);
    }
    
    return $result;
}

    

Передача ошибок между методами

        function createUser(array $userData): Result
{
    $result = new Result();
    
    // Валидация
    $validationResult = validateUserData($userData);
    if (!$validationResult->isSuccess()) {
        $result->addErrors($validationResult->getErrors());
        return $result;
    }
    
    // Создание пользователя
    // ...
    
    return $result;
}

    

Дополнительные данные в ошибках

        $error = new Error(
    'Недостаточно товара на складе',
    'INSUFFICIENT_STOCK',
    ['available' => 5, 'requested' => 10] // customData
);

// Получение дополнительных данных
$customData = $error->getCustomData();
echo "Доступно: " . $customData['available'];

    

Итог

Использование Result делает код предсказуемым, упрощает обработку ошибок и соответствует стандартам Битрикс. Все современные модули (Sale, Catalog, CRM) используют этот подход.

Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.