The definitive introduction to D8 and Composer

Note: This blog post was written in 2015 to cover Drupal 8.0, and is no longer up to date. Composer Manager is deprecated and should not be used. Here’s an updated version.

We’re making a new site based on Drupal 8. This site needs to display addresses, and some quick research leads us to the Address module.
However, after downloading and trying to enable Address, we get the following message: Address requires the commerceguys/addressing library.

In the old days a requirement like this would be satisfied by manually downloading and extracting the library into sites/all/libraries/addressing. Nowadays that’s no longer possible, PHP libraries must be installed using Composer.

What’s Composer?

Composer is a tool for managing dependencies on the project level, a project being your site or web application.

Let’s say our (non-Drupal) site needs the commerceguys/intl and commerceguys/addressing libraries (“packages” in Composer-speak). We would create a composer.json file, and list the dependencies there:

{
    "require": {
        "commerceguys/intl": "dev-master",
        "commerceguys/addressing": "dev-master"
    }
}

Available packages are listed on Packagist, a central repository anyone can add to. Running composer install will download the dependencies:

Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing commerceguys/intl (dev-master d4dca7e)
    Cloning d4dca7e4d8e5d5cee65c0e987e650daa056f3948

  - Installing commerceguys/enum (v1.0)
    Loading from cache

  - Installing doctrine/collections (v1.3.0)
    Loading from cache

  - Installing commerceguys/addressing (dev-master 98e2cae)
    Cloning 98e2caedbd71a838a7b2ececbe7691d480b0f6a5

Writing lock file
Generating autoload file

Notice how Composer has installed two more packages we didn’t ask for.
Those are the dependencies of our dependencies. You can see them listed in the commerceguys/addressing composer.json file.

Once installed, packages can be kept up to date by running composer update.
Composer knows which versions it’s allowed to install/update to by looking at the composer.json file. The dev-master in our examples means that it should always fetch the latest dev release. We could instead use wildcards to allow only releases of a specific branch.

If you’ve ever used Drush Make to download Drupal modules and themes, then all of this sounds familiar. You can think of Composer as the more advanced Drush Make that works for all PHP projects and packages. Compared to Drush Make, Composer has the benefit of being able to recursively resolve dependencies (downloading the dependencies of each dependency) and being able to detect conflicts.
For example, let’s say package A and package B both require Guzzle, the HTTP client. However, package A specifies that it only works with Guzzle5, while package B specifies that it only works with Guzzle6. In this case Composer will abort the install process and warn us.

Composer is clearly an awesome tool, but why do we NEED to use it? Using Drush Make was always optional for site builders. The secret lies in the last line of Composer output: Generating autoload files.
Modern applications such as Drupal 8 consist of many classes, so it would be impractical and costly to manually include each one. Instead, the application includes one special class, called the autoloader which then automatically includes other classes when they are first needed. When Composer runs, it regenerates the autoloader, giving it the locations of the newly downloaded dependencies.

Inside the folder where we ran composer install there’s now a vendor directory containing both our dependencies and the autoloader.
composer-listing

We can commit this folder to git, or even better, run Composer on every deploy, to ensure our dependencies are fresh. People on shared hosting will need to run Composer locally and commit/upload the result, while others will find running Composer on the server more convenient.

Drupal and Composer

Now that we know how Composer works, let’s use it to download the dependencies for Address. Inside the Address module folder there’s a composer.json file listing the required packages.
Can we run composer install inside and call it a day? No.
We would end up with multiple, possibly conflicting vendor directories on the same site, one for core and one for each module that has Composer dependencies. There can be only one. Instead, we need to run Composer at the root of the Drupal install. There’s already a composer.json file there, ready to be edited.

Here’s how that composer.json file looks like by default, trimmed for sanity:

{
  "name": "drupal/drupal",
  "type": "project",
  "require": {
    "composer/installers": "^1.0.21",
    "wikimedia/composer-merge-plugin": "^1.3.0"
  },
  "replace": {
    "drupal/core": "~8.0"
  },
  "minimum-stability": "dev",
  "prefer-stable": true,
  "extra": {
    "merge-plugin": {
      "include": [
        "core/composer.json"
      ],
      "recurse": false,
      "replace": false,
      "merge-extra": false
    }
  }
}

The first requirement (composer/installers) ensures Composer knows where to put the downloaded drupal modules and themes, so that they don’t end up in the vendor directory.
The second requirement (wikimedia/composer-merge-plugin) allows other composer.json files (listed under extra/merge-plugin/include) to be merged when Composer runs. By default it’s used to merge the core requirements from core/composer.json, but can be used to merge module requirements as well.

This gives us two options for getting the Address requirements:

Composer Manager

Composer Manager discovers each module’s composer.json file and adds it to the above mentioned merge list.

