# Типичные поломки и как их избежать

Семь граблей, на которые чаще всего наступают ИИ-ассистенты (и люди). Формат каждого пункта: симптом → причина → как правильно.

## 1. Правка `.tpl` «не применилась»

**Симптом:** файл шаблона изменён, а на сайте — старая версия.

**Причина:** шаблоны компилируются в PHP и кэшируются в `storage/cache/tpl/`. Инвалидация — по времени изменения файла (mtime), и она ненадёжна: при копировании по FTP/scp или откате из бэкапа файл может приехать со старым mtime, и движок продолжит использовать кэш.

**Как правильно:** после каждой правки шаблонов сбрасывать кэш — `php bin/celena cache:clear` (или в панели: Настройки → Производительность → Очистить кеш). Взять за привычку: правка `.tpl` и очистка кэша — одно действие.

## 2. SQL под «не ту» СУБД

**Симптом:** код работал локально, а на сервере — ошибка SQL (или наоборот); чаще всего ломаются отчёты и «сырые» запросы.

**Причина:** Celena работает и на MySQL, и на PostgreSQL — а ассистент по привычке пишет диалектный SQL. Не переносятся: из MySQL — обратные кавычки `` ` ``, `GROUP_CONCAT`, `DATE_FORMAT`, `UNIX_TIMESTAMP`, `ON DUPLICATE KEY UPDATE`, `LIMIT x,y`; из PostgreSQL — `ILIKE`, приведение `::type`, `RETURNING`, `ON CONFLICT`, `string_agg`. Вторая ошибка — писать имя таблицы строкой без префикса.

**Как правильно:** запросы — через `$conn->builder('table')` (QueryBuilder сам генерирует переносимый SQL). Если без сырого SQL никак — только конструкции, общие для обеих СУБД, и имена таблиц через `$conn->table('name')` (подставит префикс из `.env`).

## 3. Комментарий `{* … *}` съел не то

**Симптом:** после «закомментирования» куска шаблона страница ломается, выводится мусор или сайт зацикливается.

**Причина:** комментарий вырезается до **первого** `*}`. Если внутри закомментированного куска встречается своё `*}` (например, конструкция вида `{p.*}` или вложенный комментарий) — комментарий закрывается раньше времени, и «хвост» оживает как рабочий код шаблона. В худшем случае оживает `{include …}` и получается рекурсия.

**Как правильно:** комментировать короткие фразы без фигурных скобок и звёздочек внутри. Отключаемый блок кода не комментировать, а удалять — история правок и бэкапы для того и существуют.

## 4. Скрипт с CDN «молча не работает»

**Симптом:** подключили библиотеку с jsDelivr/unpkg/Google Fonts — на странице она не работает, в консоли браузера ошибки о блокировке.

**Причина:** Content-Security-Policy сайта (задана в `.htaccess`) разрешает скрипты и стили только со своего домена (`script-src 'self'`). Внешние CDN блокируются браузером намеренно — это защита от подмены чужого кода.

**Как правильно:** скачать файл и положить локально — в `templates/<тема>/assets/` или `plugins/<плагин>/assets/`. Расширять список разрешённых доменов в CSP — только осознанно и в крайнем случае (например, счётчик аналитики).

## 5. Правка штатной темы вместо форка

**Симптом:** сайт выглядел как надо, но после обновления CMS все правки внешнего вида исчезли.

**Причина:** правили `templates/default/` или `templates/commerce/` напрямую, а обновление заливает штатные темы поверх (см. «Зоны движка»).

**Как правильно:** скопировать штатную тему под своим именем (`templates/mysite/`), поправить `theme.json`, включить в панели — и дальше править только копию. Обновления её не трогают.

## 6. PHP-код в `.tpl`

**Симптом:** на странице виден сам код — текст `<?php … ?>` вместо результата его работы.

**Причина:** шаблонизатор Celena намеренно не выполняет PHP: `<?php` и `<?=` экранируются как обычный текст. Это защита — шаблон не может стать «чёрным ходом» в сервер.

**Как правильно:** в шаблонах — только теги движка: `{var}`, `[if]…[/if]`, `[foreach]…[/foreach]`, `{include}` и т.д. (см. «Шаблоны»). Нужна логика или данные из базы — она пишется в плагине: свой тег шаблонизатора или async-блок, а шаблон лишь выводит готовые переменные.

## 7. Файлы кода в `public/uploads/`

**Симптом:** «положили скрипт в uploads, а он отдаёт 403 / не выполняется».

**Причина:** выполнение PHP в `public/uploads/` заблокировано на уровне сервера — намеренно. Каталог загрузок доступен на запись через панель, и исполняемый код там — первое, что ищет злоумышленник.

**Как правильно:** код живёт только в `plugins/` и `templates/`; `public/uploads/` — исключительно для медиафайлов из панели. Соседняя грабля — права доступа: файлы должны принадлежать пользователю веб-сервера, иначе после ручного копирования сайт может встретить вас ошибкой 500. Копировали файлы от root — верните владельца (`chown`).
