存储库#

本章将解释包和存储库的概念,介绍可用的存储库类型以及它们的工作原理。

概念#

在查看现有的不同类型的存储库之前,我们需要了解 Composer 所基于的一些基本概念。

#

Composer 是一个依赖项管理器。它在本地安装包。包本质上是一个包含某些内容的目录。在这种情况下,它是 PHP 代码,但理论上可以是任何东西。它包含一个包描述,其中包含名称和版本。名称和版本用于标识包。

实际上,在内部,Composer 将每个版本都视为一个单独的包。虽然在使用 Composer 时这种区别并不重要,但当你想要修改它时,它非常重要。

除了名称和版本之外,还有一些有用的元数据。与安装最相关的情報は源定义,它描述了从哪里获取包内容。包数据指向包的内容。这里有两个选项:dist 和 source。

Dist:dist 是包数据的打包版本。通常是一个已发布的版本,通常是一个稳定版本。

Source:source 用于开发。这通常来自源代码存储库,例如 git。当您想修改下载的包时,您可以获取它。

包可以提供其中任何一个,甚至两者。根据某些因素,例如用户提供的选项和包的稳定性,将优先选择其中一个。

存储库#

存储库是一个包源。它是一个包/版本的列表。Composer 将在所有存储库中查找您的项目所需的包。

默认情况下,只有 Packagist.org 存储库在 Composer 中注册。您可以通过在 composer.json 中声明来将更多存储库添加到您的项目中。

存储库仅对根包可用,并且您的依赖项中定义的存储库不会被加载。如果您想了解原因,请阅读常见问题解答条目

在解析依赖项时,包会从上到下从存储库中查找,默认情况下,只要在一个存储库中找到一个包,Composer 就停止在其他存储库中查找。阅读存储库优先级文章以了解更多详细信息并了解如何更改此行为。

类型#

Composer#

主要的存储库类型是 composer 存储库。它使用单个 packages.json 文件,其中包含所有包元数据。

这也是 packagist 使用的存储库类型。要引用 composer 存储库,请在 packages.json 文件之前提供路径。在 packagist 的情况下,该文件位于 /packages.json,因此存储库的 URL 将为 repo.packagist.org。对于 example.org/packages.json,存储库 URL 将为 example.org

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://example.org"
        }
    ]
}

#

唯一必需的字段是 packages。JSON 结构如下

{
    "packages": {
        "vendor/package-name": {
            "dev-master": { @composer.json },
            "1.0.x-dev": { @composer.json },
            "0.0.1": { @composer.json },
            "1.0.0": { @composer.json }
        }
    }
}

@composer.json 标记将是该包版本的 composer.json 的内容,包括至少以下内容

  • 名称
  • 版本
  • dist 或 source

这是一个最小的包定义

{
    "name": "smarty/smarty",
    "version": "3.1.7",
    "dist": {
        "url": "https://smarty.php.ac.cn/files/Smarty-3.1.7.zip",
        "type": "zip"
    }
}

它可以包含模式中指定的其他任何字段。

通知批处理#

notify-batch 字段允许您指定一个 URL,该 URL 将在用户每次安装包时被调用。该 URL 可以是绝对路径(这将使用与存储库相同的域),也可以是完全限定的 URL。

一个示例值

{
    "notify-batch": "/downloads/"
}

对于包含 monolog/monolog 包的 example.org/packages.json,这将向 example.org/downloads/ 发送 POST 请求,请求体如下

{
    "downloads": [
        {"name": "monolog/monolog", "version": "1.2.1.0"}
    ]
}

version 字段将包含版本号的规范化表示。

此字段是可选的。

元数据 URL、可用包和可用包模式#

metadata-url 字段允许您提供一个 URL 模板来提供存储库中所有包。它必须包含占位符 %package%

此字段是 Composer v2 中的新字段,如果同时存在 provider-includesproviders-url 字段,则优先于它们。为了与 Composer v1 和 v2 都兼容,您理想情况下应该提供这两个字段。新的存储库实现可能只需要支持 v2。但是。

一个例子

{
    "metadata-url": "/p2/%package%.json"
}

每当 Composer 查找包时,它都会将 %package% 替换为包名,并获取该 URL。如果允许包使用开发稳定性,它还会使用 $packageName~dev(例如 /p2/foo/bar~dev.json 以查找 foo/bar 的开发版本)再次加载该 URL。

