Using Composer Manager to get off the Island Now

  • 7 minute read

On the eve of 2013, prolific Drupal contributor Larry Garfield put forth a challenge to "get off the island", and judging by the adoption of non-Drupal projects in Drupal 8 core I would say the community has responded. By using the Composer tool it is easier than ever to build on top of the tens-of-thousands of platform-agnostic projects in the PHP community, and it is exciting to see Drupal contribute to and benefit from broader initiatives. However the current Drupal landscape, including Drupal 8, makes it difficult for module developers to benefit from third-party code in the same way that Drupal 8 core does. This article highlights how the Composer Manager module can help developers reach beyond Drupal's borders regardless of the Drupal core version being used.

To quickly review Composer, it is a sophisticated dependency manager for PHP that makes it easy to build on the shoulders of giants. It works by reading the project's requirements from a composer.json file, downloading the required code to a "vendor" directory, and generating a PHP file that registers an autoloader when sourced at runtime so that classes are available on demand. The challenge of using Composer with Drupal modules is that it assumes a single composer.json file and library space, so if multiple modules use Composer to maintain their requirements it can lead to duplication of library code and unexpected version mismatches based on the order that each module's autoloaders are registered.

The Composer Manager module aims to solve the challenges with Drupal and Composer by working around the issues in a near-frictionless way for Drupal developers while also staying true to Composer's concepts and workflows. Composer Manager accomplishes this goal by scanning modules for composer.json files as they are enabled and generating a single composer.json file that contains the consolidated requirements for all modules. You can either manually use the Composer tool to pull in your application's third-party dependencies, or you can have everything done for you automatically by using Drush to enable and disable modules. Composer Manager also registers the autoloader that is created by Composer so that modules have access to the classes they depend on.

Lets try it out!

Our goal is to use the Acquia SDK for PHP's Cloud API component inside of a Drupal module so that we can list our sites hosted on Acquia Cloud. The first thing we are going to do is download and install Composer Manager using the standard Drupal process. We then need to visit Composer Manager's configuration page to modify the options according to our environment. Refer to the Best Practices section of the documentation for more details on the values that are appropriate for your installation.

Next, create a custom module that has a composer.json file in its root directory with the following content:

{
     "require": {
         "acquia/acquia-sdk-php-cloud-api": ">=0.9.0,<0.10.0"
     }
}

Finally, enable your custom module via Drush by running `drush en mymodule` replacing "mymodule" with whatever name you chose. You will likely encounter three prompts that must be agreed to: Whether you really want to enable the module, whether you accept updating packages managed by Composer, and whether you agree to download the Drush Composer extension. Accepting the prompts will enable your custom module, gather your custom module's requirements, generate the consolidated composer.json file, download Drush's Composer extension, and run the Composer commands that install the dependencies.

Output of enabling custom module via Drush

If all went well the required packages will be downloaded to the vendor directory as configured in the settings page, and visiting Composer Manager's packages page will provide some more details on the dependencies that are installed (admin/config/system/composer-manager for D7 & D8, admin/settings/composer-manager for D6).

Composer Manger packages page

You can now use the Acquia Cloud API client library in your custom module. The following snippet is written for Drupal 7 and assumes a module named "mymodule":

<?php
use Acquia\Cloud\Api\CloudApiClient;

/**
 * Implements hook_menu().
 */
function mymodule_menu() {
  $items = array();

  $items['acquia-cloud/sites'] = array(
    'title' => 'Acquia Cloud Sites',
    'page callback' => 'mymodule_acquia_cloud_sites',
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/**
 * Page callback; Shows a list of Acquia Cloud sites.
 *
 * @return array
 *   A render array for a page containing a list of Acquia Cloud sites.
 */
function mymodule_acquia_cloud_sites() {

  $cloudapi = CloudApiClient::factory(array(
      'username' => 'your-email-address',
      'password' => 'acquia-network-password',
  ));

  // @todo In the real world, implement caching and error handling
  $sites = $cloudapi->sites();

  $items = array();
  foreach ($sites as $site) {
    $items[] = check_plain($site->name());
  }

  return array(
    'sites' => array(
      '#theme' => 'item_list',
      '#items' => $items,
    ),
  );
}
?>

blog-composer-manager-example.png

That's it!

By creating a simple json file and using standard Drush workflows we were able to integrate third-party libraries into our Drupal module. There is no code duplication even if other modules have overlapping requirements, and we avoided having to write a custom autoloader to use the required classes.

I'll be the first to admit that Composer Manager isn't perfect. The specifics of why Composer Manager works the way it does are discussed in the Why can't you just … section of the documentation, and the challenges that remain are highlighted there as well. Regardless, we have found it to be a reliable solution when following the documented best practices, and the amount of time saved by the ability to leverage best-in-breed tools far outweighs the challenges. In a perfect world Drupal core either adopts a Composer-centric architecture or integrates solutions such as Embedded Composer into core in a way that works seamlessly with contributed modules. Until then, Composer Manager is your boat to get off the island and bring new friends back.

More on Composer

Check out this excellent article by Lorna Mitchell Composer – Dependency Management in PHP for more information on installing and using Composer.