Libraries API is a module that helps you with integrating 3rd party libraries.
Such libraries typically live in sites/all/libraries/$library_name, but there are other possible places.

The exact behavior of libraries + xautoload is currently being discussed. This doc page describes what is currently implemented in 7.x-5.x. Please follow #2297525: Libraries integration: Require libraries_load()..

You can use xautoload with hook_libraries_info() to have library-provided classes be autoloaded. But you could also use other solutions, such as an autoload.php shipped with the library. Up to you.

Always call libraries_load($library_name)

with Libraries API, it is the user's (site builder's) job to actually download the library and put it in place in the filesystem.

As a consequence, you cannot just assume that a library is properly downloaded / installed. Instead, you need to call libraries_load() to verify that. Besides that, libraries_load() will include all the files and call the callbacks ("pre-load" and "post-load") that were registered with hook_libraries_info() for this library.

function MYMODULE_foo() {
  if (($library = libraries_load('restaurant_api')) && !empty($library['loaded'])) {
    .. // do something with Restaurant API.
  }
}

Libraries + xautoload works without libraries_load() for BC reasons, but don't count on that!

Surprisingly, one thing that works without libraries_load() is xautoload integration. Library classes made available with "xautoload" key in hook_libraries_info() will be available no matter what, if only the library is installed.

The reason this happens is backwards compatibility. xautoload used to not care about libraries_load() in the past, so we can expect some modules out there which just use the classes and don't care to call libraries_load(). We don't want to break these modules.

This being said, you should still call libraries_load() to be safe, if only to make sure that the library exists.

xautoload callback in hook_libraries_info()

With X Autoload, you can use hook_libraries_info() to register class locations for libraries registered with Libraries API.

Note: Do NOT use hook_libraries_info_alter() for this!

/**
 * Implements hook_libraries_info()
 *
 * Allows to register PSR-0 (or other) class folders for your libraries.
 * (those things living in sites/all/libraries)
 *
 * The original documentation for this hook is at libraries module,
 * libraries.api.php
 *
 * X Autoload extends the capabilities of this hook, by adding an "xautoload"
 * key. This key takes a callback or closure function, which has the same
 * signature as hook_xautoload($adapter).
 * This means, you can use the same methods on the $api object.
 *
 * @return array[]
 *   Same as explained in libraries module, but with added key 'xautoload'.
 */
function mymodule_libraries_info() {

  return array(
    'ruebenkraut' => array(
      'name' => 'Rübenkraut library',
      'vendor url' => 'http://www.example.com',
      'download url' => 'http://github.com/example/ruebenkraut',
      'version' => '1.0',
      'xautoload' => function($adapter) {
          /**
           * @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter
           *   An adapter object that can register stuff into the class loader.
           */
          // Register a namespace with PSR-0 root in
          // 'sites/all/libraries/ruebenkraut/src'.
          $adapter->add('Rueben\Kraut\\', 'src');
        },
    ),
    'gurkentraum' => array(
      'name' => 'Gurkentraum library',
      'xautoload' => function($adapter) {
          /** @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter */
          // Scan sites/all/libraries/ruebenkraut/composer.json to look for
          // autoload information.
          $adapter->composerJson('composer.json');
        }
    ),
  );
}

Note the @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter inline docblock. This is not required, but helps your IDE to show useful type hints, e.g. about the available methods on the $adapter object.

Side effects?

Due to library classes being made available without libraries_load(), some libraries functions are called more often if xautoload is installed. The result is cached, but libraries_info() hook_libraries_info() and libraries_get_path() / libraries_get_libraries() will be called on cache clear (*), and after modules have been enabled (*).

Implementations of hook_libraries_info() that define a closure (anonymous function) will be called again every now and then (*), because closures cannot be serialized. Other implementations of hook_libraries_info() will not be called again.

(*) All of this does only happen on cache miss, that is, if at least one class file is not already cached in the class loader cache (APC or similar), or if no class loader cache is active.

Comments

RAWDESK’s picture

Here's my code in an attempt to have the Egulias email.validator library accessible in D7.

function my_module_libraries_info() {
  $libraries['EmailValidator'] = array(
    'name' => 'RFC 6531 email validator',
    'vendor url' => 'https://github.com/egulias/EmailValidator',
    'download url' => 'https://github.com/egulias/EmailValidator',
    'version' => '2.1.7',
    'xautoload' => function($adapter) {
      /**
       * @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter
       *   An adapter object that can register stuff into the class loader.
       */
      $adapter->add('Egulias\\EmailValidator\\', 'EmailValidator');
    },
  );
  return $libraries;
}

Alternative

function my_module_libraries_info() {
  $libraries['EmailValidator'] = array(
    'name' => 'RFC 6531 email validator',
    'vendor url' => 'https://github.com/egulias/EmailValidator',
    'download url' => 'https://github.com/egulias/EmailValidator',
    'version' => '2.1.7',
    'xautoload' => function($adapter) {
      /**
       * @var \Drupal\xautoload\Adapter\LocalDirectoryAdapter $adapter
       *   An adapter object that can register stuff into the class loader.
       */
      $adapter->composerJson('composer.json');
    },
  );
  return $libraries;
}

For some unclear reason, the classes are not available when called from either custom modules at sites/all/modules/custom or core paths like includes/common.inc

The error thrown is :
Fatal error: Class 'EmailValidator' not found in /var/www/root/includes/common.inc on line 1240

function valid_email_address($mail) {
  if (module_exists('libraries') && libraries_load('EmailValidator')) {
    $validator = new EmailValidator();;
    return $validator->isValid($mail, new RFCValidation());
  }
  return (bool)filter_var($mail, FILTER_VALIDATE_EMAIL);
}

The libraries_load('EmailValidator') shows the complete by info hook prepared Library instance, containing a Drupal\xautoload\Libraries\SerializableClosureWrapper object.

Am I missing something here ?
As I understood from xautoload docs, PSR-4 is supported.