The purpose of this post is to introduce a better package and dependency management system for Magento extensions.
It was a few months ago that I first heard of composer. I was surprised I had not stumbled over it earlier – it seems the PHP world is moving forward quickly, but I’m so focused on Magento that I miss some things. What a nice surprise to discover this tool!
Background
Here is a short overview, in case your case is similar to mine, and you aren’t yet familiar with composer.
Composer is a package and dependency manager for PHP libraries. But that’s nothing new; don’t we have PEAR you say? Good point.
Well, PEAR was build using the assumption, that PHP library components would be installed system-wide. As it turns out, this isn’t the best solution. In practice, different projects require different versions of the same libraries. If you upgrade system wide libraries, all dependent projects have to be upgraded, too.
So, composer fixes this issue. It installs required libraries separately for each project.
Also, it makes it very easy to manage package repositories, much easier then managing PEAR channels. Even more, it can install packages from many different sources: GIT and SVN repositories, ZIP and TAR files, and yes, even PEAR channels. The person installing the package doesn’t even need to care where the package comes from.
So where do you get available libraries?
All publicly available packages for composer are listed on packagist.org. But because plugins for applications, which have their own eco-system, should not be listed there, we created a public repository for Magento modules: packages.firegento.com.
How does it work?
Composer uses a configuration file, which lives in a project base directory. The file is named composer.json. This file lists configuration options, for example the minimum-stability, and also the list of packages that should be installed. Also a version, or a version range, can be specified for each package.
Here is an example composer.json:
{
"minimum-stability":"dev",
"require":{
"phpunit/phpunit":"3.7.9",
"n98/magerun":"*",
"twig/twig":"1.11.2.*",
"fbrnc/aoe_templatehints":"dev-master"
}
}
Composer will use packagist.org to look where to get the libraries. Because Magento modules aren’t listed there, you will have to add the packages.firegento.org repository to the configuration as follows, and also specify the Magento root directory (more on that below):
{
"minimum-stability":"dev",
"require":{
"phpunit/phpunit":"3.7.9",
"n98/magerun":"*",
"twig/twig":"1.11.2.*",
"fbrnc/aoe_templatehints":"dev-master"
},
"repositories":[
{
"type":"composer",
"url":"http://packages.firegento.com"
}
],
"extra":{
"magento-root-dir":"./"
}
}
Once the composer.json configuration file is created, all that needs to be done is install composer (curl –O http://getcomposer.org/composer.phar) and run it:
php composer.phar install
And that’s all. The listed packages and all their dependencies will be installed in the project.
The place where composer installs the libraries is a directory called vendor.
Should the contents of the composer.json file ever be changed, run
php composer.phar update
and the new configuration will be applied.
That is also how you uninstall a package: you remove it from the require list in the composer.json and run composer.phar update.
Back to Magento
As you probably are aware, Magento modules, in contrast to “usual” PHP libraries, aren’t contained in a single directory within the project. Instead module classes live in the code pool subdirectories, translation files under app/locale, and templates in the respective area, package and theme folders, and so on. For this reason, the files which composer installed under vendor, somehow need to be merged into the Magento directory hierarchy.
And this is what the magento-composer-installer project provides.
After installing a Magento module with composer, all files and directories will be symlinked into the respective targets in the Magento directory tree, very similar how modman does.
There is one little piece of information that is required so composer can do that, and that is the path to the Magento root directory. You will always need to add that to the project composer.json file, too:
{
...
"extra":{
"magento-root-dir":"./htdocs"
}
}
In case you prefer copies to symlinks, no problem: simply set the appropriate config option under extra.magento-deploystrategy:
{
...
"extra":{
"magento-root-dir":"./htdocs",
"magento-deploystrategy":"copy"
}
}
Maybe that is interesting for users on “old” windows systems that don’t yet support symlinks.
Directory layout
Before we wrap up, there is one more thing that should be talked about. As mentioned before, composer installs libraries (and Magneto modules) into a vendor directory.
So this directory needs to be integrated somehow into the project.
When placed directly in a Magento root directory we would end up with a structure like this:
htdocs/ ├── .git/ ├── composer.json ├── composer.lock ├── index.php ├── app/ ├── js/ ├── lib/ ├── media/ ├── skin/ ├── var/ └── vendor/
This works, but you need to make sure that the vendor directory, and also the compser.json and composer.lock files aren’t accessable from a web browser.
For that reason it’s better to make the parent of the Magento directory to the project root folder:
the-project-dir/ ├── .git/ ├── composer.json ├── composer.lock ├── htdocs/ │ ├── index.php │ ├── app/ │ ├── includes/ │ ├── js/ │ ├── lib/ │ ├── media/ │ ├── shell/ │ ├── skin/ │ └── var/ └── vendor/
Each solution partner and each developer have their own preferences, but I think most agree that the second variation is cleaner.
Versioning the project
Preamble: I realize not everybody uses git, but for the sake of simplicity I’ll just refer to git here. Think svn, mercurial or whatever the vcs of your choice is instead if you prefer.
The composer.json file is always included in the git repository. For the vendor directory, it depends – it isn’t always versioned.
When composer.phar install is run, a file composer.lock is created which lists all the packages in the currently installed version. But should this file already exist when the install command is called, then composer will re-create that state in listed in that file. For that reason, it theoretically is enough to version the composer.lock file, and add the vendor folder to the .gitignore list. That is assuming that every package will always remain installable in the future.
To avoid that risk, you might prefer to version the vendor directory after all. You choose.
UPDATE: If you end up versioning the vendor directory, you might want to install packages without the .git subdirectories. Composer offers command line switches to control that behaviour: –prefer-dist and –prefer-source (see the reference).
An composer install –prefer-dist will install the packages without the .git subdirectories, whereas –prefer-source will clone the source repositories, which is useful if you want to do work in the packages, too. Then you can commit straight from the vendor/<package-name> directory.
Wrapping up
If you are interested in making your own Magento modules installable with composer, please refer to the next blog post – coming shortly right here.
As mentioned before, modules can come from many different sources. All the modules on packages.firegento.com are hosted on github, or are Magento Connect 2.0 packages, which also can be installed. The latter can be recognized by the connect20/ prefix to the package name.
It also goes beyond the scope of this introductory post to describe all the possibilities the project composer.json offers, for example how to configure private repositories. A little further information can be found in the magento-composer-installer README, and of course in the excellent composer documentation on http://getcomposer.org/doc/.
The one drawback of composer for Magento (so far) is that it doesn’t handle commercial extensions very gracefully. It would be possible to add a private repository and install from there, but that’s not a real solution. But at least the community modules and other external libraries are taken care of nicely!
Finally, I’ve made a quick introductory screencast:
Hope you enjoy composer with Magento!
Originally published on magebase.com. Copyright © 2013 Magebase - All Rights Reserved.




Proud members of the
Vinai,
This is awesome – easy to read and follow
Thanks for sharing it
Regards,
Luis
Nice article Vinai!
As composer seems to become the new de-facto standard for package-management within the PHP world, I couldn’t wait for this to reach the Magento-hemisphere
Cheers,
Alex
Great post, thank you! Looking forward to try that in practice (on Windows… which does support symlinks, but not the way Linux/MacOS does
)
Yes, I can confirm that symlink() works on windows. But I think the windows users wanted the “copy” deploy mode
Anyway, either should work on wither plattform!
Hi Vinai,
thanks to you I finally tried composer!
A few things I had to change to make it work on my Debian test system:
* replace “curl –O http://getcomposer.org/composer.phar” with “curl -s https://getcomposer.org/installer | php”
* composer.json: replace line
“twig/twig”:”v1.11.2″
with
“twig/twig”:”v1.12.1″,
(v1.11.2 doesn’t exist, trailing comma missing)
* composer.json: replace line
“fbrnc/aoe_templatehints”:”dev-master”,
with
“fbrnc/aoe_templatehints”:”dev-master”
(remove trailing comma)
Hi Matthias,
thanks for the comment – I updated the post!
One more note:
“n98/magerun”:”*”
will install a pretty old version of n98-magerun (1.28.0).
Replace this with
“n98/magerun”:”dev-master”
and you get the current version from GitHub (1.51.1 as of now).
Hi Matthias,
the installed version depends on your minimum-stability setting. Specifying “minimum-stability”:”dev” and a version “*” will install the dev-master HEAD.
That is not so easy to use when you try to make a real package manager like packagist.org
Sure, satis is really simple and easy to start but after half year usage I’ve faced with lot of problems, like: how to update information by commit?
So, now I’m using https://github.com/composer/packagist
But for the quick start – Satis is what you need. And thanx author for the great job.
Composer should be a standard for php libs/extensions/modules/applications.
Hi Volodymyr,
I agree that packagist is a far superior solution, and we will move to it some time. But to get started quickly satis is great.
We solve the problem of current commits by rebuilding the packages.json twice a day in addition to a commit hook when the satis.json get’s updated.
Vinai, sorry, I don’t know how much you’re worked with PEAR, but the assumption the PEAR was build with assumption, that PHP library components would be installed system-wide isn’t quite right, at least according my experience. The PEAR is pretty flexible and configurable, even the version that was included with previous versions of magento was smart enought to not interfere with system wide extensions.
Composer has quite different purpose: “Composer solves the PHP code-sharing problem”, worth reading: http://bergie.iki.fi/blog/composer_solves_the_php_code-sharing_problem/
In other words “magento-deploystrategy”:”copy” is anti-composer concept which demonstrating the root problem of magento
IMHO, it’s time to refactor magento stack to support self containing extensions for easiest distribution and sharing.
Hi Yevgeniy,
thanks for your comment. I must admit that I took a short cut in regards to PEAR. Refactoring Magento 1 won’t happen, but for Magento 2 self-contained modules are already standard.
Thanks also for the link to the great post.
Could not parse version constraint v1.11.2.*: Invalid version string “v1.11.2.*”
Thx for the notice!
Thanks Vinai! This is amazing, I love it. Love that it has an uninstall as well. #thisisgonnachangeverything