Разработка классов на D7 API 1С-Битрикс
D7 API — это не просто «новый API» поверх старого. Это другая философия разработки: классы вместо глобальных функций, неймспейсы вместо CModule, Result-объекты вместо bool и строк ошибок, Application как точка входа вместо глобальных переменных. Разработка на D7 означает код, который не ломается при обновлении Битрикс, тестируется, переиспользуется и читается.
Базовые концепции D7 API
Application — синглтон, точка входа:
$app = \Bitrix\Main\Application::getInstance();
$connection = $app->getConnection(); // подключение к БД
$request = $app->getContext()->getRequest(); // HTTP-запрос
$server = $app->getContext()->getServer(); // данные сервера
Result-объекты. Любой метод, который может завершиться с ошибкой, возвращает наследник \Bitrix\Main\Result:
class MyServiceResult extends \Bitrix\Main\Result
{
private ?array $data = null;
public function setData(array $data): void
{
$this->data = $data;
}
public function getData(): ?array
{
return $this->data;
}
}
// Использование
$result = new MyServiceResult();
if ($someConditionFailed) {
$result->addError(new \Bitrix\Main\Error('Нет данных для обработки', 'NO_DATA'));
return $result;
}
$result->setData($processedData);
return $result;
// Вызывающий код
$result = MyService::process($input);
if (!$result->isSuccess()) {
foreach ($result->getErrors() as $error) {
echo $error->getMessage(); // Нет данных для обработки
}
}
Это устраняет класс ошибок «функция вернула false, но почему — неизвестно».
Структура сервисного класса
Бизнес-логику выносим в сервисы — классы с чёткой ответственностью:
namespace MyProject\Services;
use Bitrix\Main\Result;
use Bitrix\Main\Error;
use MyProject\Storage\OrderLogTable;
class OrderService
{
public function __construct(
private readonly int $orderId
) {}
public function changeStatus(string $newStatus): Result
{
$result = new Result();
$allowedStatuses = ['PENDING', 'PROCESSING', 'SHIPPED', 'DELIVERED', 'CANCELLED'];
if (!in_array($newStatus, $allowedStatuses, true)) {
$result->addError(new Error("Недопустимый статус: {$newStatus}", 'INVALID_STATUS'));
return $result;
}
$order = \Bitrix\Sale\Order::load($this->orderId);
if (!$order) {
$result->addError(new Error("Заказ #{$this->orderId} не найден", 'ORDER_NOT_FOUND'));
return $result;
}
$saveResult = $order->setField('STATUS_ID', $newStatus);
if (!$saveResult->isSuccess()) {
$result->addErrors($saveResult->getErrors());
return $result;
}
$order->save();
OrderLogTable::add([
'ORDER_ID' => $this->orderId,
'ACTION' => "STATUS_CHANGED_TO_{$newStatus}",
]);
return $result;
}
}
Работа с HTTP-запросом через D7
Старый способ — $_POST['field']. D7-способ:
$request = \Bitrix\Main\Application::getInstance()->getContext()->getRequest();
$field = $request->getPost('field'); // POST-параметр
$param = $request->getQuery('param'); // GET-параметр
$file = $request->getFile('upload'); // загруженный файл
$isAjax = $request->isAjaxRequest();
$isPost = $request->isPost();
Объект Request фильтрует входные данные и предоставляет типизированный доступ. Это не «безопаснее магически», но явно показывает источник данных.
Сервис-локатор и DI
В Битрикс нет полноценного DI-контейнера, но есть сервис-локатор:
// Регистрация сервиса (в init.php или в методе модуля)
\Bitrix\Main\DI\ServiceLocator::getInstance()->addInstanceLazy(
'myproject.order.service',
static function() {
return new \MyProject\Services\OrderNotificationService(
new \MyProject\Services\MailSender(),
new \MyProject\Services\SmsGateway()
);
}
);
// Получение сервиса в любом месте кода
$notifier = \Bitrix\Main\DI\ServiceLocator::getInstance()
->get('myproject.order.service');
Отступление от глобальных переменных и статических вызовов делает код тестируемым.
Кеш D7
$cache = \Bitrix\Main\Data\Cache::createInstance();
$cacheKey = md5('product_list_' . $categoryId);
if ($cache->initCache(3600, $cacheKey, '/myproject/products/')) {
$data = $cache->getVars();
} else {
$data = $this->loadFromDatabase($categoryId);
$cache->startDataCache();
$cache->endDataCache($data);
}
Тегированный кеш для инвалидации группы записей:
$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache('/myproject/products/');
$taggedCache->registerTag('my_product_' . $productId);
$taggedCache->endTagCache();
// Инвалидация при изменении товара
$taggedCache->clearByTag('my_product_' . $productId);
Работа с файлами через D7
use Bitrix\Main\IO\File;
use Bitrix\Main\IO\Directory;
// Создание директории
Directory::createDirectory('/path/to/dir');
// Работа с файлом
$file = new File('/path/to/file.txt');
$file->putContents('content');
$content = $file->getContents();
$exists = $file->isExists();
Типичные паттерны при разработке сервисных классов
Repository — класс для работы с хранилищем данных, изолирует ORM-код от бизнес-логики.
Factory — фабрика объектов по типу или параметрам.
Strategy — выбор алгоритма в рантайме (например, разные способы расчёта скидки в зависимости от типа клиента).
Эти паттерны не привязаны к Битрикс — это стандартный PHP. D7 просто даёт достаточно инструментов, чтобы их применять.
Сроки
| Задача | Срок |
|---|---|
| Набор сервисных классов для отдельной функциональности (5–10 классов) | 1–2 недели |
| Полная сервисная прослойка для модуля (репозитории, сервисы, фабрики, Result-объекты) | 3–5 недель |
| Написание юнит-тестов для готовых классов | +30–50% к срокам разработки |
Код на D7 API живёт долго. Его можно обновлять по частям, тестировать, переиспользовать в других проектах. Это окупается уже на первом значительном рефакторинге или при передаче проекта новому разработчику.







