Composer requer pacote local

105

Eu tenho algumas bibliotecas [Foo e Bar] que estou desenvolvendo em conjunto, mas ainda são coisas tecnicamente separadas. Anteriormente, acabei de redefinir o autoloader para like "Foo\\": "../Foo/src", mas agora que adicionei uma dependência Guzzle a Foo, Bar vira a tampa porque não é uma de suas dependências.

Estrutura do diretório:

/home/user/src/
    Foo/
        src/
            FooClient.php
        composer.json
    Bar/
        src/
            BarClient.php
        composer.json

Instrução teórica de carregamento automático: [em Bar / composer.json]

"require": {
    "local": "../Foo/composer.json"
}

Código de exemplo:

require('vendor/autoload.php');

$f = new \Bar\BarClient(new \Foo\FooClient());

Como posso resolver isso sem configurar um repositório local do Composer? Quero mantê-los como pacotes separados, apenas aquele requer o outro e, portanto, processa as dependências do outro.

edição pós-resposta:

Graças ao infomaníaco, fiz o seguinte:

Inicializou o repo git:

cd ~/src/Foo && git init && echo -e "vendor\ncomposer.lock" > .gitignore && git add ./ && git commit -m "Initial Commit"

Adicionada a configuração do composer:

"require": {
    "sammitch/foo": "dev-master"
},
"repositories": [{
    "type": "vcs",
    "url": "/home/sammitch/src/Foo"
}],

E então composer update!

Sammitch
fonte
Como este json especifica a identidade entre a referência a "sammitch / foo" e o endereço de "/ home / sammitch / src / Foo"? Está seguindo alguma convenção?
Sebastián Grignoli
@ SebastiánGrignoli sammitch/fooé o nome do pacote e literalmente não tem nada a ver com onde ele está localizado. Construirá uma lista de pacotes disponíveis com base em seus repositórios configurados, neste caso obtendo o composer.json do repositório git local especificado, e então composer trata do resto. O sammitch/foopacote é copiado para a vendorpasta do aplicativo atual da mesma forma que qualquer outro pacote.
Sammitch
Oh, acho que agora entendi. É apenas um repo personalizado, como no APT, que pode conter o pacote "sammit / foo". Eu entendi certo?
Sebastián Grignoli
@ SebastiánGrignoli, pode
apostar

Respostas:

37

Você pode usar o recurso de repositórios do Composer

https://getcomposer.org/doc/05-repositories.md#loading-a-package-from-a-vcs-repository

Em vez de usar o formato http, especifique um caminho de arquivo no disco.

Danny Kopping
fonte
11
getcomposer.org/doc/05-repositories.md#path também é potencialmente útil e parece funcionar melhor para mim.
Jasmine Hegman
@JasmineHegman, de fato! Eu também usei isso - ótimo para desenvolvimento
Danny Kopping,
Para tornar esta uma boa resposta, você deve mostrar COMO fazê-lo, e não apenas nomear o recurso e vincular os documentos (embora isso também seja importante). Outras respostas abaixo têm exemplos adequados.
Rudolfbyker
171

A maneira de vincular a um pacote local em desenvolvimento é primeiro adicionar composer.jsonum repositório do projeto principal , como este:

"repositories": [
    {
        "type": "path",
        "url": "/full/or/relative/path/to/development/package"
    }
]

Você também precisa ter uma versão especificada em seu pacote de desenvolvimento composer.jsonou a forma como eu faço isso é exigir que o pacote use @dev, assim:

composer require "vendorname/packagename @dev"

Deve produzir:

- Installing vendor/packagename (dev-develop)
Symlinked from /full/or/relative/path/to/development/package

O @devin no comando require é importante, o composer o usa para pegar o código-fonte e fazer um link simbólico para o seu novo pacote.

É um sinalizador de estabilidade adicionado à restrição de versão (consulte o link do pacote ).

Isso permite que você restrinja ou expanda a estabilidade de um pacote além do escopo da configuração de estabilidade mínima .

Os sinalizadores de estabilidade mínima são:

