
使用 Composer 本地仓库(如 Satis)时,若仅安装 require/require-dev 中声明的顶层包而忽略其深层依赖,根本原因在于仓库元数据不完整——Satis 未从包内 composer.json 自动提取依赖信息,必须显式在 satis.json 中补全 require、autoload、conflict、replace、provide、suggest 等关键字段。
使用 composer 本地仓库(如 satis)时,若仅安装 `require`/`require-dev` 中声明的顶层包而忽略其深层依赖,根本原因在于仓库元数据不完整——satis 未从包内 `composer.json` 自动提取依赖信息,必须显式在 `satis.json` 中补全 `require`、`autoload`、`conflict`、`replace`、`provide`、`suggest` 等关键字段。
当你将本地仓库(例如通过 Satis 搭建)配置进 composer.json:
"repositories": [
{ "type": "composer", "url": "http://localhost/" }
]
并执行 composer install 后,Composer 不会像访问 Packagist 那样自动递归解析每个包的 composer.json 中声明的 require 字段。相反,它完全依赖于 Satis 生成的仓库元数据(packages.json) ——而该文件的内容,由你的 satis.json 配置决定。
⚠️ 关键误区:很多人误以为只要包 ZIP 文件中包含正确的 composer.json,Satis 就会自动读取并注入依赖关系。但事实是:Satis 默认仅提取极简元数据(如 name、version、dist),除非你明确在 satis.json 中启用并配置了完整的“root-level”字段映射。
✅ 正确做法:确保 satis.json 中为每个包(或全局 archive 配置)启用并同步以下核心字段:
{
"name": "my/private-repo",
"homepage": "http://localhost/",
"repositories": [
{ "type": "vcs", "url": "https://github.com/myorg/package-a" }
],
"require-all": true,
"output-dir": "web/",
"archive": {
"directory": "dist",
"format": "zip",
"skip-dev": false,
"absolute-directory": false
},
"providers": {
"laravel/framework": {
"require": {
"php": "^8.0",
"ext-json": "*",
"illuminate/contracts": "^9.0",
"symfony/console": "^6.0"
},
"autoload": { "psr-4": { "Illuminate\": "src/Illuminate/" } },
"conflict": { "laravel/installer": "<p>? 更推荐方式(自动化):使用 <code>"require-all": true</code> 并配合 <code>--skip-errors</code> 运行 Satis 构建,同时通过脚本预扫描所有包的 <code>composer.json</code>,动态提取上述字段写入 <code>satis.json</code> 或生成 <code>packages.json</code> 的扩展元数据。示例 PHP 扫描逻辑片段:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill9412" title="Workflow Decomposer"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dee630206.jpg" alt="Workflow Decomposer" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill9412" title="Workflow Decomposer" class="overflowclass">Workflow Decomposer</a>
<p class="overflowclass">工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。</p>
</div>
<a rel="nofollow" href="/xiazai/skill9412" title="Workflow Decomposer" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><pre class="brush:php;toolbar:false;">foreach ($packages as $package) {
$pkgJson = json_decode(file_get_contents($package . '/composer.json'), true);
$meta = array_filter([
'require' => $pkgJson['require'] ?? [],
'autoload' => $pkgJson['autoload'] ?? [],
'conflict' => $pkgJson['conflict'] ?? [],
'replace' => $pkgJson['replace'] ?? [],
'provide' => $pkgJson['provide'] ?? [],
'suggest' => $pkgJson['suggest'] ?? [],
]);
// 写入 satis.json 的 providers 或用于生成 packages.json
}? 注意事项:
-
satis.json中缺失require字段 → Composer 认为该包“无依赖”,导致illuminate/contracts、symfony/console等 Laravel 核心依赖不被安装,从而触发Class "IlluminateFoundationApplication" not found错误; -
autoload缺失 → 类无法自动加载,即使包已安装也会报Class not found; -
conflict/replace/provide虽非必需,但缺失可能导致版本冲突检测失效或插件兼容性异常; - 建议始终运行
satis build satis.json --no-interaction后,检查输出目录下的packages.json,确认目标包对象中是否包含"require"等字段及其内容是否完整。
✅ 验证修复效果:
构建完成后,清空项目 vendor/ 和 composer.lock,执行:
composer clear-cache composer install -vvv
观察日志中是否开始解析并下载 illuminate/*、symfony/* 等子依赖 —— 若成功,即表明元数据已正确注入。
总结:Composer 本地仓库不是“透明代理”,而是“元数据服务”。它的行为完全取决于你提供的 satis.json(或 Private Packagist 等替代方案的配置)。宁可多导出字段,不可少;宁可脚本自动化,不可手动遗漏。










