Accessing Libraries, Whether In Drupal or Elsewhere

One of the assumptions regularly made is that libraries, like getid3 or Zend, live within the Drupal directory structure. The popular pattern is to put them in the libraries directory alongside the modules and themes directories. This is very limited both in workflow and accessibility to libraries. What if a developer wants to have a library in the PHP include path so multiple sites, not all of which are Drupal, can share it? What if someone wants to use Pear to manage that library? Let's take a look at a quick pattern for providing for a wide variety of possible locations for libraries.

Getting The Path

In order to work with the classes and functions provided by the library you need the path to include them. If the library was to be in the include path it would be as simple as:

include 'path/to/lib/file.php';

But, when you're taking into account the possibility it could be in the include path, in the Drupal directory structure, or elsewhere you need the path to the library.

/**
 * Retrieve the expected path to the example library.
 *
 * @return
 *   The path where the example library is to be expected to be installed.
 *
 * Note: Replace the example library name with a specific one.
 */
function example_get_path() {
  // A path can be configured to the location of the library.
  $path = variable_get('example_path', FALSE);

  if (!$path) {
    // Check if the libraries module is installed and if the example library is
    // being supplied through the libraries module.
    if (module_exists('libraries')) {
      // Check if the library is found. If no library is found libraries_get_path()
      // will still return sites/all/libraries as a path.
      $libraries = libraries_get_libraries();
      if (isset($libraries['example'])) {
        $path = libraries_get_path('example');
      }
    }

    // Check if the example library is in the include path.
    if (!$path) {
      $include_paths = explode(PATH_SEPARATOR, get_include_path());
        foreach ($include_paths as $include_path) {
          if (is_dir($include_path .'/example')) {
            $path = $include_path .'/example';
            continue;
          }
        }
    }
  }

  return $path;
}

The example above checks for the library in 3 different places.

  1. A configured location in the variables.
  2. In a libraries folder alongside the modules and themes folders. The dependency on Libraries API is not required but is checked if available.
  3. The PHP configured include path. This is where libraries can be manually placed or where Pear is typically configured to place them.

Autoloading Classes and Interfaces

Many of the libraries include an autoloader to load the classes and interfaces automatically. This way you do not need to manually include each file. An example of doing that could look like:

/**
 * Implementation of hook_init().
 */
function example_init() {
  // Due to the dependency on the libraries module being included, we wait until
  // hook_init() to register the example library.
  if ($path = example_get_path()) {
    require_once $path .'/autoloader.php';
    Example_Autoloader::getInstance();
  }
}

Not all libraries include an autoloader but many still include classes and interfaces. If you would still like to use one checkout the autoload module.

If you want the library to be available to all hook_init() functions it would be a good idea to set the weight of the library to be lower than all the other modules on the site. And, providing an implementation of hook_requirements() to check for the library being available and for a library version is useful. Examples of both of these can be found in the 2.x branch of the Zend modules zend.install file.

Note: The example code is based on the 2.x branch of the Zend module.