VGTech is a blog where the developers and devops of Norways most visited website share code and tricks of the trade… Read more

Are you brilliant? We're hiring. Read more

# Using local packages as composer dependencies

PHP

Composer changed pretty much everything when it comes to including dependencies in PHP projects. No more SVN externals or copying large library folders into your project. This is really great, but there’s one thing I’ve been struggling to find a smooth process for; developing dependencies for your project.

When implementing your project, the need for some module, library, service provider or something else will arise, and sometimes you’ll have to implement it yourself. So, how to do that?

## Possible solutions

1. Implementing it inside your project, maybe in the library or source folder. Would work, but if you want to publish it [on packagist.org or somewhere else] as a separate package later on, you will make extra work for yourself.
2. Publish the non-working package on packagist and push changes to you VCS. This is a really slow work process, as it requires you to push and do a composer update to see the changes.
3. The other way™

## The other way

I’ve found that setting up a repository with a relative file system reference is the easiest way. This way, you can have your dependency separate from the application and getting changes in the dependency is as simple as running composer update.

## Example

Given the following folder structure;

/
project/
composer.json
package/
composer.json
src/Foobar.php

### package/composer.json

Show code
{
"name": "kbrabrand/package",
"description": "My test package",
"authors": [
{
"name": "Kristoffer Brabrand",
"email": "kristoffer@brabrand.no"
}
],
"psr-0": {
"KBrabrand": "src"
}
}
}


This simply defines a composer compatible package and is pretty straight forward. Now, let’s take a look at the composer.json file for the project, where the “magic” happens.

### project/composer.json

Show code
{
"name": "kbrabrand/project",
"description": "Test project",
"authors": [
{
"name": "Kristoffer Brabrand",
"email": "kristoffer@brabrand.no"
}
],
"minimum-stability": "dev",
"repositories": [
{
"type": "vcs",
"url": "../package"
}
],
"require": {
"kbrabrand/package": "*"
}
}


The repositories part of the composer file is the only thing special. There are several repository types, but the VCS type refers to some sort of version control resource (locally or externally). The repository portion of the composer schema documentation notes that this could be svn, git or mercurial (hg).

For this example I’ve used a relative local path and git. As shown in the composer doumentation, using absolute paths or external URLs is also possible.

### Running composer

Show code
$cd package$ git init
Initialized empty Git repository in /development/package/.git/

$git add *$ git commit -m "Initial commit"


At this point, a local git repo exists in the package folder and is now ready for inclusion in the project with composer.

Show code
$cd ../project$ composer install
Installing dependencies (including require-dev)
- Installing kbrabrand/package (dev-master 4a111b4)
Cloning 4a111b483843e75a3cb0ee794c0b9eaf0b75b395

Writing lock file


That’s it! After this point, whenever a change is made to the package, commit your change and do a composer update. Like this;

Show code
$cd ../project$ git commit -am "Changes"
$cd ../project$ composer update


### Pro tip from the comment field

Gauthier Delamarre pointed out that it’s possible to specify the repository definition from composer.json into the users composer config. This is done by adding repository block to the file ~/.composer/config.json. As Gauthier points out, the benefit from doing it this way is that you won’t need to keep you environment specific paths for the repo in the composer.json, which allows you to commit and push it without thinking about messing everything up for other devs.

More documentation on the “home config”: https://getcomposer.org/doc/03-cli.md#composer-home-config-json

• ### Tomas Votruba116 week 6 days ago

Hey, I just used this tut and it's really simple and easy to setup and use. Thanks for sharing!

• ### Tomas Votruba115 week 2 days ago

For inspiration: I've also found this tl;dr; version: http://marekkalnik.tumblr.com/post/22929686367/composer-installing-package-from-local-git

• ### Darius114 week 5 days ago

Getting error:

[InvalidArgumentException]
No driver found to handle VCS repository /cygdrive/c/duomenys/projektai/no_
git/others/sandbox/HelloWorld

how can I fix it? Or do I have to install some repository? Usually I use bitbucket repositories

• ### Shambhu Kumar108 week 3 days ago

No driver found to handle VCS repository ../package

error is coming

• ### Kristoffer Brabrand108 week 3 days ago

I think you've forgot to run git init inside ../package.

In order for composer to load the dependency, you have to initialize the git repo and make at least one commit on the the branch you've required in your projects composer.json file (master in the examples in this blog post).

• ### Gauthier Delamarre98 week 3 days ago

This tip could a be time saver for anyone working on some early stage project split in multiple packages. Referring to a local clone allows to make a separate library evolve together with the main project without publishing unstable versions to a public repository (shared with other contributors for instance).

To make it even comfortable, may I suggest to move the "repository" section from project/composer.json to HOME/.composer/config.json? :)

Doing this allows to commit and push the composer.json without conflicts with other contributors!

Gauthier

PS: by the way, in your last terminal sample, there is a copy/paste issue on line 3 :) Should be "cd ../project", not "cd ../package"

• ### Kristoffer Brabrand97 week 5 days ago

Thanks for the input. I've added the suggestion to the blog post and fixed the typo.

• ### Sam97 week 4 days ago

Could save someone some time with the latest composer (because I assume what you have here worked well).

In PROJECT/COMPOSER.JSON, your require should look like

"require": {
"kbrabrand/package": "dev-master"
}

Otherwise composer will scream at you about not finding a version.

• ### forever96 week 6 days ago

Thanks, this helps !

If anyone is interested, here is my alias for Cmder to do this :
syncfw=D: $T cd D:\path\to\package$T git add --all . $T git commit -m "dev going on"$T cd ../project \$T composer update

A git init must have been done in the package directory and a composer install in the project directory.

• ### Barry79 week 5 days ago

Since a few days it's possible to just use the path, without creating a new repo :)
https://medium.com/@barryvdh/using-local-repositories-to-easily-install-private-magento-extensions-with-composer-7eb966dec23e

• ### Ozan Müyesseroğlu70 week 3 days ago

Thanks Sam, before "dev-master" I was getting "Your requirements could not be resolved to an installable set of packages." error.

• ### Gauthier Delamarre67 week 3 days ago

@Kristoffer thanks for quoting me in your blog update ;) I'm sorry I didn't came earlier, but I didn't get any notification about new comments since my last visit ;)

• ### Alasdair61 week 3 days ago

You should update this to use 'path' rather than 'vcs' in the project's composer.json, that way a symlink is used and no commiting / updating is required.

• ### rouflak55 week 3 days ago

If you want to have it working without a git repository, provide the path type instead of vcs, and keep the url key in which you provide the path (full or not) to the folder containing the composer.json

• ### TechNikh44 week 3 days ago

But what about other libraries that need not be in local?
Like in https://github.com/opdavies/oliverdavies.uk/blob/master/composer.json I want to work & test locally on just one plugin called sculpin-gist-embed-bundle. All other plugins like behat, mink.. I want to be loaded normally.

• ### Stephan3 week 10 hr ago

This still forces you to run composer update every single time which is a big hassle. Is there really no way to just keep them in sync with eachother? I know some nasty workarounds but common, there must be a proper way for this right?