# Как AVE.cms собирает сайт Эта глава объясняет публичную модель AVE.cms: что такое шаблон сайта, рубрика, поле, документ, навигация, запрос, блок и каталог, как они связаны и в каком порядке превращаются в готовую HTML-страницу. ## Общая схема ```text URL -> документ -> рубрика -> поля документа -> шаблон рубрики -> [tag:maincontent] -> шаблон сайта -> блоки и модули -> запросы -> навигации -> SEO и хлебные крошки -> готовый HTML ``` У каждой сущности одна основная зона ответственности: | Сущность | Назначение | | --- | --- | | Шаблон сайта | Общая HTML-оболочка: `head`, шапка, подвал и места для компонентов. | | Тема | Статические CSS/JS, изображения, шрифты и порядок их подключения. | | Рубрика | Тип контента: набор полей, правила URL, права и способ вывода одного документа. | | Поле | Контракт отдельного значения: редактор, валидация, хранение и публичный вывод. | | Документ | Конкретная запись рубрики со своим URL, состоянием, SEO и значениями полей. | | Навигация | Независимое дерево ссылок на документы и произвольные URL. | | Запрос | Сохраненная выборка документов с условиями, сортировкой и шаблоном списка. | | Блок | Переиспользуемый фрагмент разметки или логики. | | Каталог | Иерархия разделов, назначение документов, характеристики, фильтры и листинги. | | Модуль | Устанавливаемое расширение с маршрутами, тегами, таблицами, hooks и интерфейсом. | ## Практические руководства Если вы впервые работаете с системой или хотите понять новый редактор целиком, начните с подробной главы [Content Studio: от рубрики до публикации](content-studio.md). | Раздел панели | Руководство | | --- | --- | | Документы | [Создание, публикация, URL, ревизии и системные страницы](documents.md) | | Рубрики и поля | [Проектирование типа контента, формы и публичного вывода](rubrics.md) | | Шаблоны | [Внешняя оболочка сайта, теги, кеш и ревизии](templates.md) | | Twig-компоненты | [Точечные модульные вставки и границы их применения](twig-components.md) | | Темы | [CSS, JavaScript, изображения, шрифты и ZIP-пакеты темы](themes.md) | | Блоки | [Переиспользуемые фрагменты, редакторы и параметры](blocks.md) | | Навигация | [Шаблоны уровней, пункты и сборка HTML](navigation.md) | | Запросы | [Выборки документов, группы условий и шаблоны списка](requests.md) | | Каталог | [Универсальные деревья разделов, поля и фильтры](catalog.md) | Медиа, поля и модули вынесены в отдельные главы: [Медиа и миниатюры](../media/README.md), [Поля документов](../fields/README.md) и [Модульная система](../modules/README.md). Основной публичный сайт собирается встроенными сущностями AVE.cms. Twig не заменяет шаблоны сайта, рубрик и запросов. Для сложных модульных компонентов он подключается через обычный зарегистрированный тег; подробности приведены в [отдельной главе](twig-components.md). ## Три уровня шаблонов В AVE.cms слово «шаблон» используется для трех связанных, но разных уровней. ### 1. Шаблон сайта Шаблон сайта содержит весь HTML-документ: ```html [tag:title] [tag:rubheader]
[tag:maincontent]
[tag:rubfooter] ``` Главный контракт шаблона сайта — тег `[tag:maincontent]`. В него движок подставляет результат шаблона рубрики текущего документа или HTML системной страницы модуля. Шаблон сайта обычно содержит: - ``, `` и ``; - SEO-теги текущего документа; - общую шапку и подвал; - теги подключения CSS и JavaScript активной темы; - основную и вспомогательные навигации; - общие блоки и модульные компоненты; - `[tag:rubheader]` и `[tag:rubfooter]` для точечных вставок рубрики. Шаблон сайта не должен знать полный набор полей новости, товара или статьи. Этим владеет рубрика. ### 2. Основной шаблон рубрики Основной шаблон рубрики описывает содержимое одного документа: ```html

[tag:doc:document_title]

