Шаблоны
Структура Twig-шаблонов DevCraft Admin.
HTML админки рендерится через Twig с автоэкранированием. Фабрика окружения — EnvironmentFactory.
Расположение
| Каталог | Назначение |
|---|---|
devcraft/src/templates/core/ | Общий каркас: layout, меню, формы, макросы |
devcraft/src/modules/{mod}/templates | Шаблоны конкретного модуля |
Отдельная .md-страница для каждого .twig-файла не создаётся — описывается только структура каталогов.
Структура core/
devcraft/src/templates/core/
├── layout.twig # Базовый макет Metro UI
├── partials/
│ ├── header.twig
│ ├── sidebar.twig
│ ├── breadcrumb.twig
│ └── footer.twig
├── forms/
│ ├── field.twig
│ ├── section.twig
│ └── tabs.twig
└── macros/
└── ui.twigТочный список файлов см. в репозитории плагина; имена могут дополняться при обновлениях.
Переменные шаблона
Страницы (PageInterface) передают в Twig контекст через PageOrchestrator:
module— метаданные из manifest;breadcrumbs— цепочкаBreadCrumb;settings— значения из конфигурации;menu— пункты навигации модуля.
Модульные шаблоны
Генератор модулей создаёт стартовый шаблон в templates/modules/{slug}/. Наследуйте core/layout.twig:
{% extends 'core/layout.twig' %}
{% block content %}
{% endblock %}AJAX (DevCraft.Ajax.post)
Layout задаёт body[data-mod="{{ mod }}"] и data-ajax-base.
DevCraft.Ajax.post(method, data) вызывает:
{ajaxBase}?controller=admin&method={method}&mod={data-mod}
Без mod сателлитные методы (save_suggestion и т.п.) не находятся в реестре.
Multipart-загрузка файлов
Общий транспорт панели (не отдельная страница модуля Admin):
| Слой | Артефакт |
|---|---|
| JS | DevCraft.Ajax.postMultipart(url, formData, onProgress?) в devcraft.js |
| Twig | core/includes/upload/drop_form.twig |
| PHP | UploadedFile |
Контракт FormData
- Поле файла — обычно
file(как вUploadedFile::fromFilesKey('file')). - JSON-метаданные модуля — поле
data(строка JSON), либо отдельные ключи. user_hashдобавляется автоматически, если его ещё нет вFormData.onProgress(loaded, total)— опциональный колбэк прогресса XHR.
const fd = new FormData();
fd.append('data', JSON.stringify({ kind: 'image' }));
fd.append('file', fileInput.files[0]);
DevCraft.Ajax.postMultipart(DevCraft.Ajax.url('upload_static_file'), fd, function (loaded, total) {
// прогресс-бар
}).then(function (response) {
DevCraft.Ajax.handleNotice(response);
});$uploaded = \DevCraft\Core\Http\UploadedFile::fromFilesKey('file');
$uploaded->assertExtension(['jpg', 'png', 'webp']);
$uploaded->moveTo($targetPath);Скачивание файла клиенту — FileResponse, не multipart.