Este capítulo explicará o conceito de pacotes e repositórios, que tipos de repositórios estão disponíveis e como eles funcionam.
Antes de examinarmos os diferentes tipos de repositórios existentes, precisamos entender alguns dos conceitos básicos sobre os quais o Composer é construído.
O Composer é um gerenciador de dependências. Ele instala pacotes localmente. Um pacote é essencialmente um diretório que contém alguma coisa. Nesse caso, código PHP, mas em teoria poderia ser qualquer coisa. E ele contém uma descrição do pacote que possui um nome e uma versão. O nome e a versão são usados para identificar o pacote.
De fato, internamente o Composer vê cada versão como um pacote separado. Embora essa distinção não importe quando você estiver usando o Composer, ela é muito importante quando você quiser alterar o pacote.
Além do nome e da versão, existem metadados úteis. A informação mais relevante
para a instalação é a definição da fonte, que descreve onde obter o conteúdo do
pacote. Os dados do pacote apontam para o conteúdo do pacote. E há duas opções
aqui: dist
e source
.
Dist: é uma versão empacotada dos dados do pacote. Geralmente é uma versão publicada, normalmente é uma versão estável.
Source: é usada para desenvolvimento. Ela geralmente se origina de um repositório de código-fonte, como o git. Você pode obter o código-fonte quando quiser modificar o pacote baixado.
Os pacotes podem fornecer uma dessas ou até mesmo as duas. Dependendo de certos fatores, como as opções fornecidas pela pessoa e a estabilidade do pacote, uma delas terá a preferência.
Um repositório é uma fonte de pacotes. É uma lista de pacotes/versões. O Composer procurará em todos os seus repositórios para encontrar os pacotes que seu projeto exige.
Por padrão, apenas o repositório Packagist está registrado no Composer. Você
pode adicionar mais repositórios ao seu projeto declarando-os no
composer.json
.
Os repositórios estão disponíveis apenas para o pacote raiz e os repositórios definidos em suas dependências não serão carregados. Leia a [FAQ] faq-recursive-repos se quiser saber o porquê.
O principal tipo de repositório é o repositório composer
. Ele usa um único
arquivo packages.json
que contém todos os metadados dos pacotes.
Este também é o tipo de repositório que o Packagist usa. Para referenciar um
repositório composer
, forneça o caminho antes do arquivo packages.json
. No
caso do Packagist, esse arquivo está localizado em /packages.json
, portanto, o
URL do repositório seria repo.packagist.org
. Para
exemplo.org.br/packages.json
, o URL do repositório seria exemplo.org.br
.
O único campo obrigatório é packages
. A estrutura JSON é a seguinte:
{
"packages": {
"vendor/nome-pacote": {
"dev-master": { @composer.json },
"1.0.x-dev": { @composer.json },
"0.0.1": { @composer.json },
"1.0.0": { @composer.json }
}
}
}
O marcador @composer.json
seria o conteúdo do composer.json
dessa versão do
pacote, incluindo no mínimo:
name
version
dist
ousource
Aqui está uma definição mínima de pacote:
{
"name": "smarty/smarty",
"version": "3.1.7",
"dist": {
"url": "https://www.smarty.net/files/Smarty-3.1.7.zip",
"type": "zip"
}
}
Ela pode incluir qualquer um dos outros campos especificados no [esquema] schema.
O campo notify-batch
permite especificar um URL que será chamada sempre que
alguém instalar um pacote. O URL pode ser um caminho absoluto (que usará o mesmo
domínio que o repositório) ou um URL completamente qualificado.
Um exemplo de valor:
{
"notify-batch": "/downloads/"
}
Para exemplo.org.br/packages.json
contendo um pacote monolog/monolog
, isso
enviaria uma requisição POST
para exemplo.org.br/downloads/
com o seguinte
corpo da requisição JSON:
{
"downloads": [
{"name": "monolog/monolog", "version": "1.2.1.0"}
]
}
O campo version
conterá a representação normalizada do número da versão.
Este campo é opcional.
O campo provider-includes
permite listar um conjunto de arquivos que listam
nomes de pacotes fornecidos por este repositório. Nesse caso, o hash deve ser um
sha256 dos arquivos.
O campo providers-url
descreve como os arquivos do provedor são encontrados no
servidor. É um caminho absoluto da raiz do repositório. Deve conter os
placeholders %package%
e %hash%
.
Um exemplo:
{
"provider-includes": {
"providers-a.json": {
"sha256": "f5b4bc0b354108ef08614e569c1ed01a2782e67641744864a74e788982886f4c"
},
"providers-b.json": {
"sha256": "b38372163fac0573053536f5b8ef11b86f804ea8b016d239e706191203f6efac"
}
},
"providers-url": "/p/%package%$%hash%.json"
}
Esses arquivos contêm listas de nomes de pacotes e hashes para verificar a integridade do arquivo, por exemplo:
{
"providers": {
"acme/foo": {
"sha256": "38968de1305c2e17f4de33aea164515bc787c42c7e2d6e25948539a14268bb82"
},
"acme/bar": {
"sha256": "4dd24c930bd6e1103251306d6336ac813b563a220d9ca14f4743c032fb047233"
}
}
}
O arquivo acima declara que acme/foo
e acme/bar
podem ser encontrados neste
repositório, carregando o arquivo referenciado por providers-url
, substituindo
%package%
pelo nome do pacote com o nome do vendor e %hash%
pelo campo
sha256
. Esses arquivos contêm definições de pacotes, conforme descrito [acima]
packages.
Estes campos são opcionais. Você provavelmente não precisa deles para seu próprio repositório personalizado.
O arquivo packages.json
é carregado usando um stream PHP. Você pode definir
opções extras para esse stream usando o parâmetro options
. Você pode definir
qualquer opção de contexto de stream PHP válida. Consulte Opções e parâmetros
de contexto para obter mais informações.
VCS significa sistema de controle de versão. Isso inclui sistemas de versionamento como git, svn, fossil ou hg. O Composer possui um tipo de repositório para instalar pacotes desses sistemas.
Existem alguns casos de uso para isso. O mais comum é manter seu próprio fork de
uma biblioteca de terceiros. Se você estiver usando uma determinada biblioteca
para seu projeto e decidir alterar algo na biblioteca, desejará que seu projeto
use a versão alterada. Se a biblioteca estiver no GitHub (esse é o caso na
maioria das vezes), você pode simplesmente fazer o fork dela lá e fazer o push
das suas alterações para o seu fork. Depois disso, você atualiza o
composer.json
do projeto. Tudo que você precisa fazer é adicionar seu fork
como um repositório e atualizar a restrição de versão para apontar para seu
branch personalizado. No composer.json
, você deve prefixar o nome do seu
branch personalizado com dev-
. Para convenções de nomenclatura de restrições
de versão, consulte Bibliotecas para obter mais informações.
Exemplo assumindo que você alterou o monolog para corrigir um erro no branch
bugfix
:
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/igorw/monolog"
}
],
"require": {
"monolog/monolog": "dev-bugfix"
}
}
Quando você executar php composer.phar update
, você deve obter sua versão
modificada do monolog/monolog
em vez da versão do Packagist.
Observe que você não deve renomear o pacote, a menos que realmente pretenda
fazer o fork do projeto a longo prazo e se afastar completamente do pacote
original. O Composer selecionará seu pacote corretamente no lugar do original,
já que o repositório personalizado tem prioridade sobre o Packagist. Se você
deseja renomear o pacote, deve fazê-lo no branch padrão (geralmente master
) e
não no feature branch, pois o nome do pacote é obtido do branch padrão.
Observe também que a substituição não funcionará se você alterar a propriedade
name
no arquivo composer.json
do repositório criado pelo fork, pois ela
precisa corresponder à original para a substituição funcionar.
Se outra dependência depender do pacote criado pelo fork, é possível adicionar um alias em linha para que ela corresponda a uma restrição que, de outra forma, ela não iria. Para obter mais informações, [consulte o artigo sobre aliases] art-aliases.
Exatamente a mesma solução permite que você trabalhe com seus repositórios privados no GitHub e BitBucket:
{
"require": {
"vendor/meu-repo-privado": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "[email protected]:vendor/meu-repo-privado.git"
}
]
}
O único requisito é a instalação de chaves SSH para um cliente git.
Git não é o único sistema de controle de versão suportado pelo repositório VCS. Os seguintes são suportados:
- Git: git-scm.com
- Subversion: subversion.apache.org
- Mercurial: mercurial-scm.org
- Fossil: fossil-scm.org
Para obter pacotes desses sistemas, você precisa ter seus respectivos clientes
instalados. Isso pode ser inconveniente. E por esse motivo, há suporte especial
ao GitHub e BitBucket que usa as APIs fornecidas por esses sites para buscar os
pacotes sem precisar instalar o sistema de controle de versão. O repositório VCS
fornece opções dist
para eles que buscam os pacotes como arquivos zip.
- GitHub: github.com (Git)
- BitBucket: bitbucket.org (Git e Mercurial)
O driver VCS a ser usado é detectado automaticamente com base no URL.
Entretanto, se você precisar especificar um por qualquer motivo, poderá usar
git-bitbucket
, hg-bitbucket
, github
, gitlab
, perforce
, fossil
,
git
, svn
ou hg
como o tipo de repositório em vez de vcs
.
Se você definir a chave no-api
como true
em um repositório github
, clonará
o repositório como faria com qualquer outro repositório git, em vez de usar a
API do GitHub. Porém, diferente de usar o driver git
diretamente, o Composer
ainda tentará usar os arquivos zip do GitHub.
Note que:
- Para permitir que o Composer escolha qual driver usar, o tipo de
repositório precisa ser definido como
vcs
; - Se você já usou um repositório privado, isso significa que o Composer deve
ter clonado ele no cache. Se você deseja instalar o mesmo pacote com drivers,
lembre-se de executar o comando
composer clearcache
seguido do comandocomposer update
para atualizar o cache do Composer e instalar o pacote a partir dedist
.
O driver do BitBucket usa OAuth para acessar seus repositórios privados por meio das APIs REST do BitBucket e você precisará criar um consumidor OAuth para usar o driver, consulte a Documentação da Atlassian. Você precisará preencher o URL de callback com algo para satisfazer o BitBucket, mas o endereço não precisa ir a lugar algum e não é usado pelo Composer.
Depois de criar um consumidor OAuth no painel de controle do BitBucket, você
precisa configurar o arquivo auth.json
com as credenciais desta forma (mais
informações aqui):
{
"bitbucket-oauth": {
"bitbucket.org": {
"consumer-key": "minha-chave",
"consumer-secret": "meu-segredo"
}
}
}
Observe que o endpoint do repositório precisa ser https
em vez de git
.
Como alternativa, se você preferir não ter suas credenciais OAuth em seu sistema
de arquivos, poderá exportar o bloco bitbucket-oauth
acima para a variável de
ambiente COMPOSER_AUTH.
Como o Subversion não possui um conceito nativo de branches e tags, o Composer
assume por padrão que o código está localizado em $url/trunk
, $url/branches
e $url/tags
. Se seu repositório tiver um layout diferente, você poderá alterar
esses valores. Por exemplo, se você usasse nomes com iniciais em maiúsculas,
poderia configurar o repositório desta forma:
{
"repositories": [
{
"type": "vcs",
"url": "http://svn.exemplo.org.br/projeto-a/",
"trunk-path": "Trunk",
"branches-path": "Branches",
"tags-path": "Tags"
}
]
}
Se você não tiver um diretório branches
ou tags
, poderá desabilitá-los
completamente definindo branches-path
ou tags-path
como false
.
Se o pacote estiver em um subdiretório, por exemplo,
/trunk/foo/bar/composer.json
e /tags/1.0/foo/bar/composer.json
, você pode
fazer o Composer acessá-lo definindo a opção package-path
com o subdiretório,
nesse exemplo seria "package-path": "foo/bar/"
.
Se você possui um repositório Subversion privado, pode salvar as credenciais na
seção http-basic
da sua configuração (consulte Esquema):
{
"http-basic": {
"svn.exemplo.org.br": {
"username": "usuario",
"password": "senha"
}
}
}
Se o seu cliente Subversion estiver configurado para armazenar credenciais por
padrão, essas credenciais serão salvas para o usuário atual e as credenciais
salvas anteriormente para esse servidor serão substituídas. Você pode alterar
esse comportamento definindo a opção svn-cache-credentials
como false
na
configuração do seu repositório:
{
"repositories": [
{
"type": "vcs",
"url": "http://svn.exemplo.org.br/projeto-a/",
"svn-cache-credentials": false
}
]
}
É possível instalar pacotes de qualquer canal PEAR usando o repositório pear
.
O Composer prefixará todos os nomes de pacotes com pear-{NomeCanal}/
para
evitar conflitos. Todos os pacotes também têm alias com o prefixo
pear-{AliasCanal}/
.
Exemplo usando pear2.php.net
:
{
"repositories": [
{
"type": "pear",
"url": "https://pear2.php.net"
}
],
"require": {
"pear-pear2.php.net/PEAR2_Text_Markdown": "*",
"pear-pear2/PEAR2_HTTP_Request": "*"
}
}
Nesse caso, o nome abreviado do canal é pear2
, portanto, o nome do pacote
PEAR2_HTTP_Request
se torna pear-pear2/PEAR2_HTTP_Request
.
Nota: O repositório
pear
requer várias requisições por pacote, portanto, isso pode retardar consideravelmente o processo de instalação.
É possível criar um alias de pacotes de canais PEAR com um nome de vendor personalizado.
Exemplo:
Suponha que você tenha um repositório PEAR privado e deseje usar o Composer para incorporar dependências de um VCS. Seu repositório PEAR contém os seguintes pacotes:
PacoteBase
PacoteIntermediario
, que depende doPacoteBase
PacoteDeAltoNivel1
ePacoteDeAltoNivel2
, que dependem doPacoteIntermediario
Sem um alias de vendor, o Composer usará o nome do canal PEAR como a parte do vendor no nome do pacote:
pear-pear.foobar.repo/PacoteBase
pear-pear.foobar.repo/PacoteIntermediario
pear-pear.foobar.repo/PacoteDeAltoNivel1
pear-pear.foobar.repo/PacoteDeAltoNivel2
Suponha que posteriormente você deseje migrar seus pacotes PEAR para um esquema
de nomenclatura e repositório do Composer e adote o nome de vendor foobar
.
Os projetos que usam seus pacotes PEAR não veriam os pacotes atualizados, pois
eles têm um nome de vendor diferente (foobar/PacoteIntermediario
vs.
pear-pear.foobar.repo/PacoteIntermediario
).
Ao especificar vendor-alias
para o repositório PEAR desde o início, você pode
evitar esse cenário e proteger os nomes de seus pacotes de mudanças futuras.
Para ilustrar, o exemplo a seguir obteria os pacotes PacoteBase
,
PacoteDeAltoNivel1
e PacoteDeAltoNivel2
do seu repositório PEAR e o
PacoteIntermediario
de um repositório do GitHub:
{
"repositories": [
{
"type": "git",
"url": "https://github.com/foobar/intermediario.git"
},
{
"type": "pear",
"url": "http://pear.foobar.repo",
"vendor-alias": "foobar"
}
],
"require": {
"foobar/PacoteDeAltoNivel1": "*",
"foobar/PacoteDeAltoNivel2": "*"
}
}
Se você deseja usar um projeto que não oferece suporte ao Composer por qualquer
um dos meios acima, você mesmo ainda pode definir o pacote usando um repositório
package
.
Basicamente, você define as mesmas informações incluídas no packages.json
do
repositório composer
, mas apenas para um único pacote. Novamente, os campos
mínimos necessários são name
, version
e dist
ou source
.
Aqui está um exemplo para o mecanismo de template Smarty:
{
"repositories": [
{
"type": "package",
"package": {
"name": "smarty/smarty",
"version": "3.1.7",
"dist": {
"url": "https://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.*"
}
}
Normalmente, você não incluiria a parte source
, pois realmente não precisa
dela.
Nota: Esse tipo de repositório possui algumas limitações e deve ser evitado sempre que possível:
- O Composer não atualizará o pacote, a menos que você altere o campo
version
.- O Composer não atualizará as referências dos commits, portanto, se você usar
master
como referência, terá que excluir o pacote para forçar uma atualização e precisará lidar com um arquivo lock instável.
A chave package
em um repositório package
pode ser definida como um array
para definir várias versões de um pacote:
{
"repositories": [
{
"type": "package",
"package": [
{
"name": "foo/bar",
"version": "1.0.0",
...
},
{
"name": "foo/bar",
"version": "2.0.0",
...
}
]
}
]
}
Embora você provavelmente deseje colocar seus pacotes no Packagist na maioria das vezes, existem alguns casos de uso para hospedar seu próprio repositório.
-
Pacotes de empresas privadas: Se você faz parte de uma empresa que usa o Composer para seus pacotes internamente, convém manter esses pacotes privados.
-
Ecossistema separado: Se você tem um projeto que possui seu próprio ecossistema e os pacotes não são realmente reutilizáveis pela imensa comunidade PHP, convém mantê-los separados do Packagist. Um exemplo disso seriam os plugins do WordPress.
Para hospedar seus próprios pacotes, é recomendado o tipo de repositório nativo
composer
, que oferece o melhor desempenho.
Existem algumas ferramentas que podem te ajudar a criar um repositório
composer
.
Packagist Privado é uma aplicação hospedada ou com hospedagem própria que fornece hospedagem de pacotes privados, além do espelhamento do GitHub, Packagist.org e outros repositórios de pacotes.
Visite Packagist.com para obter mais informações.
Satis é um gerador de repositórios composer
estáticos. Parece um pouco com uma
versão ultra leve e estática do Packagist, baseada em arquivos.
Você fornece a ele um composer.json
contendo repositórios, geralmente VCS, e
definições de repositórios de pacotes. Ele buscará todos os pacotes que estão em
require
e fará o dump de um packages.json
, que é o seu repositório
composer
.
Verifique o repositório do Satis no GitHub e o artigo sobre o Satis para obter mais informações.
Existem alguns casos em que não é possível ter online nenhum dos tipos de
repositório mencionados anteriormente, nem mesmo o VCS. Um exemplo típico pode
ser a troca de bibliotecas entre organizações através de artefatos construídos.
Claro, na maioria das vezes eles são privados. Para simplificar a manutenção,
pode-se simplesmente usar um repositório do tipo artifact
com um diretório
contendo arquivos zip desses pacotes privados:
{
"repositories": [
{
"type": "artifact",
"url": "caminho/para/o/diretorio/com/zips/"
}
],
"require": {
"vendor-privado-um/core": "15.6.2",
"vendor-privado-dois/connectivity": "*",
"acme-corp/parser": "10.3.5"
}
}
Cada artefato zip é um arquivo zip com um composer.json
no diretório raiz:
unzip -l acme-corp-parser-10.3.5.zip
composer.json
...
Se houver dois arquivos com versões diferentes de um pacote, eles serão
importados. Quando um arquivo com uma versão mais recente for adicionado no
diretório de artefatos e você executar update
, essa versão também será
importada e o Composer atualizará para a versão mais recente.
Além do repositório artifact
, é possível usar o repositório path
, que
permite depender de um diretório local, absoluto ou relativo. Isso pode ser
especialmente útil ao lidar com repositórios monolíticos.
Por exemplo, se você possui a seguinte estrutura de diretórios no seu repositório:
apps
└── minha-aplicacao
└── composer.json
pacotes
└── meu-pacote
└── composer.json
Então, para adicionar o pacote meu/pacote
como uma dependência, no arquivo
apps/minha-aplicacao/composer.json
, você pode usar a seguinte configuração:
{
"repositories": [
{
"type": "path",
"url": "../../pacotes/meu-pacote"
}
],
"require": {
"meu/pacote": "*"
}
}
Se o pacote for um repositório VCS local, a versão poderá ser inferida a partir
do branch ou tag do qual foi feito o checkout. Caso contrário, a versão deverá
ser explicitamente definida no arquivo composer.json
do pacote. Se a versão
não puder ser resolvida por esses meios, presume-se que seja dev-master
.
Se possível, será criado um link simbólico do pacote local; nesse caso a saída
no console exibirá Symlinking from ../../pacotes/meu-pacote
. Se a criação do
link simbólico não for possível, o pacote será copiado. Nesse caso, o console
exibirá Mirrored from ../../pacotes/meu-pacote
.
Em vez da estratégia de fallback padrão, você pode forçar o uso do link
simbólico com a opção "symlink": true
ou o espelhamento com a opção
"symlink": false
. Forçar o espelhamento pode ser útil ao implantar ou gerar
pacotes a partir de um repositório monolítico.
Nota: No Windows, os links simbólicos de diretório são implementados usando junções NTFS porque elas podem ser criadas por usuários não administradores. O espelhamento sempre será usado nas versões abaixo do Windows 7 ou se
proc_open
estiver desabilitado.
{
"repositories": [
{
"type": "path",
"url": "../../pacotes/meu-pacote",
"options": {
"symlink": false
}
}
]
}
O til no início dos caminhos é expandido para a pasta inicial do usuário atual
e as variáveis de ambiente são processadas usando as notações do Windows e
Linux/Mac. Por exemplo, ~/git/meu-pacote
automaticamente carregará o clone de
meu-pacote
de /home/<usuario>/git/meu-pacote
, equivalente a
$HOME/git/meu-pacote
ou %USERPROFILE%/git/meu-pacote
.
Nota: Caminhos de repositórios também podem conter curingas como
*
e?
. Para mais detalhes, consulte a função glob do PHP.
Você pode desabilitar o repositório padrão Packagist.org adicionando isto ao seu
composer.json
:
{
"repositories": [
{
"packagist.org": false
}
]
}
Você pode desabilitar o Packagist.org globalmente usando a flag de configuração global:
composer config -g repo.packagist false