Skip to Content
Разработка модулейAPI провайдера

API провайдера модулей

API модулей Flute CMS предоставляет интерфейс для управления жизненным циклом модулей через ModuleManager и ModuleServiceProvider.

ModuleManager

ModuleManager — центральный класс для управления модулями. Он автоматически инициализируется при первом обращении: собирает module.json, синхронизирует статусы с БД, сортирует провайдеры и проверяет зависимости.

Получение экземпляра

<?php use Flute\Core\ModulesManager\ModuleManager; // Через DI контейнер $moduleManager = app(ModuleManager::class); // Через хелпер $moduleManager = modules();

Основные методы

<?php // Получение всех модулей (включая отключённые) $allModules = $moduleManager->getModules(); // Получение только активных модулей $activeModules = $moduleManager->getActive(); // Получение конкретного модуля $module = $moduleManager->getModule('News'); // Проверка существования модуля $exists = $moduleManager->issetModule('Shop'); // Получение JSON данных модуля $moduleJson = $moduleManager->getModuleJson('BansManager'); // Очистка кеша модулей $moduleManager->clearCache(); // Обновление списка модулей $moduleManager->refreshModules(); // Время загрузки модулей (для профилирования) $bootTimes = $moduleManager->getModulesBootTimes();

ModuleInformation

Каждый модуль представлен объектом ModuleInformation со следующими свойствами:

<?php $module = $moduleManager->getModule('News'); // Доступные свойства $module->key; // Ключ модуля: 'News' $module->name; // Название: 'News' $module->description; // Описание модуля $module->version; // Версия: '1.0.0' $module->status; // Статус: 'active', 'disabled', 'notinstalled' $module->createdAt; // Дата установки $module->dependencies; // Массив зависимостей $module->providers; // Массив провайдеров

Статусы модулей

СтатусКонстантаОписание
АктивенModuleManager::ACTIVEМодуль установлен и работает
ОтключёнModuleManager::DISABLEDМодуль установлен, но отключён
Не установленModuleManager::NOTINSTALLEDМодуль не установлен

Проверка статуса

<?php class ModuleInfoService { protected ModuleManager $moduleManager; public function __construct(ModuleManager $moduleManager) { $this->moduleManager = $moduleManager; } /** * Проверка активности модуля */ public function isModuleActive(string $moduleName): bool { $activeModules = $this->moduleManager->getActive(); return $activeModules->has($moduleName); } /** * Получение статуса модуля */ public function getModuleStatus(string $moduleName): string { if (!$this->moduleManager->issetModule($moduleName)) { return ModuleManager::NOTINSTALLED; } $module = $this->moduleManager->getModule($moduleName); return $module->status; } /** * Получение информации о модуле */ public function getModuleInfo(string $moduleName): ?ModuleInformation { try { return $this->moduleManager->getModule($moduleName); } catch (\Exception $e) { return null; } } }

Работа с зависимостями

