196

I've got a couple of libraries [Foo and Bar] that I'm developing in concert, but are still technically separate things. Previously I've just re-defined the autoloader to like "Foo\\": "../Foo/src", but now that I've added a Guzzle dependency to Foo, Bar flips it's lid because it's not one of its dependencies.

Directory structure:

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

Theoretical Autoload Statement: [in Bar/composer.json]

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

Example code:

require('vendor/autoload.php'); $f = new \Bar\BarClient(new \Foo\FooClient()); 

How can I resolve this without setting up a local Composer repo? I want to maintain these as separate packages, just that one requires the other, and therefor processes the other's dependencies.

post-answer edit:

Thanks to infomaniac I've done the following:

Initialized the git repo:

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

Added the composer config:

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

And then composer update!

6
  • How does this json specify the identity between the reference to "sammitch/foo" and the address of "/home/sammitch/src/Foo" ? Is it following any convention? Commented Mar 3, 2016 at 22:33
  • @SebastiánGrignoli sammitch/foo is the package name and has literally nothing to do with where it is located. Will construct a list of available packages based on its configured repos, in this case fetching the composer.json from the specified local git repo, and then composer handles the rest. The sammitch/foo package is copied to the current app's vendor folder the same as any other package. Commented Mar 3, 2016 at 23:51
  • Oh, I think I get it now. It's just a custom repo, like in APT, that might happen to contain the "sammit/foo" package. Did I get it right? Commented Mar 4, 2016 at 1:08
  • @SebastiánGrignoli you betcha Commented Mar 4, 2016 at 18:22
  • thanks for saying "flips it's lid"...made me laugh :D Commented Oct 25, 2022 at 12:37

4 Answers 4

317

The way to link to a local, in-development package is to first add in your main project's composer.json a repository, like this:

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

You also need to either have a version specified in your development package's composer.json or the way I do it is to require the package using @dev, like this:

composer require "vendorname/packagename @dev" 

It should output:

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

The @dev in the require command is important, composer uses this to pickup the source code and symlink it to your new package.

It's a stability flag added to the version constraint (see package link).

These allow you to further restrict or expand the stability of a package beyond the scope of the minimum-stability setting.

The minimum-stability flags are:

Available options (in order of stability) are dev, alpha, beta, RC, and stable.

Sign up to request clarification or add additional context in comments.

12 Comments

Note, that you are not allowed by composer to specify a path that is in the same directory the composer.json is placed.
Interesting point, MaPePeR I did not know this. However, I guess all the web frameworks already take care of this by putting all the dependencies into a "vendor" folder? Yii2 does this, at least.
composer require "vendorname/packagename @dev" translates to "require":{ "vendorname/packagename": "@dev" } in your app's composer.json if you want to run composer install
Please, add this: composer config repositories.local path /full/or/relative/path/to/development/package as correct way of adding repositories
Is it possible to tell composer to install it to the vendors folder for prod instead of creating a symlink?
|
118

You can use Composer's repositories feature

https://getcomposer.org/doc/05-repositories.md#path

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

Instead of using the http format, specify a file path on disk.

6 Comments

getcomposer.org/doc/05-repositories.md#path is also potentially useful and seemed to work better for me.
@JasmineHegman indeed! I've used that too - great for development
To make this a good answer, you should show HOW to do it, and not just name the feature and link the docs (although that is also important). Other answers below have proper examples.
For me, as of 2022, @dev worked rather than * for the package version.
|
15

After spending some time, I finally understood the solution. Maybe it'll be useful for someone like me and will save you some time, so I've decided that I have to share it here.

Assuming that you have the following directory structure (relative to your project root directory):

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 

In this example you may see that the local folder is meant for nested projects of your company, e.g. bar-project. But you could configure any other layout, if you wish.

Each project has to have its own composer.json file, e.g. root composer.json and local/bar-project/composer.json. Then their contents would be as follows:

(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/" } } } 

If, for example, you wish to locate each project in a separate sibling directory, as follows:

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 

- then you need to link to respective directory in repositories section:

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

After that don't forget to composer update (or even rm -rf vendor && composer update -v as the docs suggest)! Under the hood, composer will create a vendor/your-company/bar-project symlink that targets to local/bar-project (or ../bar-project respectively).

Assuming that your public/index.php is just a front controller, e.g.:

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

Then your config/composition-root.php would be:

<?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(); 

2 Comments

"rm -rf vendor/company/package" is important
@Alex83690 only if you have already run composer update with similar composer.json and therefore you need to remove the previous symlink created by composer
4

The command line way to do this is

composer config repositories.package_name local path/to/package composer require group/package_name 

If the group/package_name is available both from repository and local, the local version is used.

The local command can be replaced with vcs to reference a direct repository, or composer for default.

1 Comment

So you can not have project that use repository for a package while other are using local, nope ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.