儲存庫#

This chapter will explain the concept of packages and repositories, what kinds of repositories are available, and how they work.

概念#

Before we look at the different types of repositories that exist, we need to understand some of the basic concepts that Composer is built on.

Package#

Composer 是一個依賴管理工具。它在本地安裝套件。A package is essentially just a directory containing something. In this case it is PHP code, but in theory it could be anything. And it contains a package description which has a name and a version. The name and the version are used to identify the package.

事實上,Composer 內部將每個版本視為一個單獨的套件。While this distinction does not matter when you are using Composer, it's quite important when you want to change it.

In addition to the name and the version, there is useful metadata. The information most relevant for installation is the source definition, which describes where to get the package contents. The package data points to the contents of the package. And there are two options here: dist and source.

Dist: The dist is a packaged version of the package data. Usually a released version, usually a stable release.

Source: The source is used for development. This will usually originate from a source code repository, such as git. You can fetch this when you want to modify the downloaded package.

Packages can supply either of these, or even both. Depending on certain factors, such as user-supplied options and stability of the package, one will be preferred.

Repository#

儲存庫是套件的來源。它是一張「套件/版本」的列表。Composer will look in all your repositories to find the packages your project requires.

By default only the Packagist repository is registered in Composer. You can add more repositories to your project by declaring them in composer.json.

Repositories are only available to the root package and the repositories defined in your dependencies will not be loaded. Read the FAQ entry if you want to learn why.

類型#

Composer#

主要的儲存庫類型是 composer 儲存庫。它使用一個單一 packages.json 檔案,其中包含所有套件的詮釋資料。

This is also the repository type that packagist uses. To reference a composer repository, just supply the path before the packages.json file. In the case of packagist, that file is located at /packages.json, so the URL of the repository would be packagist.org. For example.org/packages.json the repository URL would be example.org.

packages#

唯一要求的欄位是 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 的內容,最少包含:

這裡是一個最少的套件定義:

{
    "name": "smarty/smarty",
    "version": "3.1.7",
    "dist": {
        "url": "http://www.smarty.net/files/Smarty-3.1.7.zip",
        "type": "zip"
    }
}

它還可以包含任何其他指定在 綱要 中的欄位。

notify-batch#

The notify-batch field allows you to specify a URL that will be called every time a user installs a package. The URL can be either an absolute path (that will use the same domain as the repository) or a fully qualified URL.

一個範例值:

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

For example.org/packages.json containing a monolog/monolog package, this would send a POST request to example.org/downloads/ with following JSON request body:

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

version 欄位會包含正規化表示的版本號。

此欄位是選擇性的。

provider-includes 和 providers-url#

The provider-includes field allows you to list a set of files that list package names provided by this repository. The hash should be a sha256 of the files in this case.

The providers-url describes how provider files are found on the server. It is an absolute path from the repository root. It must contain the placeholders %package% and %hash%.

一個範例:

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

Those files contain lists of package names and hashes to verify the file integrity, for example:

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

The file above declares that acme/foo and acme/bar can be found in this repository, by loading the file referenced by providers-url, replacing %package% by the vendor namespaced package name and %hash% by the sha256 field. Those files themselves just contain package definitions as described above.

此欄位是選擇性的。 你或許不需要它來自訂你自己的儲存庫。

資料流選項#

packages.json 檔案是使用一個 PHP 資料流載入。你可以在該資料流上使用 options 參數來設定額外選項。 你可以設定任何有效的 PHP 資料流文本選項。 更多資訊,詳見 文本選項及參數

VCS#

VCS stands for version control system. This includes versioning systems like git, svn, fossil or hg. Composer has a repository type for installing packages from these systems.

從一個 VCS 儲存庫載入套件#

There are a few use cases for this. The most common one is maintaining your own fork of a third party library. If you are using a certain library for your project and you decide to change something in the library, you will want your project to use the patched version. If the library is on GitHub (this is the case most of the time), you can simply fork it there and push your changes to your fork. After that you update the project's composer.json. All you have to do is add your fork as a repository and update the version constraint to point to your custom branch. Your custom branch name must be prefixed with "dev-". For version constraint naming conventions see Libraries for more information.