包含包版本的 foo/bar.jsonfoo/bar~dev.json 文件必须仅包含 foo/bar 包的版本,例如 {"packages":{"foo/bar":[ ... versions here ... ]}}

缓存是通过使用 If-Modified-Since 标头完成的,因此请确保返回 Last-Modified 标头,并且它们是准确的。

版本数组还可以选择使用来自composer/metadata-minifierComposer\MetadataMinifier\MetadataMinifier::minify() 进行压缩。如果您这样做,您应该在顶级添加一个 "minified": "composer/2.0" 键,以告知 Composer 它必须将版本列表扩展回原始数据。请参阅https://repo.packagist.org/p2/monolog/monolog.json以获取示例。

任何不存在的请求包都必须返回 404 状态码,这将向 Composer 表明此包不存在于您的存储库中。请确保 404 响应速度很快,以避免阻塞 Composer。避免重定向到其他 404 页面。

如果您的存储库只有少量包,并且您想避免 404 请求,您也可以在 packages.json 中指定一个 "available-packages" 键,该键应该是一个数组,包含您的存储库中包含的所有包名。或者,您可以指定一个 "available-package-patterns" 键,这是一个包名模式数组(使用 * 匹配任何字符串,例如 vendor/* 将使 Composer 在此存储库中查找所有匹配的包名)。

此字段是可选的。

提供者 API#

providers-api 字段允许您提供一个 URL 模板来提供提供给定包名的所有包,但不提供具有该名称的包。它必须包含占位符 %package%

例如https://packagist.org.cn/providers/monolog/monolog.json列出了一些对 monolog/monolog 具有“提供”规则的包,但它没有列出 monolog/monolog 本身。

{
    "providers-api": "https://packagist.org.cn/providers/%package%.json",
}

此字段是可选的。

列表#

list 字段允许您返回与给定过滤器匹配的包的名称(如果没有过滤器,则返回所有名称)。它应该接受一个可选的 ?filter=xx 查询参数,其中可以包含 * 作为匹配任何子字符串的通配符。

替换/提供规则不应在此处考虑。

它必须返回一个包名称数组

{
    "packageNames": [
        "a/b",
        "c/d"
    ]
}

例如,请参阅https://packagist.org.cn/packages/list.json?filter=composer/*

此字段是可选的。

提供者包含和提供者 URL#

provider-includes 字段允许您列出一组列出此存储库提供的包名的文件。在这种情况下,哈希应该是文件的 sha256。

providers-url 描述了如何在服务器上找到提供者文件。它是从存储库根目录开始的绝对路径。它必须包含占位符 %package%%hash%

这些字段由 Composer v1 使用,或者如果您的存储库没有设置 metadata-url 字段。

一个例子

{
    "provider-includes": {
        "providers-a.json": {
            "sha256": "f5b4bc0b354108ef08614e569c1ed01a2782e67641744864a74e788982886f4c"
        },
        "providers-b.json": {
            "sha256": "b38372163fac0573053536f5b8ef11b86f804ea8b016d239e706191203f6efac"
        }
    },
    "providers-url": "/p/%package%$%hash%.json"
}

这些文件包含包名和哈希值列表,用于验证文件完整性,例如

{
    "providers": {
        "acme/foo": {
            "sha256": "38968de1305c2e17f4de33aea164515bc787c42c7e2d6e25948539a14268bb82"
        },
        "acme/bar": {
            "sha256": "4dd24c930bd6e1103251306d6336ac813b563a220d9ca14f4743c032fb047233"
        }
    }
}

上面的文件声明 acme/foo 和 acme/bar 可以从此存储库中找到,方法是加载 providers-url 引用的文件,将 %package% 替换为供应商命名空间包名,并将 %hash% 替换为 sha256 字段。这些文件本身包含如上所述的包定义。

这些字段是可选的。您可能不需要为自己的自定义存储库使用它们。

cURL 或流选项#

存储库是使用 cURL(Composer 2 启用了 ext-curl)或 PHP 流访问的。您可以使用 options 参数设置额外的选项。对于 PHP 流,您可以设置任何有效的 PHP 流上下文选项。有关更多信息,请参阅上下文选项和参数。当使用 cURL 时,只能配置有限的 httpssl 选项集。

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://example.org",
            "options": {
                "http": {
                    "timeout": 60
                }
            }
        }
    ],
    "require": {
        "acme/package": "^1.0"
    }
}

VCS#

VCS 代表版本控制系统。这包括 git、svn、fossil 或 hg 等版本控制系统。Composer 有一种存储库类型,用于从这些系统安装包。

从 VCS 存储库加载包#

这有几种用例。最常见的一种是维护您自己的第三方库的分支。如果您在项目中使用某个库,并且您决定更改库中的某些内容,您将希望您的项目使用修补后的版本。如果该库在 GitHub 上(大多数情况下是这种情况),您可以在那里创建一个分支,并将您的更改推送到您的分支。之后,您更新项目的 composer.json。您只需将您的分支作为存储库添加并更新版本约束以指向您的自定义分支即可。在 composer.json 中,您应该使用 "dev-"(不将其作为实际分支名称的一部分)作为您的自定义分支名称的前缀。有关版本约束命名约定的更多信息,请参阅

假设您修补了 monolog 以修复 bugfix 分支中的错误,这是一个示例

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/igorw/monolog"
        }
    ],
    "require": {
        "monolog/monolog": "dev-bugfix"
    }
}

当您运行 php composer.phar update 时,您应该获得修改后的 monolog/monolog 版本,而不是来自 packagist 的版本。

请注意,除非您真的打算长期维护该分支并完全脱离原始包,否则您不应该重命名该包。Composer 将正确地选择您的包而不是原始包,因为自定义存储库优先于 packagist。如果您想重命名该包,您应该在默认分支(通常是主分支)中执行此操作,而不是在功能分支中执行此操作,因为包名取自默认分支。

另请注意,如果您更改了已分支的存储库的 composer.json 文件中的 name 属性,则覆盖将不起作用,因为这需要与原始包匹配才能使覆盖生效。

如果其他依赖项依赖于您已分支的包,则可以内联别名它,使其匹配它原本不会匹配的约束。有关更多信息,请参阅别名文章

使用私有仓库#

完全相同的解决方案允许您使用 GitHub 和 Bitbucket 上的私有仓库。

{
    "repositories": [
        {
            "type": "vcs",
            "url":  "[email protected]:vendor/my-private-repo.git"
        }
    ],
    "require": {
        "vendor/my-private-repo": "dev-master"
    }
}

唯一的要求是为 git 客户端安装 SSH 密钥。

Git 替代方案#

Git 不是 VCS 仓库支持的唯一版本控制系统。以下是被支持的:

要从这些系统获取包,您需要安装它们各自的客户端。这可能很不方便。因此,对于 GitHub 和 Bitbucket 有特殊的支持,它们使用这些网站提供的 API 来获取包,而无需安装版本控制系统。VCS 仓库为它们提供了 dist,它们以 zip 的形式获取包。

将使用的 VCS 驱动程序将根据 URL 自动检测。但是,如果您出于任何原因需要指定一个,您可以使用 bitbucketgithubgitlabperforcefossilgitsvnhg 作为仓库类型,而不是 vcs

如果您在 GitHub 仓库上将 no-api 键设置为 true,它将像使用其他任何 git 仓库一样克隆仓库,而不是使用 GitHub API。但与直接使用 git 驱动程序不同,Composer 仍然会尝试使用 GitHub 的 zip 文件。

请注意

  • 要让 Composer 选择使用哪个驱动程序,仓库类型需要定义为 "vcs"
  • 如果您之前使用过私有仓库,这意味着 Composer 应该已经在缓存中克隆了它。如果您想使用驱动程序安装同一个包,请记住运行命令 composer clearcache,然后运行命令 composer update 更新 Composer 缓存并从 dist 安装包。
  • VCS 驱动程序 git-bitbucket 已被弃用,建议使用 bitbucket

Bitbucket 驱动程序配置#

请注意,Bitbucket 的仓库端点需要是 https 而不是 git。

设置 Bitbucket 仓库后,您还需要 设置身份验证

Subversion 选项#

由于 Subversion 没有对分支和标签的原生概念,Composer 默认情况下假设代码位于 $url/trunk$url/branches$url/tags 中。如果您的仓库有不同的布局,您可以更改这些值。例如,如果您使用大写名称,您可以像这样配置仓库

{
    "repositories": [
        {
            "type": "vcs",
            "url": "http://svn.example.org/projectA/",
            "trunk-path": "Trunk",
            "branches-path": "Branches",
            "tags-path": "Tags"
        }
    ]
}

如果您没有分支或标签目录,您可以通过将 branches-pathtags-path 设置为 false 来完全禁用它们。

如果包位于子目录中,例如 /trunk/foo/bar/composer.json/tags/1.0/foo/bar/composer.json,那么您可以通过将 "package-path" 选项设置为子目录让 Composer 访问它,在本例中,它将是 "package-path": "foo/bar/"

如果您有私有 Subversion 仓库,您可以将凭据保存在您的配置的 http-basic 部分(请参阅 模式)中。

{
    "http-basic": {
        "svn.example.org": {
            "username": "username",
            "password": "password"
        }
    }
}

如果您的 Subversion 客户端配置为默认存储凭据,这些凭据将被保存到当前用户,并且该服务器的现有保存的凭据将被覆盖。要更改此行为,请在您的仓库配置中设置 "svn-cache-credentials" 选项。

{
    "repositories": [
        {
            "type": "vcs",
            "url": "http://svn.example.org/projectA/",
            "svn-cache-credentials": false
        }
    ]
}

#

如果您想使用一个不支持 Composer 的项目,无论通过上面提到的哪种方式,您仍然可以通过使用 package 仓库来自己定义包。

基本上,您定义了与 composer 仓库的 packages.json 中包含的信息相同的信息,但仅针对单个包。同样,最少需要的字段是 nameversion,以及 distsource 之一。

以下是一个 Smarty 模板引擎的示例。

{
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "smarty/smarty",
                "version": "3.1.7",
                "dist": {
                    "url": "https://smarty.php.ac.cn/files/Smarty-3.1.7.zip",
                    "type": "zip"
                },
                "source": {
                    "url": "http://smarty-php.googlecode.com/svn/",
                    "type": "svn",
                    "reference": "tags/Smarty_3_1_7/distribution/"
                },
                "autoload": {
                    "classmap": ["libs/"]
                }
            }
        }
    ],
    "require": {
        "smarty/smarty": "3.1.*"
    }
}

通常,您会省略 source 部分,因为您并不真正需要它。

如果包含 source 键,reference 字段应该是一个指向将要安装的版本的引用。如果 type 字段是 git,它将是提交 ID、分支或标签名称。

注意:不建议将 git 分支名称用于 reference 字段。虽然这是有效的,因为它受 git checkout 支持,但分支名称是可变的,因此无法锁定。

如果 type 字段是 svn,reference 字段应该包含运行 svn co 时附加到 URL 的引用。

注意:这种仓库类型有一些限制,应该尽可能避免。

  • 除非您更改 version 字段,否则 Composer 不会更新包。
  • Composer 不会更新提交引用,因此,如果您使用 master 作为引用,您将不得不删除该包以强制更新,并且必须处理不稳定的锁定文件。

package 仓库中的 "package" 键可以设置为一个数组,以定义包的多个版本。

{
    "repositories": [
        {
            "type": "package",
            "package": [
                {
                    "name": "foo/bar",
                    "version": "1.0.0",
                    ...
                },
                {
                    "name": "foo/bar",
                    "version": "2.0.0",
                    ...
                }
            ]
        }
    ]
}

托管您自己的#

虽然您可能希望将您的包放在 Packagist 上,但在大多数情况下,托管您自己的仓库有一些用例。

  • 私有公司包:如果您是使用 Composer 内部包的公司的一部分,您可能希望将这些包保密。

  • 独立生态系统:如果您有一个项目拥有自己的生态系统,并且这些包并非由更大的 PHP 社区真正重用,您可能希望将它们与 Packagist 分开。一个例子是 WordPress 插件。

为了托管您自己的包,建议使用原生的 composer 类型的仓库,它提供了最佳的性能。

有一些工具可以帮助您创建 composer 仓库。

私有 Packagist#

私有 Packagist 是一款托管或自托管的应用程序,提供私有包托管以及 GitHub、Packagist.org 和其他包仓库的镜像。

请查看 Packagist.com 获取更多信息。

Satis#

Satis 是一个静态 composer 仓库生成器。它有点像 Packagist 的超轻量级、静态文件版本的版本。

您需要提供一个包含仓库的 composer.json,通常是 VCS 和包仓库定义。它将获取所有 require 的包并转储一个 packages.json,它就是您的 composer 仓库。

请查看 Satis GitHub 仓库 以及 处理私有包文章 获取更多信息。

工件#

在某些情况下,即使是 VCS,也无法将前面提到的仓库类型之一放到网上。一个典型的例子可能是通过构建工件进行跨组织的库交换。当然,大多数情况下这些都是私有的。为了按原样使用这些归档文件,可以使用 artifact 类型的仓库,其中包含一个文件夹,其中包含这些私有包的 ZIP 或 TAR 归档文件。

{
    "repositories": [
        {
            "type": "artifact",
            "url": "path/to/directory/with/zips/"
        }
    ],
    "require": {
        "private-vendor-one/core": "15.6.2",
        "private-vendor-two/connectivity": "*",
        "acme-corp/parser": "10.3.5"
    }
}

每个 zip 工件是一个 ZIP 归档文件,在根文件夹中包含 composer.json

unzip -l acme-corp-parser-10.3.5.zip
composer.json
...

如果两个归档文件包含包的不同版本,则它们都会被导入。当在工件文件夹中添加了具有较新版本的归档文件,并且您运行 update 时,该版本也将被导入,并且 Composer 将更新到最新版本。

路径#

除了工件仓库之外,您还可以使用路径仓库,它允许您依赖于本地目录,无论它是绝对的还是相对的。这在处理单片仓库时特别有用。

例如,如果您的仓库中具有以下目录结构

...
├── apps
│   └── my-app
│       └── composer.json
├── packages
│   └── my-package
│       └── composer.json
...

那么,要将 my/package 包添加为依赖项,在您的 apps/my-app/composer.json 文件中,您可以使用以下配置

{
    "repositories": [
        {
            "type": "path",
            "url": "../../packages/my-package"
        }
    ],
    "require": {
        "my/package": "*"
    }
}

如果包是本地 VCS 仓库,则当前签出的分支或标签可能会推断版本。否则,版本应该在包的 composer.json 文件中明确定义。如果无法通过这些方式解析版本,则假定为 dev-master

当无法从本地 VCS 仓库推断版本时,或者当您想要覆盖版本时,您可以在声明仓库时使用 versions 选项。

{
    "repositories": [
        {
            "type": "path",
            "url": "../../packages/my-package",
            "options": {
                "versions": {
                    "my/package": "4.2-dev"
                }
            }
        }
    ]
}

本地包将尽可能使用符号链接,在这种情况下,控制台中的输出将显示 Symlinking from ../../packages/my-package。如果不能使用符号链接,则包将被复制。在这种情况下,控制台将输出 Mirrored from ../../packages/my-package

您可以使用 "symlink": true 强制使用符号链接或使用 "symlink": false 选项强制镜像,而不是使用默认回退策略。在从单片仓库部署或生成包时,强制镜像非常有用。

注意:在 Windows 上,目录符号链接是使用 NTFS 连接实现的,因为它们可以由非管理员用户创建。在低于 Windows 7 的版本或 proc_open 被禁用的情况下,将始终使用镜像。

{
    "repositories": [
        {
            "type": "path",
            "url": "../../packages/*",
            "options": {
                "symlink": false
            }
        }
    ]
}

开头的波浪号将扩展到当前用户的 home 文件夹,并且环境变量将在 Windows 和 Linux/Mac 符号中解析。例如,~/git/mypackage 将自动从 /home/<username>/git/mypackage 加载 mypackage 克隆,相当于 $HOME/git/mypackage%USERPROFILE%/git/mypackage

注意:仓库路径也可以包含通配符,如 *?。有关详细信息,请参阅 PHP glob 函数

您可以配置构建包的 dist 引用(出现在 composer.lock 文件中)的方式。

存在以下模式

  • none - 引用将始终为空。这可以帮助减少锁定文件中的锁定文件冲突,但会降低清晰度,因为不清楚上次更新的时间以及包是否处于最新状态。
  • config - 引用是根据包的 composer.json 和仓库配置的哈希构建的。
  • auto(默认使用) - 引用是根据哈希构建的,就像使用 config 一样,但如果包文件夹包含 git 仓库,则 HEAD 提交的哈希将被用作引用。
{
    "repositories": [
        {
            "type": "path",
            "url": "../../packages/*",
            "options": {
                "reference": "config"
            }
        }
    ]
}

禁用 Packagist.org#

您可以通过在您的 composer.json 中添加以下内容来禁用默认的 Packagist.org 仓库。

{
    "repositories": [
        {
            "packagist.org": false
        }
    ]
}

您可以使用全局配置标志全局禁用 Packagist.org。

php composer.phar config -g repo.packagist false

模式 | 配置

发现错别字?文档中有什么不对劲? 分叉并编辑 它!