定制 besnovatyj/yii2-cms-modman 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

besnovatyj/yii2-cms-modman

Composer 安装命令:

composer require besnovatyj/yii2-cms-modman

包简介

Система управления модулями Yii2 CMS (compile-not-patch): discovery, реестр состояния, компиляция производных конфигов, lifecycle установки/удаления модулей.

README 文档

README

Система управления модулями CMS на принципе compile-not-patch: состояние модулей декларативно и единично (реестр), а вся Yii-конфигурация — производная и компилируется заново. Модуль на стадии тестирования.

Пришла на смену прежнему патч-based modman, который сохранён как образец в app/modules/modman_b (нерабочий, для сверки). Артефакты пишутся в канонические пути конфигурации приложения — без суффиксов и аддитивных слияний.

  • Идея и слои — ARCHITECTURE.md
  • Пошаговый трекер и журнал решений — plan.md
  • Сравнение «патч-modman → modman» — таблица в ARCHITECTURE.md §12

Карта каталога

catalog/      ModuleManifest + value-объекты, discovery (Filesystem/Composer), ManifestFactory,
              PackageCatalog, InvalidModule, маркер CmsMarker/CmsKind (extra.bescms)
registry/     ModuleStatus, Version, ModuleState, ModuleRegistry (атомарный lock-файл — источник истины)
compiler/     AtomicWriter, ConfigCompiler (чистая компиляция), MenuCompiler, ArtifactPaths
deps/         SemverConstraint, DependencyGraph, DependencyResolver (прямые + обратные зависимости)
migration/    MigrationOwnershipRepository, ModuleMigrationRunner (учёт владения, pending-only update)
lifecycle/    Planner/Executor/Steps/Handlers (mutex, commit-at-end, компенсация, reconcile, sync)
events/       ModuleLifecycleDispatcher (app-level шина межмодульных интеграций)
controllers/  backend/ModulesController (веб-интерфейс)
commands/     ModulesController + MenuController (консольные драйверы поверх того же фасада)
ModuleManager.php  фасад — единый публичный API для драйверов

Контракты модуля вынесены в пакеты. Capability-интерфейсы (DeclaresModule, Provides*) живут в пакете besnovatyj/yii2-cms-contracts (Besnovatyj\Contracts\module\*), а рантайм-базовый класс — в besnovatyj/yii2-cms-kernel (Besnovatyj\Kernel\module\CmsModule). Менеджер и модули используют версии из пакетов; локального каталога contract/ больше нет.

Подключение в приложение

1. Глобальный bootstrap — в app/common/config/main.php (app-level bootstrap), чтобы DI-проводка и шина событий поднимались рано, до загрузки скомпилированных артефактов:

'bootstrap' => ['log', 'queue', \Besnovatyj\Modman\Bootstrap::class],

