Архітектура ECMS9
Загальна схема
app/
├── Config/ # конфігурація ядра (Routes, Filters, Events, Autoload,
│ │ # ModuleExtensions, Toolbar, Boot/production.php)
├── Commands/ # spark-команди ядра (cms9:*)
├── Controllers/ # базові контролери ядра (BaseFront, ...)
├── Database/ # міграції ядра (baseline + інкрементні)
├── Filters/ # фільтри ядра (CSRF, LsCache, AdminDebugToolbar, ...)
├── Helpers/ # хелпери (modules, cms, shop_render, widget)
├── Language/ # мовні файли ядра
├── Libraries/ # ядрові бібліотеки (Template, RenderPoint, Scheduler, JobQueue, оновлювачі)
├── Models/ # CI4-моделі ядра
├── Modules/ # ← модулі: Shop, Admin, NovaPoshta, Search, платіжки, ...
├── Propel/ # згенеровані легасі-ORM-моделі (Base/, Map/, Query)
└── ThirdParty/ # вендорені легасі-бібліотеки
themes/
├── administrator/ # адмін-тема (Twig/JS/CSS адмінпанелі)
└── <storefront>/ # теми вітрини (default, goodlook, fauna, ...)
public/ # фронт-контролер index.php + статичні ассети
writable/ # кеші, логи, завантаження, бекапи оновлень,
# store_modules.json, schedule.json
Ядро
Ядро — CodeIgniter 4 із розширеннями:
- Template pipeline (
App\Libraries\Template) — рендеринг сторінок вітрини через Twig-теми, зі вставними точками для модулів (аналітика, оптимізація зображень тощо). - Події — ключові бізнес-дії кидають івенти, на які підписуються модулі:
shopMakeOrder— створено замовлення (вітрина або адмінка);shopAdminOrderEdit— замовлення збережено в адмінці;shopAdminOrderUserCreate— в адмінці створено нового покупця;storefront_render_point:<name>— тема попросила розмітку модулів у точці рендеру;post_controller— хук рівня запиту (глобальна HTML-вставка, тік планувальника).
- Фільтри — CSRF, кеш сторінок (
LsCacheFilter), локаль, гейт увімкненості модуля, debug toolbar лише для адміна (Профайлер). - Реєстри модулів (
Config\ModuleExtensions) — єдине місце, де модулі вписуються в списки ядра без правок його файлів. Кожен модуль маєConfig/Registrar.php, чий статичнийModuleExtensions()повертає будь-які з ключів:csrfExempt,lsCacheNever,moduleEnabledAlways,adminMenu,jobHandlers,scheduledTasks,adminTranslations. Registrar auto-discovery CI4 зливає їх під час збірки конфігу. - Внутрішній планувальник (
App\Libraries\Scheduler) — слухачpost_controllerтікає не частіше ніж раз на хвилину і запускає простроченіscheduledTasksокремими підпроцесамиspark; стан уwritable/schedule.json, екран в адмінці —/admin/scheduler. Crontab на хостингу не потрібен (для тихих сайтів можна навести справжній крон наspark cms9:schedule-run). - Черга задач (
App\Libraries\JobQueue) — персистентні джоби, обробники яких знаходяться за ключамиmodule:typeзjobHandlers.
Модулі
Кожен модуль живе в app/Modules/<Name>/ і реєструється в БД (таблиця
components: enabled, active). Його PSR-4 простір імен береться або з
рядка в app/Config/Autoload.php (вбудовані модулі), або з
writable/store_modules.json (модулі, встановлені з магазину; зливається під
час завантаження). Детальніше — Структура модуля.
Дані
Співіснують два шари:
- Query Builder CI4 /
CodeIgniter\Model(\Config\Database::connect()) — правило для всього нового коду: нових модулів, нових файлів у наявних модулях. - Propel (легасі) — моделі
App\Propel\*зі згенерованими Query-класами (SOrdersQuery::create()->filterById(...)->findOne()); бутиться на кожен запит і досі густий в адмінці Shop та експортах. Правки всередині наявного Propel-коду лишаються в його стилі; не міксуйте обидва підходи в одному методі. Напрям — зняти Propel поетапно, тому новий код не має його нарощувати.
Схема: ядро везе міграції в app/Database/Migrations/ (baseline-міграція має
гвард — пропускається, якщо схема вже є, і відмовляється відкочувати
наповнений магазин), тому php spark migrate безпечний на живих сайтах.
Модулі міграцій не везуть: свої таблиці вони створюють ідемпотентно в методі
install()/ensureSchema() (CREATE TABLE IF NOT EXISTS), а store-пакети
можуть додати Resources/install*.sql, який інсталятор виконує по одному
стейтменту, пропускаючи помилки.
Теми
Storefront-теми — Twig. Тема не має містити хардкоду під конкретний сайт;
зовнішні ресурси — лише локальні або з офіційних CDN. Віджети модулів тема
виставляє через виклики render_point() (див.
Точки рендеру); spark shop:theme-coverage
показує, що тема показує. Теми не входять у пакет ядра, тож правка теми
розкочується на кожен сайт окремо. Адмін-тема спільна для всіх інсталяцій.