必须接管installer、repositorymanager和事件生命周期三环节,因仅监听post-package-install等事件无法干预文件落盘前行为,installer的install()方法才可控制解压路径与中断流程,且插件需正确声明type、extra.class并实现plugininterface才能激活。

Composer插件不是“加个钩子就行”,真要干预安装路径、私有源鉴权或 autoload 生成时机,必须接管 Installer、RepositoryManager 和事件生命周期三个环节——否则逻辑会在中途被默认流程覆盖。
为什么 post-package-install 监听不到文件落盘前的行为
常见错误是只订阅 post-package-install 事件,此时包已解压完毕、autoload 已部分写入,你只能做收尾动作,无法修改安装路径或跳过 autoload 生成。真正能干预行为的节点在 Installer 层。
- Installer 的
install()方法执行时,包尚未解压到vendor/,可调用$package->setInstallationSource('dist')强制走压缩包而非 Git clone - 若需拦截安装(如校验签名失败),直接抛出
RuntimeException即可中断流程 - 不要手动操作
vendor/目录 —— 应统一使用$filesystem实例(Composer 内部注入的Composer\Util\Filesystem)
如何让 Composer 用你的 Installer 而不是 LibraryInstaller
关键不在插件注册,而在 composer.json 的 type 字段与插件中 getInstallers() 的显式绑定。Composer 会按包类型匹配 installer。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 如果你的企业包定义为
"type": "enterprise-module",插件类里必须实现getInstallers()并返回对应实例:public function getInstallers() { return [new EnterpriseModuleInstaller($this->io, $this->composer)]; } - 仅监听事件或重写
activate()不足以替换 installer;不提供getInstallers(),Composer 就不会调用你的 installer - Installer 子类必须继承
Composer\Installer\LibraryInstaller或其变体,并重写install()和update()
怎么替换默认 RepositoryManager 而不 fork Composer
插件无法直接“替换”已创建的 RepositoryManager,但可在 activate() 中用 $composer->setRepositoryManager() 覆盖它——前提是你的 manager 继承原类并重写初始化逻辑。
- 自定义 manager 需继承
Composer\Repository\RepositoryManager,并在构造函数中清空默认$this->repositories,注入企业内网源 + fallback 镜像 - 必须确保
composer-plugin-api版本与当前 Composer 主版本兼容(如 Composer 2.9 →"^2.9") - 若未正确设置
type: composer-plugin或extra.class,插件根本不会被加载,更谈不上替换 manager
最易被忽略的一点:所有 installer、repository manager、事件监听器的生效前提是插件本身被正确识别和激活——composer.json 中 type 字段拼错、extra.class 命名空间没 autoload、或 PHP 类没实现 PluginInterface,都会导致整个插件静默失效,没有任何报错提示。