<?php use Flute\Core\ModulesManager\ModuleDependencies; $dependencyChecker = $moduleManager->getModuleDependencies(); $module = $moduleManager->getModule('Shop'); $activeModules = $moduleManager->getActive(); $themeInfo = app(\Flute\Core\Theme\ThemeManager::class)->getThemeInfo(); try { // Проверка всех зависимостей модуля $dependencyChecker->checkDependencies( $module->dependencies, $activeModules, $themeInfo ); echo "Все зависимости выполнены"; } catch (\Flute\Core\ModulesManager\Exceptions\ModuleDependencyException $e) { echo "Ошибка зависимостей: " . $e->getMessage(); }

В обычном цикле загрузки ModuleManager автоматически проверяет зависимости и отключает проблемные модули.

Composer интеграция

<?php // Запуск composer install для конкретного модуля // (если есть app/Modules/<Module>/composer.json) $moduleManager->runComposerInstall($module); // Принудительный install для всего проекта $moduleManager->runComposerInstall(null, true);

ModuleServiceProvider

ModuleServiceProvider — базовый класс для всех провайдеров модулей. Он предоставляет методы для загрузки ресурсов модуля.

Базовая структура провайдера

<?php namespace Flute\Modules\News\Providers; use Flute\Core\Support\ModuleServiceProvider; class NewsProvider extends ModuleServiceProvider { /** * Список расширений (опционально) */ public array $extensions = []; /** * Регистрация сервисов в DI контейнере * Вызывается первым, до boot() */ public function register(\DI\Container $container): void { // Регистрация сервисов $container->set(NewsService::class, \DI\autowire()); } /** * Загрузка ресурсов модуля * Вызывается после register() */ public function boot(\DI\Container $container): void { // Автоматическая загрузка всех ресурсов $this->bootstrapModule(); // Загрузка представлений $this->loadViews('Resources/views', 'news'); // Загрузка стилей $this->loadScss('Resources/assets/scss/news.scss'); // Условная загрузка админ-пакета if (is_admin_path() && user()->can('admin')) { $this->loadPackage(new NewsAdminPackage()); } } }

Методы загрузки ресурсов

bootstrapModule()

Автоматически загружает все стандартные ресурсы модуля:

<?php $this->bootstrapModule(); // Эквивалентно вызову: // $this->loadEntities(); - сущности БД // $this->loadConfigs(); - конфигурация // $this->loadTranslations(); - переводы // $this->loadRouterAttributes();- маршруты из атрибутов // $this->loadComponents(); - компоненты // $this->loadWidgets(); - виджеты

bootstrapModule() кеширует результаты на время defaultCacheDuration для оптимизации.

Загрузка отдельных ресурсов

<?php // Загрузка сущностей базы данных из database/Entities $this->loadEntities(); // Загрузка конфигурации из Resources/config $this->loadConfigs(); // Загрузка переводов из Resources/lang $this->loadTranslations(); // Загрузка маршрутов через атрибуты из Http/Controllers $this->loadRouterAttributes(); // Загрузка компонентов из Components/ $this->loadComponents(); // Загрузка виджетов из Widgets/ $this->loadWidgets();

Представления и стили

<?php // Загрузка представлений // Первый аргумент — путь относительно модуля // Второй — namespace для использования в view() $this->loadViews('Resources/views', 'news'); // Теперь можно использовать: // view('news::articles.index') // view('news::partials.sidebar') // Загрузка SCSS файлов $this->loadScss('Resources/assets/scss/style.scss'); // Загрузка SCSS для админки if (is_admin_path()) { template()->getTemplateAssets()->addScssFile( $this->getModulePath('Resources/assets/scss/admin.scss'), 'admin' ); }

Компоненты

<?php // Загрузка одного компонента $this->loadComponent(NewsCardComponent::class, 'news-card'); // Регистрация нескольких компонентов $this->registerComponents([ 'news-card' => NewsCardComponent::class, 'news-list' => NewsListComponent::class, 'news-featured' => NewsFeaturedComponent::class, ]);

Админ-пакеты

<?php // Загрузка админ-пакета $this->loadPackage(new NewsAdminPackage()); // Условная загрузка только для админки if (is_admin_path()) { $this->loadPackage(new NewsAdminPackage()); }

Маршруты

<?php // Загрузка routes.php вручную (не вызывается автоматически) $this->loadRoutes(); // Файл должен быть: Resources/routes/routes.php

Получение путей

<?php // Получение абсолютного пути к файлу модуля $configPath = $this->getModulePath('Resources/config/settings.php'); // Результат: /var/www/app/Modules/News/Resources/config/settings.php

Практические примеры

Полноценный провайдер

<?php namespace Flute\Modules\Shop\Providers; use Flute\Core\Support\ModuleServiceProvider; use Flute\Modules\Shop\Services\ProductService; use Flute\Modules\Shop\Services\CartService; use Flute\Modules\Shop\Admin\Package\ShopPackage; class ShopProvider extends ModuleServiceProvider { public function register(\DI\Container $container): void { // Регистрация сервисов $container->set(ProductService::class, \DI\autowire()); $container->set(CartService::class, \DI\autowire()); // Регистрация интерфейсов $container->set(ProductServiceInterface::class, \DI\get(ProductService::class)); } public function boot(\DI\Container $container): void { // Базовая загрузка $this->bootstrapModule(); // Представления и стили $this->loadViews('Resources/views', 'shop'); $this->loadScss('Resources/assets/scss/shop.scss'); // Внешние библиотеки template()->addStyle(url('assets/css/libs/swiper.min.css')); template()->addScript(url('assets/js/libs/swiper.js')); // Компоненты $this->registerComponents([ 'product-card' => ProductCardComponent::class, 'cart-widget' => CartWidgetComponent::class, ]); // Слушатели событий events()->addListener( UserRegisteredEvent::NAME, [UserRegistrationListener::class, 'handle'] ); // Админ-пакет if (is_admin_path()) { $this->loadPackage(new ShopPackage()); } } }

Провайдер с условной загрузкой

<?php namespace Flute\Modules\BansManager\Providers; use Flute\Core\Support\ModuleServiceProvider; class BansManagerProvider extends ModuleServiceProvider { public function boot(\DI\Container $container): void { // Базовые ресурсы загружаем всегда $this->loadEntities(); $this->loadConfigs(); $this->loadTranslations(); // Основной сервис $container->set(BansManager::class, \DI\autowire()); // Фронтенд ресурсы только для фронтенда if (!is_admin_path()) { $this->loadViews('Resources/views', 'bans-manager'); $this->loadScss('Resources/assets/scss/main.scss'); $this->loadRouterAttributes(); // Компоненты для фронтенда $this->registerComponents([ 'bans-table' => BansTableComponent::class, 'mutes-table' => MutesTableComponent::class, ]); } // Админ ресурсы только для админки if (is_admin_path()) { $this->loadPackage(new BansManagerPackage()); template()->getTemplateAssets()->addScssFile( $this->getModulePath('Resources/assets/scss/admin.scss'), 'admin' ); } // Регистрация драйверов $bansManager = $container->get(BansManager::class); $bansManager->registerDriver('SourceBans', SourceBansDriver::class); } }

Обработка ошибок

<?php public function boot(\DI\Container $container): void { try { $this->bootstrapModule(); $this->loadCustomResources(); } catch (\Exception $e) { // Логируем ошибку logs('modules')->error("Ошибка загрузки модуля: " . $e->getMessage()); // В debug режиме пробрасываем исключение if (is_debug()) { throw $e; } // В production продолжаем работу без этого модуля } }

Лучшие практики

Разделяйте register() и boot()

  • register() — только регистрация сервисов в DI контейнере
  • boot() — загрузка ресурсов, регистрация слушателей

Используйте условную загрузку

Загружайте ресурсы только когда они нужны:

if (is_admin_path()) { $this->loadPackage(new AdminPackage()); }

Следуйте порядку загрузки

  1. Конфигурация
  2. Сущности БД
  3. Переводы
  4. Маршруты
  5. Компоненты и виджеты
  6. Слушатели событий

Кешируйте тяжёлые операции

bootstrapModule() автоматически кеширует результаты сканирования директорий.

Логируйте ошибки

Всегда логируйте ошибки инициализации для упрощения отладки.

Работа с DI контейнером

Регистрация сервисов

<?php public function register(\DI\Container $container): void { // Простая регистрация с autowiring $container->set(MyService::class, \DI\autowire()); // Регистрация интерфейса $container->set(MyServiceInterface::class, \DI\get(MyService::class)); // Регистрация с алиасом $container->set('my_service', \DI\get(MyService::class)); // Регистрация с фабрикой $container->set(MyService::class, function() { return new MyService(config('my_module.setting')); }); }

Получение сервисов

<?php // Через DI контейнер $service = app(MyService::class); // Через алиас $service = app('my_service'); // В конструкторе (autowiring) public function __construct(MyService $service) { $this->service = $service; }