[tag:fld:lead]
[tag:fld:image]
[tag:fld:content]
``` После обработки полей этот HTML становится `[tag:maincontent]` внешнего шаблона сайта. ### 3. Дополнительный шаблон рубрики Документ может выбрать альтернативный вариант вывода той же рубрики. Например, у рубрики «Статьи» могут быть шаблоны: - обычная статья; - лонгрид; - фотогалерея; - промостраница. Набор полей и правила рубрики остаются общими, меняется только композиция конкретного документа. ## Рубрика Рубрика — это тип контента, а не папка документов. Примеры рубрик: - Новости; - Статьи; - Страницы; - Товары; - Сотрудники; - Вопросы и ответы. Рубрика определяет: - набор и группы полей; - порядок и ширину полей в редакторе документа; - значения полей по умолчанию; - основной и дополнительные публичные шаблоны; - шаблон тизера для элементов запросов; - внешний шаблон сайта; - шаблон формирования URL новых документов; - права групп пользователей; - Open Graph, вставки в header и footer; - код и hooks до и после сохранения документа. Например, рубрика «Новости» может содержать поля `image`, `lead`, `content`, `source` и `gallery`. Все документы этой рубрики используют один контракт данных, поэтому запросы и шаблоны могут обращаться к полям по стабильным alias. Подробнее о типах, настройках и хранении значений: [Поля документов](../fields/README.md). ## Документ Документ — конкретная запись выбранной рубрики. Он хранит: - ID и рубрику; - название и заголовок хлебных крошек; - alias и историю URL; - публикацию, удаление и срок действия; - автора и даты; - анонс; - SEO, robots, ключевые слова и теги; - значения полей рубрики; - выбранный дополнительный шаблон рубрики; - связи с каталогами и модулями. Документ предоставляет данные, но не должен самостоятельно описывать всю внешнюю оболочку сайта. ### URL документа Рубрика может формировать alias по шаблону: ```text news/%year/%month/%alias ``` Для документа с коротким alias `company-opened-office` результатом будет: ```text /news/2026/07/company-opened-office ``` Меню не участвует в формировании URL. После изменения alias прежний адрес может остаться в истории редиректов и вести на новый URL. ## Навигация Навигация — независимое дерево ссылок. Она хранит: - пункты и уровни вложенности; - связь с документом или произвольный URL; - название, описание, target и изображение; - CSS-класс и дополнительные атрибуты; - доступность группам пользователей; - шаблоны обычного и активного пункта каждого уровня. Навигация вставляется в страницу по alias: ```text [tag:navigation:main] ``` ### Как собирается HTML навигации Шаблоны навигации применяются в строгом порядке: ```text Обёртка: начало Уровень 1: начало Обычный или активный пункт уровня 1 ... Уровень 1: конец Обёртка: конец ``` Для вложенного меню шаблон пункта родительского уровня должен содержать место вывода следующего уровня: ```html
  • [tag:linkname] [tag:level:2]
  • [tag:linkname] [tag:level:3]
  • ``` `Уровень N: начало` задаёт обёртку списка. Тег `[tag:content]` внутри неё заменяется готовыми пунктами уровня. Если тег не указан, пункты добавляются после начальной разметки. `Уровень N: конец` всегда выводится после всех пунктов уровня. Поля `Обёртка: начало` и `Обёртка: конец` выводятся один раз вокруг всего дерева. Пример настроек первого уровня: ```html ``` Результат будет иметь полную структуру ``. Если в навигации нет доступных пунктов, внешние обёртки не выводятся. Удаление пункта меню не удаляет документ и не отключает его URL. Один документ может находиться в нескольких меню или не входить ни в одно. ## Запросы «Запрос» в AVE.cms — не HTTP-запрос, а сохраненная выборка документов. Он отвечает на два вопроса: 1. Какие документы выбрать? 2. Как вывести список и каждый его элемент? Запрос может задавать: - одну или несколько рубрик; - простые и вложенные группы условий; - сочетания `И` и `ИЛИ`; - сортировку; - лимит и пагинацию; - шаблон элемента; - обертку списка; - настройки кеширования. Примеры запросов: - последние новости; - популярные статьи; - материалы текущего автора; - связанные документы; - акции; - товары с заданными свойствами. Тег запроса использует ID или alias: ```text [tag:request:latest_news] ``` Условия с разной логикой должны быть сгруппированы явно: ```text Опубликован И ( Рубрика = Новости ИЛИ Рубрика = Статьи ) И ( Тег = Важное ИЛИ Просмотры > 1000 ) ``` Система сначала выбирает документы, затем применяет к каждому шаблон элемента и объединяет элементы в обертку списка. ## Блоки Блок — переиспользуемый фрагмент, который можно вставлять в шаблон сайта, шаблон рубрики, запрос или другой блок. Примеры: - контакты в подвале; - баннер; - форма подписки; - предупреждение; - преимущества; - сложный компонент с PHP-логикой. ```text [tag:sysblock:product_card] [tag:sysblock:contacts] ``` Блоки могут содержать запросы, навигации, модульные теги и условия. Для новой логики предпочтительнее передавать сложные операции в сервисы и модули, оставляя в блоке композицию и небольшие проектные условия. ## Каталог Каталог — отдельный слой над рубриками, документами и полями. Он не равен магазину и не должен предполагать, что каждый проект содержит товары. Каталог можно использовать для: - товарного каталога; - новостного портала; - базы знаний; - каталога услуг; - библиотеки документов; - базы специалистов или организаций; - любого структурированного раздела с фильтрацией. ### Место каталога в системе ```text Рубрики и поля | v Документы | v Каталог |- разделы и вложенность |- назначенные документы |- наборы характеристик |- фильтры и условия |- сортировка |- шаблон карточки и листинга `- индекс для быстрого публичного поиска ``` Рубрика отвечает за структуру одного документа. Каталог отвечает за то, где и как множество документов показывается пользователю. ### Что хранит каталог - собственное название и назначение; - корневые и вложенные разделы; - документы каждого раздела; - используемые поля и группы полей; - поля, включенные по умолчанию для новых разделов; - фильтры и их порядок; - условия показа разделов и документов; - настройки сортировки и пагинации; - конфигурацию карточки и листинга; - проекцию данных для быстрого публичного чтения. ### Каталог и запросы Обычный запрос подходит для независимой подборки: последние новости, работы автора, акции или связанные статьи. Каталог нужен, когда дополнительно требуются: - постоянная иерархия разделов; - назначение документов разделам; - фасетные фильтры; - согласованные карточки; - управляемая сортировка; - быстрый индекс большого набора документов. Запросы и каталог дополняют друг друга. Например, главная страница может показывать запрос «Новинки», а переход в раздел открывает полноценный каталог с фильтрами. ### Товарные возможности Товары являются расширением универсального каталога. Модуль товаров добавляет: - артикул, цену, старую цену и наличие; - товарные характеристики; - варианты одного товара; - карточки товара; - товарную индексацию. Корзина, заказы, оплаты и доставки принадлежат отдельным модулям. Их физическое удаление не должно удалять документы, рубрики и универсальную структуру каталога. ### Как выводится раздел каталога 1. По URL определяется каталог и его раздел. 2. Загружаются настройки раздела, набор полей и фильтров. 3. Входные значения фильтров нормализуются и проверяются. 4. Индекс выбирает подходящие документы. 5. Применяются сортировка и пагинация. 6. Для каждого документа собирается карточка. 7. Карточки объединяются в листинг. 8. Результат вставляется в публичную страницу каталога. Карточка является отдельным управляемым шаблоном. Она не должна копироваться в несколько системных блоков, иначе главная, каталог и подборки начинают выглядеть и работать по-разному. ### Индексация и кеш каталога Публичный фильтр не должен каждый раз разбирать все JSON-значения полей. После сохранения документа его данные проецируются в индекс каталога. Индекс содержит только значения, нужные для листинга, сортировки и фильтрации. Перестроение требуется после изменения: - документа или его полей; - назначения документа разделам; - набора характеристик; - настроек фильтров; - конфигурации карточки; - структуры вариантов товара. ## Модули Модуль — физически отделяемое расширение AVE.cms. Он может добавить: - собственные публичные и административные маршруты; - теги для шаблонов, рубрик и блоков; - новые типы полей; - hooks и события; - таблицы и миграции; - настройки и права; - пункт в меню панели управления; - действие в шапке, уведомления и Dashboard-виджет; - фоновые web-задачи и интеграции с внешними сервисами. ### Где модуль участвует в сборке До поиска документа `PublicKernel` загружает только включенные публичные части установленных модулей. После этого возможны три основных сценария. 1. **Собственный маршрут.** Модуль полностью отвечает на URL и завершает запрос без документа. Так работают API, callbacks и файловые endpoints. 2. **Страница в оболочке сайта.** Модуль предоставляет `[tag:maincontent]`, но использует выбранный шаблон сайта, SEO и общий публичный pipeline. 3. **Встроенный компонент.** Модуль регистрирует тег, который встречается в шаблоне сайта, рубрики, запроса или блока. Например, форма обратной связи может зарегистрировать тег: ```text [tag:module:contacts:feedback] ``` Шаблон отвечает только за место компонента. Валидация, отправка и хранение данных принадлежат модулю. ### Зависимости и жизненный цикл ```text Файлы доступны -> установка миграций и прав -> модуль включен -> маршруты, меню, hooks и теги работают ``` - **Отключение** прекращает загрузку runtime-вкладов, но сохраняет данные. - **Деинсталляция** выполняет объявленный модулем сценарий и убирает права. - **Физическое удаление** возможно только для отделяемого пакета после деинсталляции. - **Зависимости** не позволяют выключить модуль, пока от него зависит другой включенный пакет. Ядро, рубрики и документы не должны напрямую подключать PHP-файлы модуля. Взаимодействие строится через его публичные сервисы, теги, маршруты и hooks. Подробнее: [Модульная система](../modules/README.md). ## Порядок сборки публичной страницы Фактический pipeline одного публичного запроса: 1. `PublicKernel` запускает framework, сессию, авторизацию, модули, защиту и hooks. 2. Проверяются прямые публичные маршруты модулей. 3. URL разбирается на alias, пагинацию и дополнительные параметры. 4. По alias находится документ. 5. Если документа нет, проверяется история редиректов, затем загружается документ 404. 6. Вместе с документом загружаются рубрика, права и внешний шаблон сайта. 7. Проверяется полный кеш страницы. 8. Выполняется настроенный публичный код рубрики перед загрузкой документа. 9. Проверяются публикация документа и право текущей группы на чтение. 10. Основной или дополнительный шаблон рубрики заполняется полями документа. 11. Полученный HTML вставляется в `[tag:maincontent]` шаблона сайта. 12. Подставляются header, Open Graph и footer рубрики. 13. Обрабатываются поля запроса, блоки, системные блоки и тизеры. 14. Обрабатываются теги установленных модулей. 15. Выполняются сохраненные запросы. 16. Формируются навигации. 17. Подставляются SEO, данные документа, хлебные крошки и системные пути. 18. Выполняется разрешенный PHP из хранимых шаблонов. 19. Результат проходит через hooks ответа. 20. Для администратора добавляются быстрое редактирование и публичный debug. 21. Готовый HTML отправляется браузеру и при необходимости сохраняется в кеш. При попадании в полный кеш часть внутренних шагов не выполняется повторно, но логическая структура результата остается той же. ## Кеширование Публичный runtime использует несколько уровней: | Уровень | Что хранится | | --- | --- | | Snapshot документа | Нормализованные свойства документа и значения полей. | | Шаблон документа | Результат заполнения шаблона рубрики. | | Полная страница | Шаблон сайта вместе с содержимым и компонентами. | | Запрос | Результат тяжелой выборки или листинга. | | Каталог | Проекция для фильтрации, сортировки и карточек. | Ключи учитывают документ, рубрику, шаблон, группу пользователя, версии полей и пагинацию. После сохранения документа, рубрики, поля, запроса, шаблона или конфигурации каталога связанные записи должны инвалидироваться. Подробнее: [Кеш базы и контента](../database/cache.md). ## Hooks публичного pipeline Hook — именованная точка вмешательства в работу системы. Модуль подписывает обработчик на событие и получает структурированный контекст. Это позволяет добавлять проектную логику без изменения ядра. ### Основные публичные точки ```text frontend.request.received frontend.route.resolved content.document.loading content.document.loaded content.rubric.loading content.rubric.loaded content.query.loading content.query.loaded content.query.rendering content.query.rendered content.template.rendering content.template.rendered frontend.response.rendering frontend.response.rendered ``` События `loading` позволяют подготовить или заменить источник до чтения. События `loaded` получают уже загруженный объект и могут дополнить результат. События `rendering` и `rendered` работают с содержимым до и после рендера. ### Сохранение документов Для административного и API-сохранения предусмотрены отдельные стадии: ```text content.document.saving content.document.saved content.document.created content.document.updated content.document.published content.document.unpublished content.document.deleting content.document.deleted content.document.snapshot_built ``` Точные названия доступных событий и их контексты показываются в каталоге hooks. Обработчик должен проверять рубрику, ID или состояние документа и быстро завершаться, если событие ему не подходит. Примеры применения: - опубликовать новую статью в Telegram или Дзен; - передать заказ во внешнюю CRM; - проверить сертификат товара перед публикацией; - дополнить документ данными внешнего API; - поставить задачу на перестроение поискового индекса; - очистить CDN или сторонний кеш после изменения страницы. ### Hooks полей Тип поля сам отвечает за нормализацию и валидацию значения, но модуль может подписаться на общий цикл поля: ```text content.field.normalizing content.field.normalized content.field.validating content.field.validated content.field.saving content.field.saved content.field.rendering content.field.rendered ``` Обработчик обязательно ограничивается alias, ID или типом поля. Иначе он будет запускаться для каждого поля каждого документа. ### Каталог и hooks Индекс каталога обновляется вслед за сохранением документа и его snapshot, поэтому интеграции могут использовать фактические события `content.document.saved` и `content.document.snapshot_built`. Инвалидация проходит через `cache.invalidating` и `cache.invalidated`. Устанавливаемый каталоговый или товарный модуль может объявить дополнительные события через `hook_definitions`. Их имена и контекст становятся частью контракта именно этого модуля и появляются в общем каталоге hooks. Использовать необъявленное имя как системный контракт нельзя. ### Изменение и отмена результата `LifecycleEvent` может вернуть измененный результат. Отмена поддерживается только на стадиях, где это явно заявлено контрактом. При сохранении документа для контролируемого отказа используется `DocumentSaveEvent::fail()`. Ошибка должна быть понятной и не оставлять частично сохраненные данные. Для побочных действий после сохранения предпочтительна стадия `saved`. Для валидации и запрета операции используется стадия до записи. Внешний HTTP-вызов не следует выполнять внутри длинной транзакции, если его можно отложить до успешного сохранения. Полный каталог, приоритеты, форматы контекста и отладка: [Хуки и события](../hooks/README.md). ## Практический порядок создания сайта 1. Создать внешний шаблон сайта с `[tag:maincontent]`. 2. Создать рубрики для реальных типов контента. 3. Добавить и расположить поля каждой рубрики. 4. Собрать основной шаблон рубрики и необходимые альтернативы. 5. Создать документы и заполнить значения полей. 6. Настроить alias и проверить историю редиректов. 7. Создать навигации и привязать документы или URL. 8. Создать запросы для лент и связанных материалов. 9. Вынести повторяемые части в блоки. 10. При необходимости создать каталог, его разделы, поля и фильтры. 11. Установить только нужные проекту модули. 12. Проверить права, SEO, 404, пагинацию, кеш и мобильный вывод. ## Типовые композиции ### Новостной сайт ```text Рубрики: Новости, Статьи, Страницы Запросы: Последние, Популярные, По теме Каталог: необязателен; может использоваться как рубрикатор публикаций Модули: RSS, формы, авторизация — по необходимости ``` ### База знаний ```text Рубрики: Инструкции, FAQ, Справочные страницы Каталог: разделы знаний и фильтры по продукту/версии Запросы: Обновленные, Связанные, Популярные Навигация: основное меню и дерево документации ``` ### Интернет-магазин ```text Рубрики: Товары, Страницы, Новости Каталог: товарные разделы, характеристики и фильтры Модуль товаров: цены, наличие, варианты и карточки Commerce: корзина, заказы, избранное и история просмотров Gateways: оплаты, авторизация и доставки отдельными пакетами ``` ## Частые ошибки - Размещать всю разметку документа во внешнем шаблоне сайта. - Использовать меню для формирования URL документа. - Копировать одну карточку в несколько системных блоков. - Использовать длинную цепочку `И/ИЛИ` без групп условий. - Делать каталог зависимым от товаров и корзины. - Читать JSON всех полей при каждом публичном фильтре вместо индекса каталога. - Помещать большую бизнес-логику в хранимый шаблон вместо сервиса или модуля. - Забывать инвалидировать кеш после изменения шаблона, поля или каталога.