Files
XC_VM/docs/ru/development/module-lifecycle.md
T

142 lines
7.7 KiB
Markdown
Raw Normal View History

# Жизненный цикл модуля
Как XC_VM обнаруживает, загружает, включает/отключает, устанавливает и распространяет модули во время выполнения. Чтобы создать модуль, смотрите [Разработка модуля](module-authoring.md); для его расширений смотрите [Точки расширения модуля](module-extension-points.md).
## Включение / выключение модулей
Все обнаруженные модули загружаются по умолчанию. Используйте `src/config/modules.php` для переопределения состояния:
```php
return [
'my-module' => ['state' => 'disabled'], // preferred
// or legacy boolean (still accepted):
'my-module' => ['enabled' => false],
];
```
Доступные значения `state` (подкрепленные перечислением `ModuleState`):
|Ценность|Значение|
| ----- | ------- |
| `enabled` |Загрузка модуля (по умолчанию)|
| `disabled` |Модуль обнаружен, но пропущен|
| `installing` |Переходное состояние, заданное значением `ModuleManager` во время установки|
| `failed` |Ошибка установки; модуль пропущен (не загружен)|
> **Панельная диагностика.** На странице **Модули** отображается желтый значок **⚠ Проблема зависимости** рядом со статусом модуля, если требуемая зависимость отсутствует или не включена (например, в `plex` указано `Enabled`, а в `watch` - `failed`). Во всплывающей подсказке к значку перечислены конкретные проблемы. Это поле `dependency_warnings` вычисляется с помощью `ModuleManager::listModules()`.
Чтобы переопределить класс, разрешенный для модуля:
```php
return [
'my-module' => ['class' => 'XcVm\\Module\\MyModuleV2\\MyModuleV2Module'],
];
```
`config/modules.php` содержит только переопределения. Пустой или отсутствующий файл означает, что все обнаруженные
загружаются модули.
---
## Как работает загрузка
`ModuleLoader` выполняет эти действия при каждом запросе:
1. Сканирование `src/Modules/*/module.json`
2. Применяет переопределения из `config/modules.php`
3. Фильтры по окружающей среде (`main` / `lb` / `any`)
4. Определяет порядок загрузки:
- `pruneUnsatisfiableModules()` удаляет модули, требуемые зависимости которых недоступны (каскадно, с зарегистрированным предупреждением), чтобы загрузка никогда не прерывалась
- Топологическая сортировка (DFS) по графу зависимостей
- В пределах одной и той же группы зависимостей выполните сортировку по убыванию `priority`, затем по алфавиту
- Выдает `ModuleCycleException` для циклов (подкласс `\RuntimeException`; циклические зависимости остаются фатальными)
- Отсутствующие необязательные зависимости автоматически пропускаются
5. Resolves class name: `my-module` → FQN `XcVm\Module\MyModule\MyModuleModule`
(kebab-case → PascalCase; может быть переопределен с помощью клавиши `class` в конфигурации)
6. Регистрирует автозагрузчик модуля PSR-4 (сопоставляет `XcVm\Module\<Name>` с каталогом модуля)
7. Создает экземпляр класса module
В веб-контексте:
- `bootAll($container, $router)` → вызовы `boot()`, `registerRoutes()`, `registerNavbar()`,
и подписывается на события для каждого загруженного модуля
В контексте командной строки:
- `registerAllCommands($registry)` → вызывает `registerCommands()` для каждого загруженного модуля
---
## Marketplace: установка через расширение C
Модули с платформы устанавливаются через `ModuleManager::downloadFromPlatform()`:
```php
$manager->downloadFromPlatform(slug: 'my-module', version: '1.2.0', apiKey: $key);
```
Под капотом:
1. `XC_VM::module_install($slug, $version, $apiKey)` — Расширение C загружает, расшифровывает и распаковывает файлы
2. `installModule($slug)` — запускает `install()` в модуле
3. `EventDispatcher::dispatch(new PackageInstalledEvent(...))` — отправляет событие
4. `hotReload($slug, $path)` — загружает модуль в текущем запросе **без перезапуска PHP-FPM**
---
## Изолированные подсистемы
Модуль может быть полностью изолированной подсистемой со своей собственной точкой входа и начальной загрузкой
(например, Ministra). Это **соглашение**, а не маркерный интерфейс — он остается
обычный модуль `ModuleInterface`/`BaseModule`:
```php
class MyModule extends BaseModule {
public function getName(): string {
return 'my-module';
}
public function getVersion(): string {
return '1.0.0';
}
}
```
Изоляция означает, что подсистема работает через свою собственную общедоступную точку входа (например,
`my-module/portal.php`, путь относительно `src/`, который обрабатывает свой собственный bootstrap)
с отдельным путем начальной загрузки. Он использует общую инфраструктуру (базу данных, кэш, конфигурацию), но
участвует ли **нет** в основных `Router`, `ModuleLoader::bootAll()` или
`NavbarRegistry`. Реализации `boot()` и `registerRoutes()` обычно являются
оставлено как унаследованное бездействие.
---
## Composer обнаружение пакета
Модули могут распространяться в виде Composer пакетов с `"type": "xcvm-module"`:
```json
{
"name": "vendor/my-xcvm-module",
"type": "xcvm-module",
"extra": {
"xcvm": {
"module-path": "src"
}
}
}
```
`ModuleLoader` автоматически сканирует `vendor/composer/installed.json` (Composer 1 и 2
форматирует) и обнаруживает все установленные пакеты `xcvm-module` вместе со встроенным
каталог `src/Modules/`. Пакеты дедуплицируются — модуль как в `modules/`, так и в
`vendor/` загружается только один раз.
---