Example assuming you patched monolog to fix a bug in the bugfix branch:

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

When you run php composer.phar update, you should get your modified version of monolog/monolog instead of the one from packagist.

Note that you should not rename the package unless you really intend to fork it in the long term, and completely move away from the original package. Composer will correctly pick your package over the original one since the custom repository has priority over packagist. If you want to rename the package, you should do so in the default (often master) branch and not in a feature branch, since the package name is taken from the default branch.

Also note that the override will not work if you change the name property in your forked repository's composer.json file as this needs to match the original for the override to work.

If other dependencies rely on the package you forked, it is possible to inline-alias it so that it matches a constraint that it otherwise would not. For more information see the aliases article.

使用私有儲存庫#

Exactly the same solution allows you to work with your private repositories at GitHub and BitBucket:

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

唯一的要求是安裝給 git 客戶端的 SSH 鍵。

Git 的替代方案#

Git is not the only version control system supported by the VCS repository. The following are supported:

To get packages from these systems you need to have their respective clients installed. That can be inconvenient. And for this reason there is special support for GitHub and BitBucket that use the APIs provided by these sites, to fetch the packages without having to install the version control system. The VCS repository provides dists for them that fetch the packages as zips.

The VCS driver to be used is detected automatically based on the URL. However, should you need to specify one for whatever reason, you can use fossil, git, svn or hg as the repository type instead of vcs.

If you set the no-api key to true on a github repository it will clone the repository as it would with any other git repository instead of using the GitHub API. But unlike using the git driver directly, Composer will still attempt to use github's zip files.

Please note:

Subversion 選項#

Since Subversion has no native concept of branches and tags, Composer assumes by default that code is located in $url/trunk, $url/branches and $url/tags. If your repository has a different layout you can change those values. For example if you used capitalized names you could configure the repository like this:

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

If you have no branches or tags directory you can disable them entirely by setting the branches-path or tags-path to false.

If the package is in a sub-directory, e.g. /trunk/foo/bar/composer.json and /tags/1.0/foo/bar/composer.json, then you can make Composer access it by setting the "package-path" option to the sub-directory, in this example it would be "package-path": "foo/bar/".

If you have a private Subversion repository you can save credentials in the http-basic section of your config (See Schema):

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

If your Subversion client is configured to store credentials by default these credentials will be saved for the current user and existing saved credentials for this server will be overwritten. To change this behavior by setting the "svn-cache-credentials" option in your repository configuration:

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

PEAR#

It is possible to install packages from any PEAR channel by using the pear repository. Composer will prefix all package names with pear-{channelName}/ to avoid conflicts. All packages are also aliased with prefix pear-{channelAlias}/.

使用 pear2.php.net 的範例:

{
    "repositories": [
        {
            "type": "pear",
            "url": "https://pear2.php.net"
        }
    ],
    "require": {
        "pear-pear2.php.net/PEAR2_Text_Markdown": "*",
        "pear-pear2/PEAR2_HTTP_Request": "*"
    }
}

In this case the short name of the channel is pear2, so the PEAR2_HTTP_Request package name becomes pear-pear2/PEAR2_HTTP_Request.

注意: The pear repository requires doing quite a few requests per package, so this may considerably slow down the installation process.

自訂 vendor 別名#

使用一個 vendor 自訂名稱來別名 PEAR 頻道套件是可行的。

範例:

Suppose you have a private PEAR repository and wish to use Composer to incorporate dependencies from a VCS. Your PEAR repository contains the following packages:

Without a vendor alias, Composer will use the PEAR channel name as the vendor portion of the package name:

Suppose at a later time you wish to migrate your PEAR packages to a Composer repository and naming scheme, and adopt the vendor name of foobar. Projects using your PEAR packages would not see the updated packages, since they have a different vendor name (foobar/IntermediatePackage vs pear-pear.foobar.repo/IntermediatePackage).

By specifying vendor-alias for the PEAR repository from the start, you can avoid this scenario and future-proof your package names.

To illustrate, the following example would get the BasePackage, TopLevelPackage1, and TopLevelPackage2 packages from your PEAR repository and IntermediatePackage from a Github repository:

{
    "repositories": [
        {
            "type": "git",
            "url": "https://github.com/foobar/intermediate.git"
        },
        {
            "type": "pear",
            "url": "http://pear.foobar.repo",
            "vendor-alias": "foobar"
        }
    ],
    "require": {
        "foobar/TopLevelPackage1": "*",
        "foobar/TopLevelPackage2": "*"
    }
}

Package#

If you want to use a project that does not support Composer through any of the means above, you still can define the package yourself by using a package repository.

Basically, you define the same information that is included in the composer repository's packages.json, but only for a single package. Again, the minimum required fields are name, version, and either of dist or source.

這裡是一個給 smarty 樣板引擎的範例:

{
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "smarty/smarty",
                "version": "3.1.7",
                "dist": {
                    "url": "http://www.smarty.net/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 的部份,因為你真的並不需要它。

:這個儲存庫類型有一些限制, 而且應該盡可能被避免:

  • Composer 不會更新套件除非你變更 version 欄位。
  • Composer 不會更新 commit 參考,所以如果你使用 master 做為參考,你將不得不刪除套件來強制一個更新, 而且將不得不面對一個不穩定的鎖文件。

託管你自己的#

While you will probably want to put your packages on packagist most of the time, there are some use cases for hosting your own repository.

For hosting your own packages, a native composer type of repository is recommended, which provides the best performance.

這裡有一些工具,可以幫助你建立一個 composer 儲存庫。

私有 Packagist#

Private Packagist is a hosted or self-hosted application providing private package hosting as well as mirroring of GitHub, Packagist.org and other package repositories.

Check out Packagist.com for more information.

Satis#

Satis 是一個靜態 composer 儲存庫的產生器。它有一點像超輕量版、靜態檔案為底的 packagist。

You give it a composer.json containing repositories, typically VCS and package repository definitions. It will fetch all the packages that are required and dump a packages.json that is your composer repository.

更多資訊,檢查 satis GitHub 儲存庫Satis 文章

Artifact#

There are some cases, when there is no ability to have one of the previously mentioned repository types online, even the VCS one. Typical example could be cross-organisation library exchange through built artifacts. Of course, most of the times they are private. To simplify maintenance, one can simply use a repository of type artifact with a folder containing ZIP archives of those private packages:

{
    "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"
    }
}

Each zip artifact is just a ZIP archive with composer.json in root folder:

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

composer.json
...

If there are two archives with different versions of a package, they are both imported. When an archive with a newer version is added in the artifact folder and you run update, that version will be imported as well and Composer will update to the latest version.

Path#

In addition to the artifact repository, you can use the path one, which allows you to depend on a local directory, either absolute or relative. This can be especially useful when dealing with monolithic repositories.

For instance, if you have the following directory structure in your repository:

- apps
\_ my-app
  \_ composer.json
- packages
\_ my-package
  \_ composer.json

Then, to add the package my/package as a dependency, in your apps/my-app/composer.json file, you can use the following configuration:

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

If the package is a local VCS repository, the version may be inferred by the branch or tag that is currently checked out. Otherwise, the version should be explicitly defined in the package's composer.json file. If the version cannot be resolved by these means, it is assumed to be dev-master.

The local package will be symlinked if possible, in which case the output in the console will read Symlinked from ../../packages/my-package. If symlinking is not possible the package will be copied. In that case, the console will output Mirrored from ../../packages/my-package.

Instead of default fallback strategy you can force to use symlink with "symlink": true or mirroring with "symlink": false option. Forcing mirroring can be useful when deploying or generating package from a monolithic repository.

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

Leading tildes are expanded to the current user's home folder, and environment variables are parsed in both Windows and Linux/Mac notations. For example ~/git/mypackage will automatically load the mypackage clone from /home/<username>/git/mypackage, equivalent to $HOME/git/mypackage or %USERPROFILE%/git/mypackage.

Note: Repository paths can also contain wildcards like * and ?. For details, see the PHP glob function.

停用 Packagist.org#

你可以透過添加這個到你的 composer.json 來停用預設的 Packagist 儲存庫:

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

You can disable Packagist.org globally by using the global config flag:

composer config -g repo.packagist false

綱要 | 配置

發現錯字?在這個文件中有些錯誤?只要 fork 並編輯 它!