cd mysiteroot
drush dl composer_manager
php modules/composer_manager/scripts/init.php
composer drupal-update

And we’re done. The vendor directory now contains our module’s dependencies.
Once we decide to install another module with Composer dependencies, for example Drupal Commerce, we just need to download that module, then run composer drupal-update again.

For more details, check out the Composer Manager documentation.

Sugar-free Composer

The second option is to treat the root composer.json file as a real Drush Make alternative, and add entire modules as requirements.

  "require": {
    "composer/installers": "^1.0.21",
    "wikimedia/composer-merge-plugin": "^1.3.0",
    "drupal/address": "8.1.*@dev"
  },

Thanks to Composer’s recursive dependency resolving, the libraries required by the module will be automatically downloaded as well.

The next thing we need to do is add the Drupal Packagist repository to the file:

    "repositories": [
        {
            "type": "composer",
            "url": "https://packagist.drupal-composer.org"
        }
    ],

This will allow Composer to find the listed Drupal modules.
This is a temporary measure, once Drupal Packagist gets moved to drupal.org, the root composer.json will come with the repository included by default.

We can now run composer update. This downloads the address module to modules/.

The next time we need to add a module or theme, we can take a shortcut:

composer require drupal/address 8.1.*@dev

This will add the line to the ‘require’ section of composer.json, then download just that specific requirement and its dependencies.

The sugar-free method brings a lot more convenience, since core, modules, themes can now be managed using the same powerful mechanism.

For more details, check out the documentation.

Sugar-free, tarball-free Composer

If Composer downloads everything for us, then there’s no need to actually start from a Drupal tarball. We can use the composer create-project command instead which will give us the structure we need:

composer create-project drupal-composer/drupal-project:8.x-dev myproject --stability dev --no-interaction

This creates a myproject directory with a slightly different project layout:
composer-project
There’s once again a composer.json file and a matching vendor directory, but the actual Drupal install has been moved a level deeper, into the web directory.

The project comes with Drush and Drupal Console. They can always be removed by editing composer.json and running composer update.

Conclusion

Composer is here to stay, and it’s time we got familiar with it.
Due to its power, more and more modules are choosing to separate pieces of their logic into separate packages that can be used by the wider PHP community. They’re also choosing to depend on other people’s libraries in order to reduce their own workload.
There is also no doubt that Composer will replace Drush Make, and make itself the preferred way of assembling sites. Advanced Drupal hosting services like Platform.sh (wink wink) already support it.

In the meantime people who already started making sites without Composer can rely on Composer Manager to get required dependencies without altering their existing workflows.

Advertisements

10 thoughts on “The definitive introduction to D8 and Composer

  1. Classic documentation mistake of recommending to manually creating a composer.json. Problem is, if you have an existing one and want to install only the thing you added without updating anything else — you simply can’t. This is one of my biggest gripes with anything composer: everyone recommends a route that only works in a tutorial. What you wanted is “composer require packagename” instead. Please fix the article and let’s work on not spreading this madness.

    • The initial example shows a composer.json created from scratch to house only the two mentioned dependencies. In that case the two approaches are equivalent.

      I have added a paragraph to the “Sugar-free Composer” section explaining composer require.

      On the other hand, I don’t actually believe “updating everything” is a bad thing, assuming the version constraints are tight enough.

      • So why does putting the new entry into the composer.json file and then run composer update vendor/package-name, doesn’t it do what you want?

        Using composer init is also always pretty handy

  2. Interested in your thoughts on what you think the ubiquity of composer_manager will be for Drupal 8. I have the feeling that it will be like ctools in Drupal 7 – on practically every site. In which case it makes good sense for module developers to use composer.json files and the workflow detailed in https://www.drupal.org/node/2405811#modules. Would you agree?

    • There is no doubt that many of the top 50 contribs will require Composer to be installed. That said, I see Composer Manager as a necessary evil, and hope it will become less and less needed as core simplifies the “sugar-free” workflow. Ideally all you’d need to do is run “composer require drupal/commerce 8.1.*” to install Commerce, for example.

  3. I’m probably missing something very basic, but I’ve tried both the Sugar-free method and Composer Manager module on my just installed Drupal 8 repository (8.0.x branch), and with both of them I get “Could not open input file: composer.phar” – because there is no composer.phar file by default. Where do I get it or what am I doing wrong?

  4. Has anyone made this work on Windows using Acquia Dev Desktop? I installed Composer Manager and then tried to run:

    php modules\contrib\composer_manager\scripts\init.php

    That was on Friday, and I finally control-c’d out of the process when I returned to work on Tuesday morning. Anybody else seen such behavior? Or am I the only one foolish enough to be trying this? (Unfortunately, working in government, I don’t have much choice what platform I develop on.)

Comments are closed.