Структура модуля
Модуль в Flute CMS — это самостоятельный пакет, который добавляет новую функциональность. Каждый модуль располагается в отдельной папке внутри app/Modules/ и имеет стандартную структуру.
Файловая структура
Типичный модуль выглядит так:
- module.json
- BlogProvider.php
Что за что отвечает
| Директория | Для чего нужна |
|---|---|
Providers/ | Точка входа модуля. Здесь регистрируются сервисы и загружаются ресурсы |
Http/Controllers/ | Контроллеры, обрабатывающие HTTP-запросы. Маршруты задаются через атрибуты |
database/Entities/ | Сущности для работы с базой данных через Cycle ORM |
Resources/config/ | Настройки модуля. Доступны через config('имя_файла.ключ') |
Resources/lang/ | Переводы на разные языки |
Resources/views/ | Blade-шаблоны для отображения страниц |
Components/ | Интерактивные Yoyo-компоненты (работают без перезагрузки страницы) |
Widgets/ | Блоки, которые можно размещать на страницах через админку |
Services/ | Бизнес-логика модуля (не обязательная папка) |
Middleware/ | Фильтры запросов (проверка прав, валидация и т.д.) |
Не все папки обязательны. Минимально нужны только module.json и Providers/.
Манифест модуля (module.json)
Каждый модуль должен иметь файл module.json в корне. Это “паспорт” модуля — без него система не узнает о модуле.
Минимальный пример
{
"name": "Blog",
"version": "1.0.0",
"description": "Модуль блога для публикации статей",
"providers": [
"Flute\\Modules\\Blog\\Providers\\BlogProvider"
]
}Полный пример с зависимостями
Если ваш модуль требует определённую версию PHP, другие модули или composer-пакеты:
{
"name": "Shop",
"version": "2.0.0",
"description": "Интернет-магазин с корзиной и оплатой",
"authors": ["Иван Петров"],
"providers": [
"Flute\\Modules\\Shop\\Providers\\ShopProvider"
],
"dependencies": {
"php": ">=8.2",
"flute": ">=1.0.0",
"modules": {
"Payments": ">=1.0.0"
},
"extensions": ["curl", "gd"],
"composer": {
"guzzlehttp/guzzle": "^7.0"
}
}
}Что можно указать в dependencies
| Тип | Описание | Пример |
|---|---|---|
php | Минимальная версия PHP | ">=8.2" |
flute | Минимальная версия Flute CMS | ">=1.0.0" |
modules | Другие модули, которые должны быть активны | {"Payments": ">=1.0.0"} |
extensions | PHP-расширения | ["curl", "gd"] |
composer | Composer-пакеты | {"guzzlehttp/guzzle": "^7.0"} |
theme | Требуемая тема | {"standard": ">=1.0.0"} |
Если зависимости не выполнены, модуль автоматически отключается. Проверьте логи, если модуль не работает.
Провайдер модуля
Провайдер — это главный класс модуля. Он говорит системе, какие сервисы регистрировать и какие ресурсы загружать.
Базовый провайдер
<?php
namespace Flute\Modules\Blog\Providers;
use Flute\Core\Support\ModuleServiceProvider;
class BlogProvider extends ModuleServiceProvider
{
/**
* Имя модуля (должно совпадать с именем папки)
*/
protected ?string $moduleName = 'Blog';
/**
* Регистрация сервисов.
* Вызывается ВСЕГДА, даже если модуль отключён.
* Здесь регистрируем классы в DI-контейнере.
*/
public function register(\DI\Container $container): void
{
// Регистрируем сервис для работы со статьями
$container->set(ArticleService::class, \DI\autowire());
}
/**
* Инициализация модуля.
* Вызывается ТОЛЬКО для активных модулей.
* Здесь загружаем ресурсы и настраиваем модуль.
*/
public function boot(\DI\Container $container): void
{
// Загружаем все ресурсы одной командой
$this->bootstrapModule();
}
}Что делает bootstrapModule()
Метод bootstrapModule() — это “магия”, которая автоматически находит и загружает все ресурсы модуля:
Сущности базы данных
Ищет классы в database/Entities/ и регистрирует их в Cycle ORM. После этого вы можете работать с базой через rep(Article::class)->findAll().
Конфигурацию
Файлы из Resources/config/ становятся доступны через config(). Например, файл blog.php доступен как config('blog.posts_per_page').
Переводы
Файлы из Resources/lang/ru/messages.php регистрируются для локализации. Используйте __('messages.welcome') в коде.
Контроллеры с маршрутами
Сканирует папки Http/Controllers/, Controllers/ и Submodules/*/Controllers/. Маршруты берутся из атрибутов #[Get], #[Post] и т.д.
Yoyo-компоненты
Классы из Components/ автоматически регистрируются. Компонент ArticleCard.php становится доступен как @yoyo('article-card').
Виджеты
Классы из Widgets/, реализующие WidgetInterface, можно использовать на страницах.
Если вам нужен файл routes.php для ручного определения маршрутов, добавьте в boot():
$this->loadRoutesFrom('routes.php');Загрузка ресурсов вручную
Иногда нужен более точный контроль. Вместо bootstrapModule() можно загружать ресурсы по отдельности:
public function boot(\DI\Container $container): void
{
// Только сущности БД
$this->loadEntities();
// Только конфигурацию
$this->loadConfigs();
// Только переводы
$this->loadTranslations();
// Шаблоны с кастомным namespace
// Теперь можно использовать: view('myblog::pages.index')
$this->loadViews('Resources/views', 'myblog');
// Маршруты из файла
$this->loadRoutesFrom('routes.php');
// SCSS стили (компилируются автоматически)
$this->loadScss('Resources/assets/scss/blog.scss');
// Компоненты и виджеты
$this->loadComponents();
$this->loadWidgets();
}Жизненный цикл модуля
Когда Flute запускается, модули проходят несколько этапов:
Поиск модулей
Система сканирует папку app/Modules/ и находит все module.json.
Проверка статуса
Каждый модуль сверяется с базой данных. Статусы:
active— модуль работаетdisabled— модуль отключён администраторомnotinstalled— модуль найден, но ещё не установлен
Проверка зависимостей
Для каждого активного модуля проверяются зависимости из module.json. Если что-то не так (нет нужного PHP-расширения, не установлен зависимый модуль), модуль автоматически отключается.
Регистрация (register)
Вызывается метод register() у ВСЕХ модулей. Здесь регистрируются сервисы в DI-контейнере.
Инициализация (boot)
Вызывается метод boot() только у АКТИВНЫХ модулей. Здесь загружаются ресурсы и выполняется настройка.
Кеширование
Для производительности Flute кеширует результаты сканирования файлов. По умолчанию кеш живёт 1 час.
Когда нужно сбросить кеш
- Добавили новый контроллер или компонент
- Изменили структуру папок модуля
- Добавили новые переводы
Как сбросить кеш
// Сбросить кеш всех модулей (список модулей, статусы)
app(\Flute\Core\ModulesManager\ModuleManager::class)->clearCache();
// Сбросить кеш конкретного модуля (файлы, переводы, компоненты)
$provider->clearFileCache();Изменить время кеширования
public function boot(\DI\Container $container): void
{
// Кешировать на 2 часа вместо 1
$this->setCacheDuration(7200);
$this->bootstrapModule();
}Расширения модуля
Если модуль большой, можно разбить его на расширения:
class ShopProvider extends ModuleServiceProvider
{
/**
* Расширения загружаются автоматически
*/
public array $extensions = [
CartExtension::class,
PaymentExtension::class,
DeliveryExtension::class,
];
}Каждое расширение — это класс, который реализует ModuleExtensionInterface:
<?php
namespace Flute\Modules\Shop\Extensions;
use Flute\Core\ModulesManager\Contracts\ModuleExtensionInterface;
class CartExtension implements ModuleExtensionInterface
{
public function register(): void
{
// Регистрация сервисов корзины
}
public function boot(): void
{
// Инициализация корзины
}
}У расширений вызывается только register(). Метод boot() НЕ вызывается автоматически.
Соглашения об именовании
Чтобы модули были совместимы и код был читаемым, следуйте этим правилам:
| Что | Как называть | Пример |
|---|---|---|
| Папка модуля | StudlyCase | Blog, UserProfile, PaymentGateway |
| Классы | StudlyCase | ArticleController, PaymentService |
| Методы | camelCase | getArticles(), processPayment() |
| Файлы шаблонов | kebab-case | article-card.blade.php, user-profile.blade.php |
| Константы | UPPER_CASE | MAX_ARTICLES, DEFAULT_LIMIT |
| Таблицы БД | snake_case с префиксом | blog_articles, shop_orders |
Имя папки модуля должно совпадать с полем name в module.json и свойством $moduleName в провайдере.