Working at the same time in a project and its dependencies: Composer and path type repository

With the Domain-Driven Design, Microservices and API explosion, I see more teams working in a base project, such as a Web, and integrating other private packages they develop in a different repository. For example, working on the Web and an API client for a external REST service at the same time.

For example, at @AtrapaloEng, our sales development team (checkout process, purchases, orders, payments, etc.) integrates different payment methods into the web so users, specially Latam ones, can be happier using their preferred payment methods. They create a repository for each of the new payment methods we support as a external package. Sometimes a developer in the team must work with different projects at the same time, the Web and the payment method in development.

In this scenario, one option is work on the payment package, tag, push, go to the base project and update dependencies with Composer. As you can see, it’s a bit slower, how we can improve this process? Composer to the rescue!

At RESTGames, there is a battleship referee that makes two REST services play one against the other. It’s written in PHP and uses a helper PHP library with basic elements of Battleship game (Board, Ships, Shot, etc.) so you can create your own engine. Referee project depends upon the PHP library. When I improve the referee, sometimes I need to update the library. Sometimes it will be cool just to update the library in the “vendor” folder and commit the changes to the library from there.

Well, with Composer there is something similar for that. If you have both a project and its dependency cloned in your machine, you can define a Composer repository in your composer.json of “path” type that points to the library path. It’ll use a copy-and-paste o softlink (the cool one) strategy to “import” the dependency into the project.

From Composer’s web: “In addition to the artifact repository, you can use the path one, which allows you to depend on a relative directory. This can be especially useful when dealing with monolith repositories.”

Let’s take a look to the composer.json.

{
    "name": "restgames/battleship-client",
    ...
    "repositories": [
        {
            "type": "path",
            "url": "../battleship-php",
            "options": {
                "symlink": true
            }
        }
    ],
    "require": {
        "restgames/battleship-php": "dev-master",
    },
...

When running “composer install”, Composer will take a look to the folder. If the library exists, it will softlink it in your vendor folder. If it does not exist, it will try to find it in Packagist. Let’s see some snapshots.

Library cloned in local

Screen Shot 2016-03-24 at 16.18.36

Composer symlinked from local folder

Screen Shot 2016-03-24 at 16.21.04

Library is renamed so Composer is not going to find it

 Screen Shot 2016-03-24 at 16.21.40

Composer downloads from Packagist ;)

Screen Shot 2016-03-24 at 16.22.03

The only issue, is that all developers working in the project and the library needs to have cloned the library in the same folder name, not a big deal for such a benefit.

You can find more info at Composer documentation about Repositories (https://getcomposer.org/doc/05-repositories.md#path)

Bonus Point (requested via twitter)

You can define as many repositories as you want. Componer will try to find the package respecting the order defined in the composer.json file. For example, given the following composer.json:

...
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/restgames/battleship-php"
        },
        {
            "type": "path",
            "url": "../battleship-php",
            "options": {
                "symlink": true
            }
        }
    ],
...

Composer will try to find first on github without packagist, then in local, then in Packagist.

  • Very nice summary, thank you!

  • david

    Hello everyone,

    I would like to use path repositories in local (for development) and vcs for production. If I use the last “bonus” puntualization using both repositories (first local and last vcs) the issue I am having is that in production the path doesn’t exist, then the information into composer.lock is no valid for both enviroments. Using always vcs at first place breaks it, because I should commit every change in a testing/development environment.

    I might not understand something.

    Thank you.