As opções disponíveis (em ordem de estabilidade) são dev, alpha, beta, RC, e stable.

Dhiraj Gupta
fonte
8
Observe que você não tem permissão para o composer especificar um caminho que esteja no mesmo diretório em que composer.json está colocado.
MaPePeR
Interessante, MaPePeR Eu não sabia disso. No entanto, acho que todos os frameworks da web já cuidam disso, colocando todas as dependências em uma pasta "vendor"? Yii2 faz isso, pelo menos.
Dhiraj Gupta de
3
composer require "vendorname/packagename @dev"traduz para "require":{ "vendorname/packagename": "@dev" }no composer.json do seu aplicativo se você deseja executar a instalação do composer
Sir_Faenor
2
Por favor, adicione este: composer config repositories.local path / full / ou / relative / path / to / development / package como forma correta de adicionar repositórios
basil
1
É possível dizer ao composer para instalá-lo na pasta vendors para prod em vez de criar um link simbólico?
BenjaminH
7

Depois de passar algum tempo, finalmente entendi a solução. Talvez seja útil para alguém como eu e economize seu tempo, então decidi que devo compartilhar aqui.

Supondo que você tenha a seguinte estrutura de diretório (em relação ao diretório raiz do projeto):

composer.json
config
config/composition-root.php
local
local/bar-project
local/bar-project/composer.json
local/bar-project/src
local/bar-project/src/Bar.php
public
public/index.php
src
src/Foo.php

Neste exemplo, você pode ver que a localpasta se destina a projetos aninhados de sua empresa, por exemplo bar-project. Mas você pode configurar qualquer outro layout, se desejar.

Cada projeto deve ter seu próprio composer.jsonarquivo, por exemplo, root composer.jsone local/bar-project/composer.json. Então, seu conteúdo seria o seguinte:

(root composer.json:)

{
  "name": "your-company/foo-project",
  "require": {
    "php": "^7",
    "your-company/bar-project": "@dev"
  },
  "autoload": {
    "psr-4": {
      "YourCompany\\FooProject\\": "src/"
    }
  },
  "repositories": [
    {
      "type": "path",
      "url": "local/bar-project"
    }
  ]
}

( local/bar-project/composer.json:)

{
  "name": "your-company/bar-project",
  "autoload": {
    "psr-4": {
      "YourCompany\\BarProject\\": "src/"
    }
  }
}

Se, por exemplo, você deseja localizar cada projeto em um diretório irmão separado, da seguinte maneira:

your-company
your-company/foo-project
your-company/foo-project/composer.json
your-company/foo-project/config
your-company/foo-project/config/composition-root.php
your-company/foo-project/public
your-company/foo-project/public/index.php
your-company/foo-project/src
your-company/foo-project/src/Foo.php
your-company/bar-project
your-company/bar-project/composer.json
your-company/bar-project/src
your-company/bar-project/src/Bar.php

- então você precisa vincular ao respectivo diretório na repositoriesseção:

  "repositories": [
    {
      "type": "path",
      "url": "../bar-project"
    }
  ]

Depois disso não se esqueça de composer update(ou mesmo rm -rf vendor && composer update -vcomo a documentação sugere )! Sob o capô, o compositor criará um vendor/your-company/bar-projectlink simbólico que visa local/bar-project(ou ../bar-projectrespectivamente).

Supondo que seu public/index.phpseja apenas um front controller, por exemplo:

<?php
require_once __DIR__ . '/../config/composition-root.php';

Então você config/composition-root.phpseria:

<?php

declare(strict_types=1);

use YourCompany\BarProject\Bar;
use YourCompany\FooProject\Foo;

require_once __DIR__ . '/../vendor/autoload.php';

$bar = new Bar();
$foo = new Foo($bar);
$foo->greet();
porqueer
fonte
1
"rm -rf vendor / company / package" é importante
Alex83690
@ Alex83690 somente se você já executou composer updatecom similar composer.jsone, portanto, você precisa remover o link simbólico anterior criado pelo composer
whyer