annotate sites/all/modules/libraries/libraries.module @ 2:b74b41bb73f0

-- Google analytics module
author danieleb <danielebarchiesi@me.com>
date Thu, 22 Aug 2013 17:22:54 +0100
parents
children b28be78d8160
rev   line source
danielebarchiesi@2 1 <?php
danielebarchiesi@2 2
danielebarchiesi@2 3 /**
danielebarchiesi@2 4 * @file
danielebarchiesi@2 5 * External library handling for Drupal modules.
danielebarchiesi@2 6 */
danielebarchiesi@2 7
danielebarchiesi@2 8 /**
danielebarchiesi@2 9 * Implements hook_flush_caches().
danielebarchiesi@2 10 */
danielebarchiesi@2 11 function libraries_flush_caches() {
danielebarchiesi@2 12 // @todo When upgrading from 1.x, update.php attempts to flush caches before
danielebarchiesi@2 13 // the cache table has been created.
danielebarchiesi@2 14 // @see http://drupal.org/node/1477932
danielebarchiesi@2 15 if (db_table_exists('cache_libraries')) {
danielebarchiesi@2 16 return array('cache_libraries');
danielebarchiesi@2 17 }
danielebarchiesi@2 18 }
danielebarchiesi@2 19
danielebarchiesi@2 20 /**
danielebarchiesi@2 21 * Gets the path of a library.
danielebarchiesi@2 22 *
danielebarchiesi@2 23 * @param $name
danielebarchiesi@2 24 * The machine name of a library to return the path for.
danielebarchiesi@2 25 * @param $base_path
danielebarchiesi@2 26 * Whether to prefix the resulting path with base_path().
danielebarchiesi@2 27 *
danielebarchiesi@2 28 * @return
danielebarchiesi@2 29 * The path to the specified library or FALSE if the library wasn't found.
danielebarchiesi@2 30 *
danielebarchiesi@2 31 * @ingroup libraries
danielebarchiesi@2 32 */
danielebarchiesi@2 33 function libraries_get_path($name, $base_path = FALSE) {
danielebarchiesi@2 34 $libraries = &drupal_static(__FUNCTION__);
danielebarchiesi@2 35
danielebarchiesi@2 36 if (!isset($libraries)) {
danielebarchiesi@2 37 $libraries = libraries_get_libraries();
danielebarchiesi@2 38 }
danielebarchiesi@2 39
danielebarchiesi@2 40 $path = ($base_path ? base_path() : '');
danielebarchiesi@2 41 if (!isset($libraries[$name])) {
danielebarchiesi@2 42 return FALSE;
danielebarchiesi@2 43 }
danielebarchiesi@2 44 else {
danielebarchiesi@2 45 $path .= $libraries[$name];
danielebarchiesi@2 46 }
danielebarchiesi@2 47
danielebarchiesi@2 48 return $path;
danielebarchiesi@2 49 }
danielebarchiesi@2 50
danielebarchiesi@2 51 /**
danielebarchiesi@2 52 * Returns an array of library directories.
danielebarchiesi@2 53 *
danielebarchiesi@2 54 * Returns an array of library directories from the all-sites directory
danielebarchiesi@2 55 * (i.e. sites/all/libraries/), the profiles directory, and site-specific
danielebarchiesi@2 56 * directory (i.e. sites/somesite/libraries/). The returned array will be keyed
danielebarchiesi@2 57 * by the library name. Site-specific libraries are prioritized over libraries
danielebarchiesi@2 58 * in the default directories. That is, if a library with the same name appears
danielebarchiesi@2 59 * in both the site-wide directory and site-specific directory, only the
danielebarchiesi@2 60 * site-specific version will be listed.
danielebarchiesi@2 61 *
danielebarchiesi@2 62 * @return
danielebarchiesi@2 63 * A list of library directories.
danielebarchiesi@2 64 *
danielebarchiesi@2 65 * @ingroup libraries
danielebarchiesi@2 66 */
danielebarchiesi@2 67 function libraries_get_libraries() {
danielebarchiesi@2 68 $searchdir = array();
danielebarchiesi@2 69 $profile = drupal_get_path('profile', drupal_get_profile());
danielebarchiesi@2 70 $config = conf_path();
danielebarchiesi@2 71
danielebarchiesi@2 72 // Similar to 'modules' and 'themes' directories in the root directory,
danielebarchiesi@2 73 // certain distributions may want to place libraries into a 'libraries'
danielebarchiesi@2 74 // directory in Drupal's root directory.
danielebarchiesi@2 75 $searchdir[] = 'libraries';
danielebarchiesi@2 76
danielebarchiesi@2 77 // Similar to 'modules' and 'themes' directories inside an installation
danielebarchiesi@2 78 // profile, installation profiles may want to place libraries into a
danielebarchiesi@2 79 // 'libraries' directory.
danielebarchiesi@2 80 $searchdir[] = "$profile/libraries";
danielebarchiesi@2 81
danielebarchiesi@2 82 // Always search sites/all/libraries.
danielebarchiesi@2 83 $searchdir[] = 'sites/all/libraries';
danielebarchiesi@2 84
danielebarchiesi@2 85 // Also search sites/<domain>/*.
danielebarchiesi@2 86 $searchdir[] = "$config/libraries";
danielebarchiesi@2 87
danielebarchiesi@2 88 // Retrieve list of directories.
danielebarchiesi@2 89 $directories = array();
danielebarchiesi@2 90 $nomask = array('CVS');
danielebarchiesi@2 91 foreach ($searchdir as $dir) {
danielebarchiesi@2 92 if (is_dir($dir) && $handle = opendir($dir)) {
danielebarchiesi@2 93 while (FALSE !== ($file = readdir($handle))) {
danielebarchiesi@2 94 if (!in_array($file, $nomask) && $file[0] != '.') {
danielebarchiesi@2 95 if (is_dir("$dir/$file")) {
danielebarchiesi@2 96 $directories[$file] = "$dir/$file";
danielebarchiesi@2 97 }
danielebarchiesi@2 98 }
danielebarchiesi@2 99 }
danielebarchiesi@2 100 closedir($handle);
danielebarchiesi@2 101 }
danielebarchiesi@2 102 }
danielebarchiesi@2 103
danielebarchiesi@2 104 return $directories;
danielebarchiesi@2 105 }
danielebarchiesi@2 106
danielebarchiesi@2 107 /**
danielebarchiesi@2 108 * Looks for library info files.
danielebarchiesi@2 109 *
danielebarchiesi@2 110 * This function scans the following directories for info files:
danielebarchiesi@2 111 * - libraries
danielebarchiesi@2 112 * - profiles/$profilename/libraries
danielebarchiesi@2 113 * - sites/all/libraries
danielebarchiesi@2 114 * - sites/$sitename/libraries
danielebarchiesi@2 115 * - any directories specified via hook_libraries_info_file_paths()
danielebarchiesi@2 116 *
danielebarchiesi@2 117 * @return
danielebarchiesi@2 118 * An array of info files, keyed by library name. The values are the paths of
danielebarchiesi@2 119 * the files.
danielebarchiesi@2 120 */
danielebarchiesi@2 121 function libraries_scan_info_files() {
danielebarchiesi@2 122 $profile = drupal_get_path('profile', drupal_get_profile());
danielebarchiesi@2 123 $config = conf_path();
danielebarchiesi@2 124
danielebarchiesi@2 125 // Build a list of directories.
danielebarchiesi@2 126 $directories = module_invoke_all('libraries_info_file_paths');
danielebarchiesi@2 127 $directories[] = 'libraries';
danielebarchiesi@2 128 $directories[] = "$profile/libraries";
danielebarchiesi@2 129 $directories[] = 'sites/all/libraries';
danielebarchiesi@2 130 $directories[] = "$config/libraries";
danielebarchiesi@2 131
danielebarchiesi@2 132 // Scan for info files.
danielebarchiesi@2 133 $files = array();
danielebarchiesi@2 134 foreach ($directories as $dir) {
danielebarchiesi@2 135 if (file_exists($dir)) {
danielebarchiesi@2 136 $files = array_merge($files, file_scan_directory($dir, '@^[a-z0-9._-]+\.libraries\.info$@', array(
danielebarchiesi@2 137 'key' => 'name',
danielebarchiesi@2 138 'recurse' => FALSE,
danielebarchiesi@2 139 )));
danielebarchiesi@2 140 }
danielebarchiesi@2 141 }
danielebarchiesi@2 142
danielebarchiesi@2 143 foreach ($files as $filename => $file) {
danielebarchiesi@2 144 $files[basename($filename, '.libraries')] = $file;
danielebarchiesi@2 145 unset($files[$filename]);
danielebarchiesi@2 146 }
danielebarchiesi@2 147
danielebarchiesi@2 148 return $files;
danielebarchiesi@2 149 }
danielebarchiesi@2 150
danielebarchiesi@2 151 /**
danielebarchiesi@2 152 * Invokes library callbacks.
danielebarchiesi@2 153 *
danielebarchiesi@2 154 * @param $group
danielebarchiesi@2 155 * A string containing the group of callbacks that is to be applied. Should be
danielebarchiesi@2 156 * either 'info', 'pre-detect', 'post-detect', or 'load'.
danielebarchiesi@2 157 * @param $library
danielebarchiesi@2 158 * An array of library information, passed by reference.
danielebarchiesi@2 159 */
danielebarchiesi@2 160 function libraries_invoke($group, &$library) {
danielebarchiesi@2 161 foreach ($library['callbacks'][$group] as $callback) {
danielebarchiesi@2 162 libraries_traverse_library($library, $callback);
danielebarchiesi@2 163 }
danielebarchiesi@2 164 }
danielebarchiesi@2 165
danielebarchiesi@2 166 /**
danielebarchiesi@2 167 * Helper function to apply a callback to all parts of a library.
danielebarchiesi@2 168 *
danielebarchiesi@2 169 * Because library declarations can include variants and versions, and those
danielebarchiesi@2 170 * version declarations can in turn include variants, modifying e.g. the 'files'
danielebarchiesi@2 171 * property everywhere it is declared can be quite cumbersome, in which case
danielebarchiesi@2 172 * this helper function is useful.
danielebarchiesi@2 173 *
danielebarchiesi@2 174 * @param $library
danielebarchiesi@2 175 * An array of library information, passed by reference.
danielebarchiesi@2 176 * @param $callback
danielebarchiesi@2 177 * A string containing the callback to apply to all parts of a library.
danielebarchiesi@2 178 */
danielebarchiesi@2 179 function libraries_traverse_library(&$library, $callback) {
danielebarchiesi@2 180 // Always apply the callback to the top-level library.
danielebarchiesi@2 181 $callback($library, NULL, NULL);
danielebarchiesi@2 182
danielebarchiesi@2 183 // Apply the callback to versions.
danielebarchiesi@2 184 if (isset($library['versions'])) {
danielebarchiesi@2 185 foreach ($library['versions'] as $version_string => &$version) {
danielebarchiesi@2 186 $callback($version, $version_string, NULL);
danielebarchiesi@2 187 // Versions can include variants as well.
danielebarchiesi@2 188 if (isset($version['variants'])) {
danielebarchiesi@2 189 foreach ($version['variants'] as $version_variant_name => &$version_variant) {
danielebarchiesi@2 190 $callback($version_variant, $version_string, $version_variant_name);
danielebarchiesi@2 191 }
danielebarchiesi@2 192 }
danielebarchiesi@2 193 }
danielebarchiesi@2 194 }
danielebarchiesi@2 195
danielebarchiesi@2 196 // Apply the callback to variants.
danielebarchiesi@2 197 if (isset($library['variants'])) {
danielebarchiesi@2 198 foreach ($library['variants'] as $variant_name => &$variant) {
danielebarchiesi@2 199 $callback($variant, NULL, $variant_name);
danielebarchiesi@2 200 }
danielebarchiesi@2 201 }
danielebarchiesi@2 202 }
danielebarchiesi@2 203
danielebarchiesi@2 204 /**
danielebarchiesi@2 205 * Library info callback to make all 'files' properties consistent.
danielebarchiesi@2 206 *
danielebarchiesi@2 207 * This turns libraries' file information declared as e.g.
danielebarchiesi@2 208 * @code
danielebarchiesi@2 209 * $library['files']['js'] = array('example_1.js', 'example_2.js');
danielebarchiesi@2 210 * @endcode
danielebarchiesi@2 211 * into
danielebarchiesi@2 212 * @code
danielebarchiesi@2 213 * $library['files']['js'] = array(
danielebarchiesi@2 214 * 'example_1.js' => array(),
danielebarchiesi@2 215 * 'example_2.js' => array(),
danielebarchiesi@2 216 * );
danielebarchiesi@2 217 * @endcode
danielebarchiesi@2 218 * It does the same for the 'integration files' property.
danielebarchiesi@2 219 *
danielebarchiesi@2 220 * @param $library
danielebarchiesi@2 221 * An associative array of library information or a part of it, passed by
danielebarchiesi@2 222 * reference.
danielebarchiesi@2 223 * @param $version
danielebarchiesi@2 224 * If the library information belongs to a specific version, the version
danielebarchiesi@2 225 * string. NULL otherwise.
danielebarchiesi@2 226 * @param $variant
danielebarchiesi@2 227 * If the library information belongs to a specific variant, the variant name.
danielebarchiesi@2 228 * NULL otherwise.
danielebarchiesi@2 229 *
danielebarchiesi@2 230 * @see libraries_info()
danielebarchiesi@2 231 * @see libraries_invoke()
danielebarchiesi@2 232 */
danielebarchiesi@2 233 function libraries_prepare_files(&$library, $version = NULL, $variant = NULL) {
danielebarchiesi@2 234 // Both the 'files' property and the 'integration files' property contain file
danielebarchiesi@2 235 // declarations, and we want to make both consistent.
danielebarchiesi@2 236 $file_types = array();
danielebarchiesi@2 237 if (isset($library['files'])) {
danielebarchiesi@2 238 $file_types[] = &$library['files'];
danielebarchiesi@2 239 }
danielebarchiesi@2 240 if (isset($library['integration files'])) {
danielebarchiesi@2 241 // Integration files are additionally keyed by module.
danielebarchiesi@2 242 foreach ($library['integration files'] as &$integration_files) {
danielebarchiesi@2 243 $file_types[] = &$integration_files;
danielebarchiesi@2 244 }
danielebarchiesi@2 245 }
danielebarchiesi@2 246 foreach ($file_types as &$files) {
danielebarchiesi@2 247 // Go through all supported types of files.
danielebarchiesi@2 248 foreach (array('js', 'css', 'php') as $type) {
danielebarchiesi@2 249 if (isset($files[$type])) {
danielebarchiesi@2 250 foreach ($files[$type] as $key => $value) {
danielebarchiesi@2 251 // Unset numeric keys and turn the respective values into keys.
danielebarchiesi@2 252 if (is_numeric($key)) {
danielebarchiesi@2 253 $files[$type][$value] = array();
danielebarchiesi@2 254 unset($files[$type][$key]);
danielebarchiesi@2 255 }
danielebarchiesi@2 256 }
danielebarchiesi@2 257 }
danielebarchiesi@2 258 }
danielebarchiesi@2 259 }
danielebarchiesi@2 260 }
danielebarchiesi@2 261
danielebarchiesi@2 262 /**
danielebarchiesi@2 263 * Library post-detect callback to process and detect dependencies.
danielebarchiesi@2 264 *
danielebarchiesi@2 265 * It checks whether each of the dependencies of a library are installed and
danielebarchiesi@2 266 * available in a compatible version.
danielebarchiesi@2 267 *
danielebarchiesi@2 268 * @param $library
danielebarchiesi@2 269 * An associative array of library information or a part of it, passed by
danielebarchiesi@2 270 * reference.
danielebarchiesi@2 271 * @param $version
danielebarchiesi@2 272 * If the library information belongs to a specific version, the version
danielebarchiesi@2 273 * string. NULL otherwise.
danielebarchiesi@2 274 * @param $variant
danielebarchiesi@2 275 * If the library information belongs to a specific variant, the variant name.
danielebarchiesi@2 276 * NULL otherwise.
danielebarchiesi@2 277 *
danielebarchiesi@2 278 * @see libraries_info()
danielebarchiesi@2 279 * @see libraries_invoke()
danielebarchiesi@2 280 */
danielebarchiesi@2 281 function libraries_detect_dependencies(&$library, $version = NULL, $variant = NULL) {
danielebarchiesi@2 282 if (isset($library['dependencies'])) {
danielebarchiesi@2 283 foreach ($library['dependencies'] as &$dependency_string) {
danielebarchiesi@2 284 $dependency_info = drupal_parse_dependency($dependency_string);
danielebarchiesi@2 285 $dependency = libraries_detect($dependency_info['name']);
danielebarchiesi@2 286 if (!$dependency['installed']) {
danielebarchiesi@2 287 $library['installed'] = FALSE;
danielebarchiesi@2 288 $library['error'] = 'missing dependency';
danielebarchiesi@2 289 $library['error message'] = t('The %dependency library, which the %library library depends on, is not installed.', array(
danielebarchiesi@2 290 '%dependency' => $dependency['name'],
danielebarchiesi@2 291 '%library' => $library['name'],
danielebarchiesi@2 292 ));
danielebarchiesi@2 293 }
danielebarchiesi@2 294 elseif (drupal_check_incompatibility($dependency_info, $dependency['version'])) {
danielebarchiesi@2 295 $library['installed'] = FALSE;
danielebarchiesi@2 296 $library['error'] = 'incompatible dependency';
danielebarchiesi@2 297 $library['error message'] = t('The version %dependency_version of the %dependency library is not compatible with the %library library.', array(
danielebarchiesi@2 298 '%dependency_version' => $dependency['version'],
danielebarchiesi@2 299 '%dependency' => $dependency['name'],
danielebarchiesi@2 300 '%library' => $library['name'],
danielebarchiesi@2 301 ));
danielebarchiesi@2 302 }
danielebarchiesi@2 303
danielebarchiesi@2 304 // Remove the version string from the dependency, so libraries_load() can
danielebarchiesi@2 305 // load the libraries directly.
danielebarchiesi@2 306 $dependency_string = $dependency_info['name'];
danielebarchiesi@2 307 }
danielebarchiesi@2 308 }
danielebarchiesi@2 309 }
danielebarchiesi@2 310
danielebarchiesi@2 311 /**
danielebarchiesi@2 312 * Returns information about registered libraries.
danielebarchiesi@2 313 *
danielebarchiesi@2 314 * The returned information is unprocessed; i.e., as registered by modules.
danielebarchiesi@2 315 *
danielebarchiesi@2 316 * @param $name
danielebarchiesi@2 317 * (optional) The machine name of a library to return registered information
danielebarchiesi@2 318 * for. If omitted, information about all registered libraries is returned.
danielebarchiesi@2 319 *
danielebarchiesi@2 320 * @return array|false
danielebarchiesi@2 321 * An associative array containing registered information for all libraries,
danielebarchiesi@2 322 * the registered information for the library specified by $name, or FALSE if
danielebarchiesi@2 323 * the library $name is not registered.
danielebarchiesi@2 324 *
danielebarchiesi@2 325 * @see hook_libraries_info()
danielebarchiesi@2 326 *
danielebarchiesi@2 327 * @todo Re-introduce support for include file plugin system - either by copying
danielebarchiesi@2 328 * Wysiwyg's code, or directly switching to CTools.
danielebarchiesi@2 329 */
danielebarchiesi@2 330 function &libraries_info($name = NULL) {
danielebarchiesi@2 331 // This static cache is re-used by libraries_detect() to save memory.
danielebarchiesi@2 332 $libraries = &drupal_static(__FUNCTION__);
danielebarchiesi@2 333
danielebarchiesi@2 334 if (!isset($libraries)) {
danielebarchiesi@2 335 $libraries = array();
danielebarchiesi@2 336 // Gather information from hook_libraries_info().
danielebarchiesi@2 337 foreach (module_implements('libraries_info') as $module) {
danielebarchiesi@2 338 foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
danielebarchiesi@2 339 $properties['module'] = $module;
danielebarchiesi@2 340 $libraries[$machine_name] = $properties;
danielebarchiesi@2 341 }
danielebarchiesi@2 342 }
danielebarchiesi@2 343 // Gather information from hook_libraries_info() in enabled themes.
danielebarchiesi@2 344 // @see drupal_alter()
danielebarchiesi@2 345 global $theme, $base_theme_info;
danielebarchiesi@2 346 if (isset($theme)) {
danielebarchiesi@2 347 $theme_keys = array();
danielebarchiesi@2 348 foreach ($base_theme_info as $base) {
danielebarchiesi@2 349 $theme_keys[] = $base->name;
danielebarchiesi@2 350 }
danielebarchiesi@2 351 $theme_keys[] = $theme;
danielebarchiesi@2 352 foreach ($theme_keys as $theme_key) {
danielebarchiesi@2 353 $function = $theme_key . '_' . 'libraries_info';
danielebarchiesi@2 354 if (function_exists($function)) {
danielebarchiesi@2 355 foreach ($function() as $machine_name => $properties) {
danielebarchiesi@2 356 $properties['theme'] = $theme_key;
danielebarchiesi@2 357 $libraries[$machine_name] = $properties;
danielebarchiesi@2 358 }
danielebarchiesi@2 359 }
danielebarchiesi@2 360 }
danielebarchiesi@2 361 }
danielebarchiesi@2 362
danielebarchiesi@2 363 // Gather information from .info files.
danielebarchiesi@2 364 // .info files override module definitions.
danielebarchiesi@2 365 foreach (libraries_scan_info_files() as $machine_name => $file) {
danielebarchiesi@2 366 $properties = drupal_parse_info_file($file->uri);
danielebarchiesi@2 367 $properties['info file'] = $file->uri;
danielebarchiesi@2 368 $libraries[$machine_name] = $properties;
danielebarchiesi@2 369 }
danielebarchiesi@2 370
danielebarchiesi@2 371 // Provide defaults.
danielebarchiesi@2 372 foreach ($libraries as $machine_name => &$properties) {
danielebarchiesi@2 373 libraries_info_defaults($properties, $machine_name);
danielebarchiesi@2 374 }
danielebarchiesi@2 375
danielebarchiesi@2 376 // Allow modules to alter the registered libraries.
danielebarchiesi@2 377 drupal_alter('libraries_info', $libraries);
danielebarchiesi@2 378
danielebarchiesi@2 379 // Invoke callbacks in the 'info' group.
danielebarchiesi@2 380 foreach ($libraries as &$properties) {
danielebarchiesi@2 381 libraries_invoke('info', $properties);
danielebarchiesi@2 382 }
danielebarchiesi@2 383 }
danielebarchiesi@2 384
danielebarchiesi@2 385 if (isset($name)) {
danielebarchiesi@2 386 if (!empty($libraries[$name])) {
danielebarchiesi@2 387 return $libraries[$name];
danielebarchiesi@2 388 }
danielebarchiesi@2 389 else {
danielebarchiesi@2 390 $false = FALSE;
danielebarchiesi@2 391 return $false;
danielebarchiesi@2 392 }
danielebarchiesi@2 393 }
danielebarchiesi@2 394 return $libraries;
danielebarchiesi@2 395 }
danielebarchiesi@2 396
danielebarchiesi@2 397 /**
danielebarchiesi@2 398 * Applies default properties to a library definition.
danielebarchiesi@2 399 *
danielebarchiesi@2 400 * @library
danielebarchiesi@2 401 * An array of library information, passed by reference.
danielebarchiesi@2 402 * @name
danielebarchiesi@2 403 * The machine name of the passed-in library.
danielebarchiesi@2 404 */
danielebarchiesi@2 405 function libraries_info_defaults(&$library, $name) {
danielebarchiesi@2 406 $library += array(
danielebarchiesi@2 407 'machine name' => $name,
danielebarchiesi@2 408 'name' => $name,
danielebarchiesi@2 409 'vendor url' => '',
danielebarchiesi@2 410 'download url' => '',
danielebarchiesi@2 411 'path' => '',
danielebarchiesi@2 412 'library path' => NULL,
danielebarchiesi@2 413 'version callback' => 'libraries_get_version',
danielebarchiesi@2 414 'version arguments' => array(),
danielebarchiesi@2 415 'files' => array(),
danielebarchiesi@2 416 'dependencies' => array(),
danielebarchiesi@2 417 'variants' => array(),
danielebarchiesi@2 418 'versions' => array(),
danielebarchiesi@2 419 'integration files' => array(),
danielebarchiesi@2 420 'callbacks' => array(),
danielebarchiesi@2 421 );
danielebarchiesi@2 422 $library['callbacks'] += array(
danielebarchiesi@2 423 'info' => array(),
danielebarchiesi@2 424 'pre-detect' => array(),
danielebarchiesi@2 425 'post-detect' => array(),
danielebarchiesi@2 426 'pre-dependencies-load' => array(),
danielebarchiesi@2 427 'pre-load' => array(),
danielebarchiesi@2 428 'post-load' => array(),
danielebarchiesi@2 429 );
danielebarchiesi@2 430
danielebarchiesi@2 431 // Add our own callbacks before any others.
danielebarchiesi@2 432 array_unshift($library['callbacks']['info'], 'libraries_prepare_files');
danielebarchiesi@2 433 array_unshift($library['callbacks']['post-detect'], 'libraries_detect_dependencies');
danielebarchiesi@2 434
danielebarchiesi@2 435 return $library;
danielebarchiesi@2 436 }
danielebarchiesi@2 437
danielebarchiesi@2 438 /**
danielebarchiesi@2 439 * Tries to detect a library and its installed version.
danielebarchiesi@2 440 *
danielebarchiesi@2 441 * @param $name
danielebarchiesi@2 442 * The machine name of a library to return registered information for.
danielebarchiesi@2 443 *
danielebarchiesi@2 444 * @return array|false
danielebarchiesi@2 445 * An associative array containing registered information for the library
danielebarchiesi@2 446 * specified by $name, or FALSE if the library $name is not registered.
danielebarchiesi@2 447 * In addition to the keys returned by libraries_info(), the following keys
danielebarchiesi@2 448 * are contained:
danielebarchiesi@2 449 * - installed: A boolean indicating whether the library is installed. Note
danielebarchiesi@2 450 * that not only the top-level library, but also each variant contains this
danielebarchiesi@2 451 * key.
danielebarchiesi@2 452 * - version: If the version could be detected, the full version string.
danielebarchiesi@2 453 * - error: If an error occurred during library detection, one of the
danielebarchiesi@2 454 * following error statuses: "not found", "not detected", "not supported".
danielebarchiesi@2 455 * - error message: If an error occurred during library detection, a detailed
danielebarchiesi@2 456 * error message.
danielebarchiesi@2 457 *
danielebarchiesi@2 458 * @see libraries_info()
danielebarchiesi@2 459 */
danielebarchiesi@2 460 function libraries_detect($name) {
danielebarchiesi@2 461 // Re-use the statically cached value of libraries_info() to save memory.
danielebarchiesi@2 462 $library = &libraries_info($name);
danielebarchiesi@2 463
danielebarchiesi@2 464 if ($library === FALSE) {
danielebarchiesi@2 465 return $library;
danielebarchiesi@2 466 }
danielebarchiesi@2 467 // If 'installed' is set, library detection ran already.
danielebarchiesi@2 468 if (isset($library['installed'])) {
danielebarchiesi@2 469 return $library;
danielebarchiesi@2 470 }
danielebarchiesi@2 471
danielebarchiesi@2 472 $library['installed'] = FALSE;
danielebarchiesi@2 473
danielebarchiesi@2 474 // Check whether the library exists.
danielebarchiesi@2 475 if (!isset($library['library path'])) {
danielebarchiesi@2 476 $library['library path'] = libraries_get_path($library['machine name']);
danielebarchiesi@2 477 }
danielebarchiesi@2 478 if ($library['library path'] === FALSE || !file_exists($library['library path'])) {
danielebarchiesi@2 479 $library['error'] = 'not found';
danielebarchiesi@2 480 $library['error message'] = t('The %library library could not be found.', array(
danielebarchiesi@2 481 '%library' => $library['name'],
danielebarchiesi@2 482 ));
danielebarchiesi@2 483 return $library;
danielebarchiesi@2 484 }
danielebarchiesi@2 485
danielebarchiesi@2 486 // Invoke callbacks in the 'pre-detect' group.
danielebarchiesi@2 487 libraries_invoke('pre-detect', $library);
danielebarchiesi@2 488
danielebarchiesi@2 489 // Detect library version, if not hardcoded.
danielebarchiesi@2 490 if (!isset($library['version'])) {
danielebarchiesi@2 491 // We support both a single parameter, which is an associative array, and an
danielebarchiesi@2 492 // indexed array of multiple parameters.
danielebarchiesi@2 493 if (isset($library['version arguments'][0])) {
danielebarchiesi@2 494 // Add the library as the first argument.
danielebarchiesi@2 495 $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments']));
danielebarchiesi@2 496 }
danielebarchiesi@2 497 else {
danielebarchiesi@2 498 $library['version'] = $library['version callback']($library, $library['version arguments']);
danielebarchiesi@2 499 }
danielebarchiesi@2 500 if (empty($library['version'])) {
danielebarchiesi@2 501 $library['error'] = 'not detected';
danielebarchiesi@2 502 $library['error message'] = t('The version of the %library library could not be detected.', array(
danielebarchiesi@2 503 '%library' => $library['name'],
danielebarchiesi@2 504 ));
danielebarchiesi@2 505 return $library;
danielebarchiesi@2 506 }
danielebarchiesi@2 507 }
danielebarchiesi@2 508
danielebarchiesi@2 509 // Determine to which supported version the installed version maps.
danielebarchiesi@2 510 if (!empty($library['versions'])) {
danielebarchiesi@2 511 ksort($library['versions']);
danielebarchiesi@2 512 $version = 0;
danielebarchiesi@2 513 foreach ($library['versions'] as $supported_version => $version_properties) {
danielebarchiesi@2 514 if (version_compare($library['version'], $supported_version, '>=')) {
danielebarchiesi@2 515 $version = $supported_version;
danielebarchiesi@2 516 }
danielebarchiesi@2 517 }
danielebarchiesi@2 518 if (!$version) {
danielebarchiesi@2 519 $library['error'] = 'not supported';
danielebarchiesi@2 520 $library['error message'] = t('The installed version %version of the %library library is not supported.', array(
danielebarchiesi@2 521 '%version' => $library['version'],
danielebarchiesi@2 522 '%library' => $library['name'],
danielebarchiesi@2 523 ));
danielebarchiesi@2 524 return $library;
danielebarchiesi@2 525 }
danielebarchiesi@2 526
danielebarchiesi@2 527 // Apply version specific definitions and overrides.
danielebarchiesi@2 528 $library = array_merge($library, $library['versions'][$version]);
danielebarchiesi@2 529 unset($library['versions']);
danielebarchiesi@2 530 }
danielebarchiesi@2 531
danielebarchiesi@2 532 // Check each variant if it is installed.
danielebarchiesi@2 533 if (!empty($library['variants'])) {
danielebarchiesi@2 534 foreach ($library['variants'] as $variant_name => &$variant) {
danielebarchiesi@2 535 // If no variant callback has been set, assume the variant to be
danielebarchiesi@2 536 // installed.
danielebarchiesi@2 537 if (!isset($variant['variant callback'])) {
danielebarchiesi@2 538 $variant['installed'] = TRUE;
danielebarchiesi@2 539 }
danielebarchiesi@2 540 else {
danielebarchiesi@2 541 // We support both a single parameter, which is an associative array,
danielebarchiesi@2 542 // and an indexed array of multiple parameters.
danielebarchiesi@2 543 if (isset($variant['variant arguments'][0])) {
danielebarchiesi@2 544 // Add the library as the first argument, and the variant name as the second.
danielebarchiesi@2 545 $variant['installed'] = call_user_func_array($variant['variant callback'], array_merge(array($library, $variant_name), $variant['variant arguments']));
danielebarchiesi@2 546 }
danielebarchiesi@2 547 else {
danielebarchiesi@2 548 $variant['installed'] = $variant['variant callback']($library, $variant_name, $variant['variant arguments']);
danielebarchiesi@2 549 }
danielebarchiesi@2 550 if (!$variant['installed']) {
danielebarchiesi@2 551 $variant['error'] = 'not found';
danielebarchiesi@2 552 $variant['error message'] = t('The %variant variant of the %library library could not be found.', array(
danielebarchiesi@2 553 '%variant' => $variant_name,
danielebarchiesi@2 554 '%library' => $library['name'],
danielebarchiesi@2 555 ));
danielebarchiesi@2 556 }
danielebarchiesi@2 557 }
danielebarchiesi@2 558 }
danielebarchiesi@2 559 }
danielebarchiesi@2 560
danielebarchiesi@2 561 // If we end up here, the library should be usable.
danielebarchiesi@2 562 $library['installed'] = TRUE;
danielebarchiesi@2 563
danielebarchiesi@2 564 // Invoke callbacks in the 'post-detect' group.
danielebarchiesi@2 565 libraries_invoke('post-detect', $library);
danielebarchiesi@2 566
danielebarchiesi@2 567 return $library;
danielebarchiesi@2 568 }
danielebarchiesi@2 569
danielebarchiesi@2 570 /**
danielebarchiesi@2 571 * Loads a library.
danielebarchiesi@2 572 *
danielebarchiesi@2 573 * @param $name
danielebarchiesi@2 574 * The name of the library to load.
danielebarchiesi@2 575 * @param $variant
danielebarchiesi@2 576 * The name of the variant to load. Note that only one variant of a library
danielebarchiesi@2 577 * can be loaded within a single request. The variant that has been passed
danielebarchiesi@2 578 * first is used; different variant names in subsequent calls are ignored.
danielebarchiesi@2 579 *
danielebarchiesi@2 580 * @return
danielebarchiesi@2 581 * An associative array of the library information as returned from
danielebarchiesi@2 582 * libraries_info(). The top-level properties contain the effective definition
danielebarchiesi@2 583 * of the library (variant) that has been loaded. Additionally:
danielebarchiesi@2 584 * - installed: Whether the library is installed, as determined by
danielebarchiesi@2 585 * libraries_detect_library().
danielebarchiesi@2 586 * - loaded: Either the amount of library files that have been loaded, or
danielebarchiesi@2 587 * FALSE if the library could not be loaded.
danielebarchiesi@2 588 * See hook_libraries_info() for more information.
danielebarchiesi@2 589 */
danielebarchiesi@2 590 function libraries_load($name, $variant = NULL) {
danielebarchiesi@2 591 $loaded = &drupal_static(__FUNCTION__, array());
danielebarchiesi@2 592
danielebarchiesi@2 593 if (!isset($loaded[$name])) {
danielebarchiesi@2 594 $library = cache_get($name, 'cache_libraries');
danielebarchiesi@2 595 if ($library) {
danielebarchiesi@2 596 $library = $library->data;
danielebarchiesi@2 597 }
danielebarchiesi@2 598 else {
danielebarchiesi@2 599 $library = libraries_detect($name);
danielebarchiesi@2 600 cache_set($name, $library, 'cache_libraries');
danielebarchiesi@2 601 }
danielebarchiesi@2 602
danielebarchiesi@2 603 // If a variant was specified, override the top-level properties with the
danielebarchiesi@2 604 // variant properties.
danielebarchiesi@2 605 if (isset($variant)) {
danielebarchiesi@2 606 // Ensure that the $variant key exists, and if it does not, set its
danielebarchiesi@2 607 // 'installed' property to FALSE by default. This will prevent the loading
danielebarchiesi@2 608 // of the library files below.
danielebarchiesi@2 609 $library['variants'] += array($variant => array('installed' => FALSE));
danielebarchiesi@2 610 $library = array_merge($library, $library['variants'][$variant]);
danielebarchiesi@2 611 }
danielebarchiesi@2 612 // Regardless of whether a specific variant was requested or not, there can
danielebarchiesi@2 613 // only be one variant of a library within a single request.
danielebarchiesi@2 614 unset($library['variants']);
danielebarchiesi@2 615
danielebarchiesi@2 616 // Invoke callbacks in the 'pre-dependencies-load' group.
danielebarchiesi@2 617 libraries_invoke('pre-dependencies-load', $library);
danielebarchiesi@2 618
danielebarchiesi@2 619 // If the library (variant) is installed, load it.
danielebarchiesi@2 620 $library['loaded'] = FALSE;
danielebarchiesi@2 621 if ($library['installed']) {
danielebarchiesi@2 622 // Load library dependencies.
danielebarchiesi@2 623 if (isset($library['dependencies'])) {
danielebarchiesi@2 624 foreach ($library['dependencies'] as $dependency) {
danielebarchiesi@2 625 libraries_load($dependency);
danielebarchiesi@2 626 }
danielebarchiesi@2 627 }
danielebarchiesi@2 628
danielebarchiesi@2 629 // Invoke callbacks in the 'pre-load' group.
danielebarchiesi@2 630 libraries_invoke('pre-load', $library);
danielebarchiesi@2 631
danielebarchiesi@2 632 // Load all the files associated with the library.
danielebarchiesi@2 633 $library['loaded'] = libraries_load_files($library);
danielebarchiesi@2 634
danielebarchiesi@2 635 // Invoke callbacks in the 'post-load' group.
danielebarchiesi@2 636 libraries_invoke('post-load', $library);
danielebarchiesi@2 637 }
danielebarchiesi@2 638 $loaded[$name] = $library;
danielebarchiesi@2 639 }
danielebarchiesi@2 640
danielebarchiesi@2 641 return $loaded[$name];
danielebarchiesi@2 642 }
danielebarchiesi@2 643
danielebarchiesi@2 644 /**
danielebarchiesi@2 645 * Loads a library's files.
danielebarchiesi@2 646 *
danielebarchiesi@2 647 * @param $library
danielebarchiesi@2 648 * An array of library information as returned by libraries_info().
danielebarchiesi@2 649 *
danielebarchiesi@2 650 * @return
danielebarchiesi@2 651 * The number of loaded files.
danielebarchiesi@2 652 */
danielebarchiesi@2 653 function libraries_load_files($library) {
danielebarchiesi@2 654 // Load integration files.
danielebarchiesi@2 655 if (!empty($library['integration files'])) {
danielebarchiesi@2 656 foreach ($library['integration files'] as $module => $files) {
danielebarchiesi@2 657 libraries_load_files(array(
danielebarchiesi@2 658 'files' => $files,
danielebarchiesi@2 659 'path' => '',
danielebarchiesi@2 660 'library path' => drupal_get_path('module', $module),
danielebarchiesi@2 661 ));
danielebarchiesi@2 662 }
danielebarchiesi@2 663 }
danielebarchiesi@2 664
danielebarchiesi@2 665 // Construct the full path to the library for later use.
danielebarchiesi@2 666 $path = $library['library path'];
danielebarchiesi@2 667 $path = ($library['path'] !== '' ? $path . '/' . $library['path'] : $path);
danielebarchiesi@2 668
danielebarchiesi@2 669 // Count the number of loaded files for the return value.
danielebarchiesi@2 670 $count = 0;
danielebarchiesi@2 671
danielebarchiesi@2 672 // Load both the JavaScript and the CSS files.
danielebarchiesi@2 673 // The parameters for drupal_add_js() and drupal_add_css() require special
danielebarchiesi@2 674 // handling.
danielebarchiesi@2 675 // @see drupal_process_attached()
danielebarchiesi@2 676 foreach (array('js', 'css') as $type) {
danielebarchiesi@2 677 if (!empty($library['files'][$type])) {
danielebarchiesi@2 678 foreach ($library['files'][$type] as $data => $options) {
danielebarchiesi@2 679 // If the value is not an array, it's a filename and passed as first
danielebarchiesi@2 680 // (and only) argument.
danielebarchiesi@2 681 if (!is_array($options)) {
danielebarchiesi@2 682 $data = $options;
danielebarchiesi@2 683 $options = array();
danielebarchiesi@2 684 }
danielebarchiesi@2 685 // In some cases, the first parameter ($data) is an array. Arrays can't
danielebarchiesi@2 686 // be passed as keys in PHP, so we have to get $data from the value
danielebarchiesi@2 687 // array.
danielebarchiesi@2 688 if (is_numeric($data)) {
danielebarchiesi@2 689 $data = $options['data'];
danielebarchiesi@2 690 unset($options['data']);
danielebarchiesi@2 691 }
danielebarchiesi@2 692 // Prepend the library path to the file name.
danielebarchiesi@2 693 $data = "$path/$data";
danielebarchiesi@2 694 // Apply the default group if the group isn't explicitly given.
danielebarchiesi@2 695 if (!isset($options['group'])) {
danielebarchiesi@2 696 $options['group'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
danielebarchiesi@2 697 }
danielebarchiesi@2 698 call_user_func('drupal_add_' . $type, $data, $options);
danielebarchiesi@2 699 $count++;
danielebarchiesi@2 700 }
danielebarchiesi@2 701 }
danielebarchiesi@2 702 }
danielebarchiesi@2 703
danielebarchiesi@2 704 // Load PHP files.
danielebarchiesi@2 705 if (!empty($library['files']['php'])) {
danielebarchiesi@2 706 foreach ($library['files']['php'] as $file => $array) {
danielebarchiesi@2 707 $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
danielebarchiesi@2 708 if (file_exists($file_path)) {
danielebarchiesi@2 709 require_once $file_path;
danielebarchiesi@2 710 $count++;
danielebarchiesi@2 711 }
danielebarchiesi@2 712 }
danielebarchiesi@2 713 }
danielebarchiesi@2 714
danielebarchiesi@2 715 return $count;
danielebarchiesi@2 716 }
danielebarchiesi@2 717
danielebarchiesi@2 718 /**
danielebarchiesi@2 719 * Gets the version information from an arbitrary library.
danielebarchiesi@2 720 *
danielebarchiesi@2 721 * @param $library
danielebarchiesi@2 722 * An associative array containing all information about the library.
danielebarchiesi@2 723 * @param $options
danielebarchiesi@2 724 * An associative array containing with the following keys:
danielebarchiesi@2 725 * - file: The filename to parse for the version, relative to the library
danielebarchiesi@2 726 * path. For example: 'docs/changelog.txt'.
danielebarchiesi@2 727 * - pattern: A string containing a regular expression (PCRE) to match the
danielebarchiesi@2 728 * library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'. Note that
danielebarchiesi@2 729 * the returned version is not the match of the entire pattern (i.e.
danielebarchiesi@2 730 * '@version 1.2.3' in the above example) but the match of the first
danielebarchiesi@2 731 * sub-pattern (i.e. '1.2.3' in the above example).
danielebarchiesi@2 732 * - lines: (optional) The maximum number of lines to search the pattern in.
danielebarchiesi@2 733 * Defaults to 20.
danielebarchiesi@2 734 * - cols: (optional) The maximum number of characters per line to take into
danielebarchiesi@2 735 * account. Defaults to 200. In case of minified or compressed files, this
danielebarchiesi@2 736 * prevents reading the entire file into memory.
danielebarchiesi@2 737 *
danielebarchiesi@2 738 * @return
danielebarchiesi@2 739 * A string containing the version of the library.
danielebarchiesi@2 740 *
danielebarchiesi@2 741 * @see libraries_get_path()
danielebarchiesi@2 742 */
danielebarchiesi@2 743 function libraries_get_version($library, $options) {
danielebarchiesi@2 744 // Provide defaults.
danielebarchiesi@2 745 $options += array(
danielebarchiesi@2 746 'file' => '',
danielebarchiesi@2 747 'pattern' => '',
danielebarchiesi@2 748 'lines' => 20,
danielebarchiesi@2 749 'cols' => 200,
danielebarchiesi@2 750 );
danielebarchiesi@2 751
danielebarchiesi@2 752 $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file'];
danielebarchiesi@2 753 if (empty($options['file']) || !file_exists($file)) {
danielebarchiesi@2 754 return;
danielebarchiesi@2 755 }
danielebarchiesi@2 756 $file = fopen($file, 'r');
danielebarchiesi@2 757 while ($options['lines'] && $line = fgets($file, $options['cols'])) {
danielebarchiesi@2 758 if (preg_match($options['pattern'], $line, $version)) {
danielebarchiesi@2 759 fclose($file);
danielebarchiesi@2 760 return $version[1];
danielebarchiesi@2 761 }
danielebarchiesi@2 762 $options['lines']--;
danielebarchiesi@2 763 }
danielebarchiesi@2 764 fclose($file);
danielebarchiesi@2 765 }