# Настройки модуля ## Назначение Сквозная подсистема настроек модуля: форма в админ-панели, хранение значений и чтение их на backend. Это **каркас**, в который встраиваются остальные фичи — когда фиче нужен свой флаг/параметр, она добавляет поле в этот пайплайн, а не строит собственный механизм. ## Точки входа | action | Метод | Где объявлен | |--------------------|------------------------------------|---------------------| | `getSettingsForm` | `SettingsHandler::getSettingsForm` | `bastion/routes.php` | | `saveSettingsForm` | `SettingsHandler::saveSettingsForm`| `bastion/routes.php` | | `resetCache` | `SettingsHandler::resetCache` | `bastion/routes.php` | | `getSystemInfo` | `SettingsHandler::getSystemInfo` | `bastion/routes.php` | ## Ключевые файлы по слоям - **Дефолты:** `module/oc_telegram_shop/upload/oc_telegram_shop/configs/app.php` — структура всех настроек с дефолтными значениями (секции `app`, `telegram`, `metrics`, `store`, `orders`, `texts`, `sliders`, `mainpage_blocks`, `pulse`, `cron`). - **Handler (админка):** `module/.../bastion/Handlers/SettingsHandler.php` — `getSettingsForm()` отдаёт срез конфига (`Arr::getWithKeys` по списку секций), `saveSettingsForm()` сохраняет тот же срез. - **Сохранение:** `module/.../bastion/Services/SettingsService.php` — `update()` пишет в OpenCart-таблицу `oc_setting` через `model_setting_setting->editSetting('module_telecart', ['module_telecart_settings' => $data])`, синхронизирует статус модуля `module_tgshop` и очищает кэш. - **Чтение (backend):** `Openguru\OpenCartFramework\Config\Settings` — `get('a.b.c')` / `getAll()`. Расширение для витрины — `App\Services\SettingsService` (наследует `Settings`) и DTO в `src/DTO/Settings/` с типизированными геттерами (`is*()`, `get*()`). - **Сборка конфига:** `module/.../bastion/ApplicationFactory.php` (и точка входа `admin/controller/extension/module/tgshop.php`) — дефолты из `configs/app.php` мержатся с сохранёнными `module_telecart_settings` через `Arr::mergeArraysRecursively`, результат отдаётся в `Application`. - **Фронтенд (стор):** `frontend/admin/src/stores/settings.js` — Pinia setup-store: дефолтный state, `fetchSettings()` (`getSettingsForm`), `saveSettings()` (`saveSettingsForm`). - **Фронтенд (поля):** `frontend/admin/src/components/Settings/` — `ItemBool` (toggle), `ItemInput`, `ItemSelect`, `ItemImage`, `ItemToggleButton`. `ItemBool` → `Switcher` → `ToggleSwitch` (PrimeVue). Используются во `views/*View.vue`. ## Поток данных Чтение формы: `getSettingsForm` → `Settings::getAll()` (уже смерженный конфиг) → срез по секциям → JSON → стор `fetchSettings()` → поля во `*View.vue`. Сохранение: поле (`v-model`) → стор `saveSettings()` → `saveSettingsForm` → `SettingsService::update()` → `oc_setting` (`module_telecart_settings`) + сброс кэша. Чтение на backend: дефолты `configs/app.php` ⊕ сохранённые значения → `Application` → `Config\Settings` / DTO → сервисы (через DI-провайдеры, которые инжектят `getConfigValue('...')` в конструкторы). ## Как добавить новый toggle (чек-лист) 1. **Дефолт:** добавить ключ в нужную секцию `configs/app.php` (для булева — `true`/`false`). 2. **Backend-потребитель:** прочитать значение там, где оно нужно. Идиома модуля — читать в ServiceProvider (`$app->getConfigValue('секция.ключ')`) и **инжектить** в конструктор сервиса (не дёргать конфиг из глубины класса). При наличии DTO — добавить геттер. 3. **Стор:** добавить ключ с дефолтом в соответствующую секцию state в `frontend/admin/src/stores/settings.js`. 4. **View:** добавить компонент поля (для тумблера — `…текст-подсказка…`) в нужный `*View.vue`. 5. Убедиться, что секция уже перечислена в списках `Arr::getWithKeys` в `getSettingsForm`/ `saveSettingsForm` (если добавляешь поле в новую секцию — добавить и саму секцию в оба списка). ## Связанные фичи - [telecart-pulse](../telecart-pulse/CLAUDE.md) — heartbeat использует этот каркас: флаг `pulse.heartbeat_enabled` проходит весь путь от формы до backend-гейта. ## Нюансы и подводные камни - **PHP 7.4** в backend-коде (без `match`, промоушена свойств, union-типов и т.п.). - `getSettingsForm`/`saveSettingsForm` работают строго по **белому списку секций** (`Arr::getWithKeys`). Поле вне перечисленных секций не отдастся и не сохранится. - Секция `cron` содержит read-only поля (`cli_path`, `last_run`), которые добавляются при выдаче и вырезаются перед сохранением — не сохраняй вычисляемые значения. - `saveSettingsForm` сейчас вызывает пустой `validate()` — серверной валидации значений настроек по сути нет; не полагайся на неё. - После сохранения кэш сбрасывается целиком (`SettingsService::update` → `cache->clear()`). - Существующие установки не имеют сохранённого значения нового ключа — оно берётся из дефолта `configs/app.php` (мерж). Выбирай дефолт так, чтобы поведение «как было».