В прошлой части мы поставили оба инструмента и получили первый работающий endpoint. Теперь начинается то, что на практике важнее “Hello World”: как устроен проект и где именно должен жить ваш код, чтобы через 3 месяца вы не проклинали себя (или предыдущую команду).
Сегодня разберём:
- структуру каталогов (Laravel и Битрикс “по умолчанию”),
- где хранить кастомный код, чтобы не превратить проект в кашу,
- модули/пакеты как единицы расширения,
- MVC vs компонентный подход,
- и наконец — Service Container / Service Locator и почему это влияет на качество кода сильнее, чем выбор ORM.
Структура файлов и каталогов
Структура проекта важна не “потому что папки”, а потому что она отвечает на главный вопрос архитектуры: где у нас живут роли — роутинг, контроллеры, модели, представления, бизнес‑сервисы, конфиги.
Чтобы не писать общие слова, начнём с прикладной карты “где что лежит”, а затем разберём нюансы.
Карта “где что лежит”: Laravel ↔ Bitrix
| Архитектурная роль | Laravel (типовой путь) | Bitrix (типовой путь / аналог) |
|---|---|---|
| Точка входа (front controller) | public/index.php |
index.php в корне сайта (плюс служебные входные точки ядра) |
| Маршрутизация | routes/web.php, routes/api.php |
Исторически: ЧПУ + urlrewrite.php. Современно: D7‑роуты подключаются из local/routes/*.php (см. прошлую статью). |
| Контроллеры HTTP | app/Http/Controllers/* |
1) “контроллер‑стайл” через компоненты (/local/components/.../component.php и/или /local/components/.../class.php), 2) D7‑контроллеры на базе \Bitrix\Main\Engine\Controller обычно в local/modules/<vendor>.<module>/lib/ |
| Модели / слой данных | app/Models/* (Eloquent) |
D7 ORM: классы *Table / сущности обычно в local/modules/<vendor>.<module>/lib/... |
| Представления (HTML) | resources/views/*.blade.php |
1) Шаблон сайта: local/templates/<site_template>/, 2) шаблоны компонентов: .../templates/, 3) views в D7‑контроллерах: local/modules/<vendor>.<module>/views/... (см. renderView()) |
| Бизнес‑логика (сервисы) | app/Services/* / app/Actions/* (любой ваш слой) |
Лучше всего: сервисы/домен в local/modules/<vendor>.<module>/lib/ (или минимально — в local/lib/), а не внутри компонента/шаблона |
| Конфиги | config/*.php + .env |
.settings.php / .settings_extra.php (плюс настройки модулей и окружения) |
| Миграции | database/migrations/* |
В ядре нет “стандарта миграций” как в Laravel: обычно сторонние решения/скрипты/свои инструменты |
Laravel: структура, заточенная под MVC (и расширяемая без боли)
Laravel из коробки даёт очень понятные “центры тяжести” (официально: Directory Structure):
routes/— входные точки (web/api/console). Роуты не прячутся “где‑то”, это отдельная сущность проекта.app/Http/Controllers/— контроллеры, которые принимают запрос, вызывают сервис/домен и возвращают response.app/Models/— модели Eloquent (если вы используете “laravel‑way” для данных).resources/views/— Blade‑вьюхи: layout’ы, страницы, компоненты (про компоненты поговорим глубже в части про шаблонизацию).app/Providers/— сервис‑провайдеры: место, где вы регистрируете свои сервисы/биндинги и “вшиваете” инфраструктуру в контейнер.database/— миграции/сидеры/фабрики: данные и схема БД как часть кода.
Практическая мысль: Laravel не просто “разложил папки”, он подталкивает к разделению слоёв: HTTP отдельно, домен отдельно, представление отдельно.
Битрикс: структура, заточенная под “сайт из компонентов” (и требующая договорённостей)
В Битриксе точка сборки страницы исторически другая: страница/раздел собираются компонентами внутри шаблона сайта.
Базовая структура (официально: Структура директорий):
site-root/
local/ # ваш код и кастомизация
upload/ # файлы
bitrix/ # ядро
Но архитектурно важнее — что находится внутри local/:
1) Представления (вьюхи): шаблон сайта и шаблоны компонентов
- Шаблон сайта обычно живёт в
local/templates/<site_template>/. Это аналог “глобального layout’а” и структуры страниц: шапка/подвал, общие стили, подключения. - Шаблоны компонентов могут быть:
- рядом с компонентом в
local/components/<vendor>/<name>/templates/<template>/, - или переопределены на уровне шаблона сайта (частая практика для кастомизации без “форка” компонента).
- рядом с компонентом в
Компонентный подход в деталях: Структура компонента, Шаблоны компонента, Простые и комплексные компоненты.
2) “Контроллер” в классическом понимании: чаще всего это компонент
Во многих проектах роль “контроллера” фактически выполняет компонент — в формате component.php или пары class.php + templates/ (два распространённых варианта реализации):
- получает вход (параметры, запрос),
- собирает данные (часто — через API/ORM/сервисы),
- отдаёт массив в шаблон компонента.
Здесь важная развилка архитектуры:
- если в
component.php/class.phpживёт бизнес‑логика — проект быстро деградирует, - если
component.php/class.phpтонкий (оркестратор), а домен вынесен — проект “держит форму”.
3) “Вьюхи как во фреймворке”: D7‑контроллеры умеют рендерить представления
Если вы строите проект в более MVC‑стиле, в Битриксе можно (и это уже “официальный путь”) использовать D7‑контроллеры и возвращать HTML через renderView().
Важно: система ищет шаблон по пути вида local/modules/<vendor>.<module>/views/.... Это делает слой “представлений” в Битриксе ближе к классическому фреймворку, а не только к компонентам.
Документация: Контроллеры → Рендеринг представления (renderView).
4) Модели и бизнес‑логика: модуль как “нормальный дом”
Если вы хотите структуру уровня Laravel, самый устойчивый путь — выделять бизнес‑логику в модуль:
local/modules/<vendor>.<module>/lib/— классы домена, сервисы, интеграции;- здесь же обычно живут D7 ORM‑классы (
*Tableи связанные сущности); - здесь же уместны D7‑контроллеры (Engine Controller), если вы строите API/роутинг “по‑фреймворковому”.
Да, “можно и в local/lib/”, но модуль даёт границы, которые особенно нужны, когда проект растёт.
Laravel: “пакет = Composer + сервис‑провайдер”
Пакет в Laravel — это обычная Composer‑зависимость, которая может:
- добавить классы и конфиг,
- зарегистрировать сервисы через Service Provider,
- добавить роуты/миграции/команды/вьюхи.
Фундаментальный механизм — контейнер и провайдеры: Service Container, Service Providers.
Битрикс: “модуль = часть платформы со своим жизненным циклом”
Модуль в Битриксе — это “встроенная” единица системы: вы можете ставить/снимать модуль, он регистрируется, добавляет таблицы, события, настройки, админку, API.
Если вы хотите проект уровня “не один лендинг”, то модуль — зачастую лучший ответ на вопрос “куда класть бизнес‑код”, потому что он:
- изолирует доменную логику от компонентов,
- даёт структуру и границы (что особенно важно, когда в проекте 5+ разработчиков),
- уменьшает хаос обновлений и копипаста.
MVC в Laravel: “HTTP‑слой → домен → инфраструктура”
Классическая (и самая здравая) картина в Laravel выглядит так:
- Route: определяет входную точку,
- Controller: тонкий слой оркестрации,
- Service/Action: бизнес‑логика,
- Model (Eloquent) / Repository: доступ к данным,
- View / API Resource: представление результата.
Пример “как принято” (условно):
// Controller: получает запрос и вызывает сервис
final class OrderController
{
public function store(StoreOrderRequest $request, CreateOrder $action)
{
$order = $action->handle($request->validated());
return response()->json(['id' => $order->id]);
}
}
Ключ не в том, что “MVC красиво”, а в том, что Laravel поощряет разделение ответственности через предсказуемые точки расширения.
Компонентный подход в Битриксе: “страница собирается компонентами”
В Битриксе исторически центральная единица — компонент:
- он получает параметры (из шаблона/настроек),
- делает выборки/готовит данные,
- передаёт их в шаблон компонента.
Если упрощать, “страница” часто становится композицией компонентов, а “контроллер” как явная сущность может отсутствовать.
Это не плохо и не хорошо — это просто другой центр тяжести:
- плюс: удобно для CMS‑логики и контентных страниц, есть готовые компоненты,
- минус: если бизнес‑логика попадает в компоненты, проект быстро превращается в “spaghetti components”.
Практический вывод: в Битриксе особенно важно сознательно выстраивать слои, потому что платформа сама по себе “не заставляет”.
Service Container (Laravel) vs Service Locator (Bitrix): почему это вообще важно
Laravel: зависимости приходят “снаружи” (DI по умолчанию)
Laravel построен вокруг контейнера зависимостей: вы описываете, как создать сервис, а затем получаете его через:
- constructor injection,
- method injection,
- или через
app(SomeClass::class)/ фасады (но это отдельная тема).
Документация: Service Container, Facades.
Это даёт очень практичные вещи:
- код проще тестировать (можно подменять зависимости),
- классы имеют явные зависимости,
- меньше скрытой магии “откуда взялся объект”.
Битрикс: Service Locator как DI‑механизм (и как он реально работает)
В Битриксе Service Locator есть официально: \Bitrix\Main\DI\ServiceLocator (PSR‑11, доступен с версии main 20.5.400). Документация: Service Locator.
На практике это означает два важных “архитектурных” эффекта:
- Вы можете регистрировать сервисы (в
.settings.phpядра или в.settings.phpмодуля) и получать их по коду/классу — то есть у вас появляется “контейнер” и контролируемое создание объектов. - D7‑контроллеры умеют автовайрить зависимости: если класс не относится к встроенным “особым” аргументам и не описан в
getAutoWiredParameters, система попытается взять его из Service Locator (а если не зарегистрирован — создаст напрямую).
При этом, да, в старых/типичных проектах всё ещё встречается “глобальный контекст”:
- глобальные объекты (
$USER,$APPLICATION), - статические фасады‑стайл классы (
\Bitrix\Main\Application,\Bitrix\Main\Context), - “подключи модуль и используй классы”.
Это удобно “быстро сделать”, но у этого есть цена:
- зависимости становятся неявными,
- тестирование усложняется,
- растёт связность кода и платформы.
- выносить бизнес‑логику в сервисы/классы,
- прокидывать зависимости явно (хотя бы через конструктор),
- уменьшать количество прямых обращений к глобальному контексту из домена.
Сравнительная таблица: структура и архитектура
Шкала (как и в прошлой части): от -2 до +2.
| Критерий | Laravel (баллы) | Битрикс (баллы) | Комментарий |
|---|---|---|---|
| “Карта ролей” понятна сразу (роуты / контроллеры / модели / вьюхи) | +2 | 0 | В Laravel почти любой слой имеет “дом”. В Битриксе аналогичные роли есть, но они распределены между шаблоном сайта, компонентами и (желательно) модулем. |
| Где живёт UI (представления) | +2 | +2 | Laravel: resources/views. Битрикс: local/templates + шаблоны компонентов + views в модулях для D7‑контроллеров (renderView). |
| Где живёт бизнес‑логика (и как не смешать её с UI) | +2 | +1 | В Laravel разделение поддержано структурой. В Битриксе нужно сознательно выносить домен в сервисы/модуль, иначе логика “утечёт” в component.php и шаблоны. |
| Модульность и расширяемость | +2 | +2 | Laravel: Composer‑пакеты/провайдеры. Битрикс: модули. Оба подхода рабочие, просто разные по философии. |
| Работа с зависимостями (DI) | +2 | -1 | В Laravel DI — норма. В Битриксе часто встречается Service Locator‑стайл и глобальный контекст — архитектура быстрее деградирует без правил. |
| Итого за статью | +10 | +4 | |
| Общий счёт (накопительный) | +20 | +11 | Счёт будет накапливаться по мере выхода статей. |
Laravel даёт сильные границы “из коробки”: роли (роутинг/контроллеры/вьюхи/конфиг/миграции) имеют очевидные места, а зависимости естественно живут в DI‑контейнере. Это помогает даже средним командам держать проект “в форме”.
Битрикс даёт мощную платформу и компонентный подход, но границы нужно строить самим: разделять шаблон сайта / компоненты / модуль, держать домен вне component.php, и аккуратно работать с зависимостями и глобальным контекстом.
В следующей части перейдём к теме, где эти различия проявляются особенно ярко: маршрутизация (Laravel Routes vs urlrewrite vs D7‑роутинг).
Разложить проект так, чтобы не было стыдно
Задание для Laravel
Сделайте минимальную вертикаль “роут → контроллер → сервис → представление”:
- Создайте роут в
routes/web.php. - Создайте контроллер в
app/Http/Controllers/(пусть он будет тонким). - Создайте сервис в
app/Services/и подключите его через DI. - Создайте Blade‑вьюху в
resources/views/и верните её из контроллера.
Опорные доки: Service Container, Service Providers.
Задание для Битрикса
Сделайте минимальную вертикаль “страница → компонент → сервис → шаблон компонента” (и не забудьте, что компонент бывает в вариантах component.php и class.php):
- Создайте кастомный компонент в
local/components/<vendor>/<name>/. - Вынесите бизнес‑логику из
component.php/class.phpв отдельный класс:- минимум:
local/lib/..., - правильнее:
local/modules/<vendor>.<module>/lib/....
- минимум:
- В
component.php/class.phpоставьте только оркестрацию: вход → вызов сервиса →$arResult→ подключение шаблона. - Сделайте шаблон компонента в
.../templates/.default/и подключите компонент на тестовой странице или в шаблоне сайта.
Опорные доки: Структура директорий, материалы по компонентам: Структура компонента.