Skip to main content

Drupal 8 Now: Composer dependencies in Drupal 7

One of the key goals of namespaces in PHP is to avoid collisions between class and function names between different libraries. Using namespaces and the PSR-0/4 standard creates a clean and simple way of sharing code across projects. This is a core part of the Drupal 8 architecture.

This approach has been a large factor in the PHP Renaissance and the huge amount of sharing of code across PHP external libraries.

In this post, I will show how we can leverage external libraries in existing Drupal 7 sites, using similar techniques to how it is being done in Drupal 8.

by Kim Pepper /

In Drupal 7, The standard way to load in 3rd-party libraries is to put them in the sites/all/libraries folder, install the Libraries module, and then implement hook_libraries_info() to tell the Libraries module about your external library.

In Drupal 8, most of the code is in PSR-0/4 namespaced classes. External libraries are also written in PSR-0/4 classes and are brought in using Composer. They are passed into Drupal classes using Dependency Injection and managed with the Symfony2 Service Container. This is a much cleaner and simpler way of using external libraries.

The good news is, you can take much the same approach with your custom Drupal 7 modules calling external libraries, right now.

Setting Up

There are a few moving parts in our example module. Lets have a quick overview of them first.

HTTPBin

For our example module, we want to grab some data from an external web service, such as httpbin.org. This is just a test web service which returns information about the requestion you made. In our case we will just request the IP address of the incoming request we made from a JSON response. Any other web serice will do.

Once we have it, we are just going to display it in a block. Simple!

Guzzle

Guzzle is a http client that is replacing drupal_http_request() in Drupal 8. It's an object-oriented, extensible and fully featured client, with a very simple API. Perfect for interacting with web services!

Composer

Composer is a major breakthrough for the open source PHP community. Along with PSR-0 and Packagist, It has provided a standardised way of sharing code among different projects. You just need to create a composer.json file, declare your dependencies, and then download them with the command line tools.

XAutoload

As mentioned in previous posts, the excellent XAutoload makes it easy to simply call the classes you need, without manually loading them, with a simple API.

Putting it all together

Step 1: Install composer

If you haven't got composer installed yet, the installation instructions are a very simple one-liner:

curl -sS https://getcomposer.org/installer | php -- --version=1.0.0-alpha8 --install-dir=/usr/local/bin --filename=composer

We're using Mac OSX, so we want to put composer into /usr/local/bin so its automatically added to our path. We also specify a specific version, to avoid the "works on my machine" problem.

More detailed installation instructions are available on the Composer site.

Step 2: Create a composer.json file

In order to load in the Guzzle library, we need to specify it as a dependency. Create the following composer.json file in the root directory of our project.

{
  "require": {
    "guzzlehttp/guzzle": "~4.0.2"
  }
}

Step 3: Install the libraries with composer

Assuming you have composer installed, run the following:

composer install

Composer will generate a lock file composer.lock and download dependencies into <project_root>/vendor. If we wanted to put them somewhere else (e.g. sites/all/vendor) we can use the COMPOSER_VENDOR_DIR environment variable.

Step 4: Tell XAutoload where to load our composer autoload files

We need to let XAutoload know where composer has installed its vendor directory, and autoload files. Fortunately, doing this in our guzzle_example.module is a single line function.

/**
* Implements hook_autoload().
*/
function guzzle_example_xautoload($api) {
  $api->absolute()->composerDir('vendor/composer');
}

Step 5: Use Guzzle in your module

XAutoload does all the hard work of auto-loading our classes, so we can just instantiate them directly in our code:

<?php
function guzzle_example_get_host_ip() {
  $client = new \GuzzleHttp\Client();
  $response = $client->get('http://httpbin.org/get');
  $json = $response->json();
  return $json['origin'];
}

Here were are simply creating a new Guzzle Client object, and calling the get method with the url to our web service. Look mum! No require()! The web service returns a JSON response, with a key origin that has our IP address. Try it yourself! http://httpbin.org/get

Step 6: Output the data in a block

From here, we could wire can wire this up to some standard Drupal 7 custom block code, to output this a the site.

<?php
function guzzle_example_block_info() {
  return array(
    'host_ip' => array(
      'info' => t("What's My IP?"),
      'cache' => DRUPAL_NO_CACHE,
    ),
  );
}

function guzzle_example_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'host_ip':
$block['subject'] = t("What's My IP?");
$block['content'] = guzzle_example_get_host_ip();
break;
}
return $block;
}

Conclusion

A lot of PHP libraries are now being written using the PSR-0/4 standards, and its easier than ever to use them in your custom module code.

Why wait for Drupal 8?

Posted by Kim Pepper
Technical Director

Dated

Comments

Comment by dawehner

Dated

Just curious, what happens if multiple modules have the same external dependencies?

Comment by Kim Pepper

Dated

This example is for your own custom modules using external libraries, so the assumption is you have a single composer.json for your project, which manages all dependencies. This is something that we currently do.

Managing dependencies for an unknown number of contrib modules is a a difficult problem, and one that hasn't really been solved yet! One solution is to try to naively merge them from multiple composer.json files like Composer Manager does.

Comment by Dave Hall

Dated

Nice write up Kim. I prefer to use the Composer Manager module over XAutoloader. It makes it easy to work with composer and includes a PSR-0/4 compliant autoloader.

Comment by Manu

Dated

Imo, composer manager has the avantage of supporting composer dependencies in contrib modules also. More and more recent modules does have a composer.json file.
So Composer resolving contrib+custom package dependecies is a big win for me, but having some room for improvements.

Comment by Dave

Dated

Confused by Step 5 when you say, "Composer Manager does all the hard work of auto-loading our classes..."

This is the first time "Composer Manager" is mentioned. Are you referring to the Drupal.org Composer Manager module? And I thought Xautoload was supposed to handle autoloading? Are you using both Composer Manager AND Xautoload?

Comment by Kim Pepper

Dated

Sorry about that! That was a mistake. I've updated.

We previously had been using Composer Manager, but found creating a single composer.json file that we manually manage ourselves, was preferable to the way Composer Manager naively merged the composer.json files together. Either approach will work, it just depends on your level of confidence with composer.

Comment by donquixote

Dated

> Composer Manager module? And I thought Xautoload was supposed to handle autoloading? Are you using both Composer Manager AND Xautoload?

The question of Composer manager is more how you want to download and manage the libraries and their dependencies. The autoloading is really a second thought, there is not really much of a difference.

There is even an issue on Composer manager to use xautoload as a class loader: https://www.drupal.org/node/1943536. But the question is really where is the benefit?

The xautoload cache (APC or other) works better if no other class loaders are active. But the difference is minimal. And in general, the two can live side by side.

Comment by Dinesh Waghmare

Dated

Hi, nice documentation, however with latest composer manager its easy to maintain dependencies among contrib as well as custom modules.

Would be great to start using composer_manager and drush to deal with it.

Pagination

Add new comment

Restricted HTML

  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <h2> <h3> <h4> <h5> <h6>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Not sure where to start? Try typing "hello" or "help" if you get stuck.