18 KiB
Repositories
This chapter will explain the concept of packages and repositories, what kinds of repositories are available, and how they work.
Concepts
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 is a dependency manager. It installs packages locally. 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.
In fact, internally composer sees every version as a separate package. 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
A repository is a package source. It's a list of packages/versions. 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.
Types
Composer
The main repository type is the composer
repository. It uses a single
packages.json
file that contains all of the package metadata.
This is also the repository type that packagist uses. To reference a
composer
repository, just supply the path before the packages.json
file.
In 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
The only required field is packages
. The JSON structure is as follows:
{
"packages": {
"vendor/package-name": {
"dev-master": { @composer.json },
"1.0.x-dev": { @composer.json },
"0.0.1": { @composer.json },
"1.0.0": { @composer.json }
}
}
}
The @composer.json
marker would be the contents of the composer.json
from
that package version including as a minimum:
- name
- version
- dist or source
Here is a minimal package definition:
{
"name": "smarty/smarty",
"version": "3.1.7",
"dist": {
"url": "http://www.smarty.net/files/Smarty-3.1.7.zip",
"type": "zip"
}
}
It may include any of the other fields specified in the schema.
notify-batch
The notify-batch
field allows you to specify an 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.
An example value:
{
"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"},
]
}
The version field will contain the normalized representation of the version number.
This field is optional.
includes
For larger repositories it is possible to split the packages.json
into
multiple files. The includes
field allows you to reference these additional
files.
An example:
{
"includes": {
"packages-2011.json": {
"sha1": "525a85fb37edd1ad71040d429928c2c0edec9d17"
},
"packages-2012-01.json": {
"sha1": "897cde726f8a3918faf27c803b336da223d400dd"
},
"packages-2012-02.json": {
"sha1": "26f911ad717da26bbcac3f8f435280d13917efa5"
}
}
}
The SHA-1 sum of the file allows it to be cached and only re-requested if the hash changed.
This field is optional. You probably don't need it for your own custom repository.
provider-includes and providers-url
For very large repositories like packagist.org using the so-called provider
files is the preferred method. 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.
An example:
{
"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
%name%
by the package name and %hash%
by the sha256 field. Those files
themselves just contain package definitions as described above.
This field is optional. You probably don't need it for your own custom repository.
stream options
The packages.json
file is loaded using a PHP stream. You can set extra options
on that stream using the options
parameter. You can set any valid PHP stream
context option. See Context options and parameters
for more information.
VCS
VCS stands for version control system. This includes versioning systems like git, svn or hg. Composer has a repository type for installing packages from these systems.
Loading a package from a VCS repository
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. 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.
It is possible to inline-alias a package constraint so that it matches a constraint that it otherwise would not. For more information see the aliases article.
Using private repositories
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"
}
]
}
The only requirement is the installation of SSH keys for a git client.
Git alternatives
Git is not the only version control system supported by the VCS repository. The following are supported:
- Git: git-scm.com
- Subversion: subversion.apache.org
- Mercurial: mercurial.selenic.com
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 dist
s for them that fetch the packages as zips.
- GitHub: github.com (Git)
- BitBucket: bitbucket.org (Git and Mercurial)
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 git
, svn
or
hg
as the repository type instead of vcs
.
Subversion Options
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
.
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}/
Example using pear2.php.net
:
{
"repositories": [
{
"type": "pear",
"url": "http://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
.
Note: The
pear
repository requires doing quite a few requests per package, so this may considerably slow down the installation process.
Custom vendor alias
It is possible to alias PEAR channel packages with a custom vendor name.
Example:
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:
BasePackage
IntermediatePackage
, which depends onBasePackage
TopLevelPackage1
andTopLevelPackage2
which both depend onIntermediatePackage
Without a vendor alias, Composer will use the PEAR channel name as the vendor portion of the package name:
pear-pear.foobar.repo/BasePackage
pear-pear.foobar.repo/IntermediatePackage
pear-pear.foobar.repo/TopLevelPackage1
pear-pear.foobar.repo/TopLevelPackage2
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
.
Here is an example for the smarty template engine:
{
"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.*"
}
}
Typically you would leave the source part off, as you don't really need it.
Hosting your own
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.
-
Private company packages: If you are part of a company that uses composer for their packages internally, you might want to keep those packages private.
-
Separate ecosystem: If you have a project which has its own ecosystem, and the packages aren't really reusable by the greater PHP community, you might want to keep them separate to packagist. An example of this would be wordpress plugins.
When hosting your own package repository it is recommended to use a composer
one. This is type that is native to composer and yields the best performance.
There are a few tools that can help you create a composer
repository.
Packagist
The underlying application used by packagist is open source. This means that you can just install your own copy of packagist, re-brand, and use it. It's really quite straight-forward to do. However due to its size and complexity, for most small and medium sized companies willing to track a few packages will be better off using Satis.
Packagist is a Symfony2 application, and it is available on GitHub. It uses composer internally and acts as a proxy between VCS repositories and the composer users. It holds a list of all VCS packages, periodically re-crawls them, and exposes them as a composer repository.
To set your own copy, simply follow the instructions from the packagist github repository.
Satis
Satis is a static composer
repository generator. It is a bit like an ultra-
lightweight, static file-based version of packagist.
You give it a composer.json
containing repositories, typically VCS and
package repository definitions. It will fetch all the packages that are
require
d and dump a packages.json
that is your composer
repository.
Check the satis GitHub repository and the Satis article for more information.
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 maintainance, one can simply specify
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:
$ tar -tf acme-corp-parser-10.3.5.zip
composer.json
...
If there is two archives with different versions of a package, they would be
imported both. If archive with newer version would be put to artifact folder and
update
command would be triggered, that version would replace previous, at it
logically seems.
Disabling Packagist
You can disable the default Packagist repository by adding this to your
composer.json
:
{
"repositories": [
{
"packagist": false
}
]
}