Bootstrap поднимает DI-контейнер менеджера и его канал лога modman/*. Это же решает chicken-and-egg: менеджер обязан работать, чтобы скомпилировать конфиги, поэтому его проводка — глобальная, а не из компилируемого артефакта.

2. Компилируемые артефакты — это и есть конфиг приложения. Менеджер пишет в канонические пути (@config-dyn-gen/modulesConfigFile.php, componentsConfigFile.php, logChannelsConfigFile.php, menu-*.php, …), которые приложение и так загружает. Никаких _new и аддитивного слияния — это основной конфиг.

3. Холодный старт — автоматический. Bootstrap (шаг 1) сам регистрирует модуль Modman в приложении (Application::setModule), поэтому менеджер доступен даже когда modulesConfigFile.php пуст, устарел или ссылается на мёртвый старый id/namespace. Это разрывает chicken-and-egg: инструмент, который компилирует артефакт модулей, не зависит от этого артефакта, чтобы запуститься, — руками артефакт править не нужно (и нельзя, closed-loop compile-not-patch).

Регистрация идемпотентна (guard hasModule): как системный модуль (editable=false) Modman всё равно попадёт в modulesConfigFile.php при следующей recompile и переживёт любую пересборку (см. ARCHITECTURE §6); саморегистрация в bootstrap — постоянная страховка на холодный старт, а не костыль.

Использование

Веб: /Modman/backend/modules/index — список модулей/пакетов (фильтры по статусу/обновлениям, сортировка, пагинация), «План» (dry-run), установка, обновление, удаление, «Сверка» (reconcile), «Пересобрать конфиг», «Пересобрать меню». (sync — пока только в консоли, см. ниже.)

Консоль:

php yii Modman/modules/list
php yii Modman/modules/check <moduleId>
php yii Modman/modules/install <moduleId>
php yii Modman/modules/update <moduleId>
php yii Modman/modules/uninstall <moduleId>
php yii Modman/modules/reconcile
php yii Modman/modules/sync [--adoptAll]   # пересобрать реестр из реальности (см. ниже)
php yii Modman/modules/recompile
php yii Modman/menu/info       # диагностика локаций меню (вкл/выкл, файл, существование, число пунктов)
php yii Modman/menu/rebuild    # перекомпилировать только артефакты меню

(Для консоли модуль также должен быть в modules console-приложения.)

sync — восстановление реестра из фактического состояния

Реестр modules-state.php — единственный источник истины, но если его файл затёрли/побили, штатного способа восстановить его «из реальности» раньше не было (reconcile чинит только транзиентные записи, уже присутствующие в реестре). sync закрывает эту точку отказа — без ручной правки файла и без ручных контрольных сумм:

  • набор модулей берётся из discovery (composer + скан packages/besnovatyj);
  • применённые миграции — из БД-истории владения (MigrationOwnershipRepository);
  • manifestChecksum — пересчитывается детерминированно фабрикой манифестов.

«Установлен по факту» = уже installed в реестре, или за модулем числятся применённые миграции в БД, или передан --adoptAll. Иначе модуль пропускается (используйте install). После пересборки запускается recompile. Осиротевшие записи реестра (пакет исчез из каталога) не удаляются — только сообщаются. --adoptAll (-a) — крайняя мера: усыновить как installed все обнаруженные editable-модули для голого восстановления.

Маркер пакета CMS (extra.bescms)

Менеджер показывает только пакеты, явно помеченные как часть этой CMS, — чужие composer-зависимости из vendor/ (после переезда в GitHub их будут сотни) в список не попадают. Маркер живёт в composer.json в блоке extra (трогать type: yii2-extension нельзя — по нему Yii подключает свои bootstrap):

"extra": {
"bescms": {"kind": "module"}
}
  • kind: "module" — полноценный управляемый модуль. Должен также объявлять extra.moduleClass/moduleId и реализовывать контракт DeclaresModule (см. ниже). Попадает во вкладку «Модули».
  • kind: "package" — пакет CMS без жизненного цикла (например, виджет). Виден во вкладке «Пакеты», но не устанавливается менеджером.

Пакет без маркера менеджер игнорирует. Модуль, помеченный kind: module, но с ошибкой конфигурации (нет moduleClass, не реализует контракт, дубликат id), показывается строкой с причиной и погашенной кнопкой установки; подробности уходят в лог-канал modman/*, а не во flash на всю страницу.

Контракт модуля

Модуль наследует тонкий рантайм-базовый класс Besnovatyj\Kernel\module\CmsModule (раскладка controllerNamespace по контексту приложения, layout из активной темы, хук DI /config/container.php) и реализует DeclaresModule плюс нужные Provides* (статические методы — discovery не инстанцирует класс):

use Besnovatyj\Kernel\module\CmsModule;
use Besnovatyj\Contracts\module\DeclaresModule;
use Besnovatyj\Contracts\module\ProvidesMigrations;

final class Module extends CmsModule implements DeclaresModule, ProvidesMigrations
{
    public static function moduleId(): string { return 'Shortcode'; }
    public static function moduleVersion(): string { return '1.0.0'; }
    public static function isEditable(): bool { return true; }
    public static function moduleConfig(): array { return ['id' => 'Shortcode', 'params' => [...]]; }

    public static function migrationPath(): string { return __DIR__ . '/migrations'; }
    public static function migrationNamespace(): ?string { return __NAMESPACE__ . '\\migrations'; }
}

Соответствующий composer.json модуля объявляет и маркер, и класс/id:

"extra": {
"bescms": {"kind": "module"},
"moduleClass": "Besnovatyj\\Shortcode\\Module",
"moduleId": "Shortcode"
}

Размещение контрактов. Контракты и базовый класс вынесены в отдельные пакеты (besnovatyj/yii2-cms-contracts и besnovatyj/yii2-cms-kernel), поэтому модули не зависят от менеджера.

Сам менеджер — обычный модуль. modman/Module реализует тот же DeclaresModule с isEditable() === false: он виден в общем списке как «системный» (с версией, без кнопок установки/удаления), а не как исключение. Его проводка — глобальная (шаг 1), а в компиляцию он попадает как любой системный модуль.

Проверка синтаксиса (Docker)

docker compose exec php sh -c 'find /home/node/app/packages/besnovatyj/modman/src -name "*.php" -not -path "*/.git/*" -print0 | xargs -0 -n1 -P4 php -l'

Описание функционала и логики

Кнопка "Обновить" модуль

Это кнопка update-lifecycle модуля в modman — не git, не composer, не upstream-проверка. Она пересобирает интеграцию уже лежащего на диске кода модуля в приложение.

Путь: POST → actionUpdateModuleManager::update()UpdateHandler::update().

Когда появляется: только если installed && hasUpdate, где hasUpdate = модуль активен И (версия манифеста > версии в реестре ИЛИ checksum манифеста ≠ записанного в реестре). То есть код на диске изменился (новый тег/новый вклад), а реестр modman ещё отражает старое состояние.

Что делает (под LifecycleLock + мьютексом):

  1. Пишет в реестр статус Updating (write-ahead intent), шлёт событие BeforeUpdate (на него могут реагировать другие модули).
  2. Применяет только pending-миграции модуля — благодаря учёту владения миграциями, без down→up/переустановки (в старом modman «обновление» = снести и поставить заново; здесь — настоящий инкрементальный апдейт).
  3. Создаёт недостающие директории модуля (@static/...).
  4. Commit: обновляет запись в реестре — новая version, новый checksum, updatedAt = now, список применённых миграций дополняется, статус → Installed.
  5. LifecycleExecutor в конце перекомпилирует конфигурацию (merge-plan/артефакты) из реестра.
  6. При успехе — событие AfterUpdate и отчёт «обновлён до vX» в модалке; при ошибке — rollback к прежнему установленному состоянию.

Чего она НЕ делает: не тянет новый код с GitHub и не запускает composer update — предполагается, что новый код уже на диске (composer его уже поставил). Кнопка лишь синхронизирует под него БД-миграции, директории, реестр и скомпилированный конфиг.

Кнопка-иконка «обновить, минуя кэш» в колонке Upstream — другое: она лишь заново запрашивает последний тег с GitHub, ничего в системе не меняя.

besnovatyj/yii2-cms-modman 适用场景与选型建议

besnovatyj/yii2-cms-modman 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 07 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「cms」 「modules」 「modman」 「yii2」 「module-manager」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 besnovatyj/yii2-cms-modman 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 besnovatyj/yii2-cms-modman 我们能提供哪些服务?
定制开发 / 二次开发

基于 besnovatyj/yii2-cms-modman 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-15