annotate sites/all/modules/ctools/includes/plugins.inc @ 11:b0ee71395280

deleted .DS_Store files
author danieleb <danielebarchiesi@me.com>
date Mon, 28 Oct 2013 16:12:13 +0000
parents ff03f76ab3fe
children
rev   line source
danielebarchiesi@0 1 <?php
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * @file
danielebarchiesi@0 5 *
danielebarchiesi@0 6 * Contains routines to organize and load plugins. It allows a special
danielebarchiesi@0 7 * variation of the hook system so that plugins can be kept in separate
danielebarchiesi@0 8 * .inc files, and can be either loaded all at once or loaded only when
danielebarchiesi@0 9 * necessary.
danielebarchiesi@0 10 */
danielebarchiesi@0 11
danielebarchiesi@0 12 /**
danielebarchiesi@0 13 * Get an array of information about modules that support an API.
danielebarchiesi@0 14 *
danielebarchiesi@0 15 * This will ask each module if they support the given API, and if they do
danielebarchiesi@0 16 * it will return an array of information about the modules that do.
danielebarchiesi@0 17 *
danielebarchiesi@0 18 * This function invokes hook_ctools_api. This invocation is statically
danielebarchiesi@0 19 * cached, so feel free to call it as often per page run as you like, it
danielebarchiesi@0 20 * will cost very little.
danielebarchiesi@0 21 *
danielebarchiesi@0 22 * This function can be used as an alternative to module_implements and can
danielebarchiesi@0 23 * thus be used to find a precise list of modules that not only support
danielebarchiesi@0 24 * a given hook (aka 'api') but also restrict to only modules that use
danielebarchiesi@0 25 * the given version. This will allow multiple modules moving at different
danielebarchiesi@0 26 * paces to still be able to work together and, in the event of a mismatch,
danielebarchiesi@0 27 * either fall back to older behaviors or simply cease loading, which is
danielebarchiesi@0 28 * still better than a crash.
danielebarchiesi@0 29 *
danielebarchiesi@0 30 * @param $owner
danielebarchiesi@0 31 * The name of the module that controls the API.
danielebarchiesi@0 32 * @param $api
danielebarchiesi@0 33 * The name of the api. The api name forms the file name:
danielebarchiesi@0 34 * $module.$api.inc
danielebarchiesi@0 35 * @param $minimum_version
danielebarchiesi@0 36 * The lowest version API that is compatible with this one. If a module
danielebarchiesi@0 37 * reports its API as older than this, its files will not be loaded. This
danielebarchiesi@0 38 * should never change during operation.
danielebarchiesi@0 39 * @param $current_version
danielebarchiesi@0 40 * The current version of the api. If a module reports its minimum API as
danielebarchiesi@0 41 * higher than this, its files will not be loaded. This should never change
danielebarchiesi@0 42 * during operation.
danielebarchiesi@0 43 *
danielebarchiesi@0 44 * @return
danielebarchiesi@0 45 * An array of API information, keyed by module. Each module's information will
danielebarchiesi@0 46 * contain:
danielebarchiesi@0 47 * - 'version': The version of the API required by the module. The module
danielebarchiesi@0 48 * should use the lowest number it can support so that the widest range
danielebarchiesi@0 49 * of supported versions can be used.
danielebarchiesi@0 50 * - 'path': If not provided, this will be the module's path. This is
danielebarchiesi@0 51 * where the module will store any subsidiary files. This differs from
danielebarchiesi@0 52 * plugin paths which are figured separately.
danielebarchiesi@0 53 *
danielebarchiesi@0 54 * APIs can request any other information to be placed here that they might
danielebarchiesi@0 55 * need. This should be in the documentation for that particular API.
danielebarchiesi@0 56 */
danielebarchiesi@0 57 function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version) {
danielebarchiesi@0 58 $cache = &drupal_static(__FUNCTION__, array());
danielebarchiesi@0 59 if (!isset($cache[$owner][$api])) {
danielebarchiesi@0 60 $cache[$owner][$api] = array();
danielebarchiesi@0 61
danielebarchiesi@0 62 $hook = ctools_plugin_api_get_hook($owner, $api);
danielebarchiesi@0 63
danielebarchiesi@0 64 foreach (module_implements($hook) as $module) {
danielebarchiesi@0 65 $function = $module . '_' . $hook;
danielebarchiesi@0 66 $info = $function($owner, $api);
danielebarchiesi@0 67 $version = NULL;
danielebarchiesi@0 68 // This is added to make hook_views_api() compatible with this, since
danielebarchiesi@0 69 // views used a different version key.
danielebarchiesi@0 70 if (isset($info['version'])) {
danielebarchiesi@0 71 $version = $info['version'];
danielebarchiesi@0 72 }
danielebarchiesi@0 73 else if (isset($info['api'])) {
danielebarchiesi@0 74 $version = $info['api'];
danielebarchiesi@0 75 }
danielebarchiesi@0 76
danielebarchiesi@0 77 if (!isset($version)) {
danielebarchiesi@0 78 continue;
danielebarchiesi@0 79 }
danielebarchiesi@0 80
danielebarchiesi@0 81 // Only process if version is between minimum and current, inclusive.
danielebarchiesi@0 82 if (version_compare($version, $minimum_version, '>=') && version_compare($version, $current_version, '<=')) {
danielebarchiesi@0 83 if (!isset($info['path'])) {
danielebarchiesi@0 84 $info['path'] = drupal_get_path('module', $module);
danielebarchiesi@0 85 }
danielebarchiesi@0 86 $cache[$owner][$api][$module] = $info;
danielebarchiesi@0 87 }
danielebarchiesi@0 88 }
danielebarchiesi@0 89
danielebarchiesi@0 90 // And allow themes to implement these as well.
danielebarchiesi@0 91 $themes = _ctools_list_themes();
danielebarchiesi@0 92 foreach ($themes as $name => $theme) {
danielebarchiesi@0 93 if (!empty($theme->info['api'][$owner][$api])) {
danielebarchiesi@0 94 $info = $theme->info['api'][$owner][$api];
danielebarchiesi@0 95 if (!isset($info['version'])) {
danielebarchiesi@0 96 continue;
danielebarchiesi@0 97 }
danielebarchiesi@0 98
danielebarchiesi@0 99 // Only process if version is between minimum and current, inclusive.
danielebarchiesi@0 100 if (version_compare($info['version'], $minimum_version, '>=') && version_compare($info['version'], $current_version, '<=')) {
danielebarchiesi@0 101 if (!isset($info['path'])) {
danielebarchiesi@0 102 $info['path'] = '';
danielebarchiesi@0 103 }
danielebarchiesi@0 104 // Because themes can't easily specify full path, we add it here
danielebarchiesi@0 105 // even though we do not for modules:
danielebarchiesi@0 106 $info['path'] = drupal_get_path('theme', $name) . '/' . $info['path'];
danielebarchiesi@0 107 $cache[$owner][$api][$name] = $info;
danielebarchiesi@0 108 }
danielebarchiesi@0 109 }
danielebarchiesi@0 110 }
danielebarchiesi@0 111
danielebarchiesi@0 112 // Allow other modules to hook in.
danielebarchiesi@0 113 drupal_alter($hook, $cache[$owner][$api]);
danielebarchiesi@0 114 }
danielebarchiesi@0 115
danielebarchiesi@0 116 return $cache[$owner][$api];
danielebarchiesi@0 117 }
danielebarchiesi@0 118
danielebarchiesi@0 119 /**
danielebarchiesi@0 120 * Load a group of API files.
danielebarchiesi@0 121 *
danielebarchiesi@0 122 * This will ask each module if they support the given API, and if they do
danielebarchiesi@0 123 * it will load the specified file name. The API and the file name
danielebarchiesi@0 124 * coincide by design.
danielebarchiesi@0 125 *
danielebarchiesi@0 126 * @param $owner
danielebarchiesi@0 127 * The name of the module that controls the API.
danielebarchiesi@0 128 * @param $api
danielebarchiesi@0 129 * The name of the api. The api name forms the file name:
danielebarchiesi@0 130 * $module.$api.inc, though this can be overridden by the module's response.
danielebarchiesi@0 131 * @param $minimum_version
danielebarchiesi@0 132 * The lowest version API that is compatible with this one. If a module
danielebarchiesi@0 133 * reports its API as older than this, its files will not be loaded. This
danielebarchiesi@0 134 * should never change during operation.
danielebarchiesi@0 135 * @param $current_version
danielebarchiesi@0 136 * The current version of the api. If a module reports its minimum API as
danielebarchiesi@0 137 * higher than this, its files will not be loaded. This should never change
danielebarchiesi@0 138 * during operation.
danielebarchiesi@0 139 *
danielebarchiesi@0 140 * @return
danielebarchiesi@0 141 * The API information, in case you need it.
danielebarchiesi@0 142 */
danielebarchiesi@0 143 function ctools_plugin_api_include($owner, $api, $minimum_version, $current_version) {
danielebarchiesi@0 144 static $already_done = array();
danielebarchiesi@0 145
danielebarchiesi@0 146 $info = ctools_plugin_api_info($owner, $api, $minimum_version, $current_version);
danielebarchiesi@0 147 foreach ($info as $module => $plugin_info) {
danielebarchiesi@0 148 if (!isset($already_done[$owner][$api][$module])) {
danielebarchiesi@0 149 if (isset($plugin_info["$api file"])) {
danielebarchiesi@0 150 $file = $plugin_info["$api file"];
danielebarchiesi@0 151 }
danielebarchiesi@0 152 else if (isset($plugin_info['file'])) {
danielebarchiesi@0 153 $file = $plugin_info['file'];
danielebarchiesi@0 154 }
danielebarchiesi@0 155 else {
danielebarchiesi@0 156 $file = "$module.$api.inc";
danielebarchiesi@0 157 }
danielebarchiesi@0 158
danielebarchiesi@0 159 if (file_exists(DRUPAL_ROOT . "/$plugin_info[path]/$file")) {
danielebarchiesi@0 160 require_once DRUPAL_ROOT . "/$plugin_info[path]/$file";
danielebarchiesi@0 161 }
danielebarchiesi@0 162 else if (file_exists(DRUPAL_ROOT . "/$file")) {
danielebarchiesi@0 163 require_once DRUPAL_ROOT . "/$file";
danielebarchiesi@0 164 }
danielebarchiesi@0 165 $already_done[$owner][$api][$module] = TRUE;
danielebarchiesi@0 166 }
danielebarchiesi@0 167 }
danielebarchiesi@0 168
danielebarchiesi@0 169 return $info;
danielebarchiesi@0 170 }
danielebarchiesi@0 171
danielebarchiesi@0 172 /**
danielebarchiesi@0 173 * Find out what hook to use to determine if modules support an API.
danielebarchiesi@0 174 *
danielebarchiesi@0 175 * By default, most APIs will use hook_ctools_plugin_api, but some modules
danielebarchiesi@0 176 * want sole ownership. This technique lets modules define what hook
danielebarchiesi@0 177 * to use.
danielebarchiesi@0 178 */
danielebarchiesi@0 179 function ctools_plugin_api_get_hook($owner, $api) {
danielebarchiesi@0 180 // Allow modules to use their own hook for this. The only easy way to do
danielebarchiesi@0 181 // this right now is with a magically named function.
danielebarchiesi@0 182 if (function_exists($function = $owner . '_' . $api . '_hook_name')) {
danielebarchiesi@0 183 $hook = $function();
danielebarchiesi@0 184 }
danielebarchiesi@0 185 else if (function_exists($function = $owner . '_ctools_plugin_api_hook_name')) {
danielebarchiesi@0 186 $hook = $function();
danielebarchiesi@0 187 }
danielebarchiesi@0 188
danielebarchiesi@0 189 // Do this last so that if the $function above failed to return, we have a
danielebarchiesi@0 190 // sane default.
danielebarchiesi@0 191 if (empty($hook)) {
danielebarchiesi@0 192 $hook = 'ctools_plugin_api';
danielebarchiesi@0 193 }
danielebarchiesi@0 194
danielebarchiesi@0 195 return $hook;
danielebarchiesi@0 196 }
danielebarchiesi@0 197
danielebarchiesi@0 198 /**
danielebarchiesi@0 199 * Fetch a group of plugins by name.
danielebarchiesi@0 200 *
danielebarchiesi@0 201 * @param $module
danielebarchiesi@0 202 * The name of the module that utilizes this plugin system. It will be
danielebarchiesi@0 203 * used to call hook_ctools_plugin_$plugin() to get more data about the plugin.
danielebarchiesi@0 204 * @param $type
danielebarchiesi@0 205 * The type identifier of the plugin.
danielebarchiesi@0 206 * @param $id
danielebarchiesi@0 207 * If specified, return only information about plugin with this identifier.
danielebarchiesi@0 208 * The system will do its utmost to load only plugins with this id.
danielebarchiesi@0 209 *
danielebarchiesi@0 210 * @return
danielebarchiesi@0 211 * An array of information arrays about the plugins received. The contents
danielebarchiesi@0 212 * of the array are specific to the plugin.
danielebarchiesi@0 213 */
danielebarchiesi@0 214 function ctools_get_plugins($module, $type, $id = NULL) {
danielebarchiesi@0 215 // Store local caches of plugins and plugin info so we don't have to do full
danielebarchiesi@0 216 // lookups everytime.
danielebarchiesi@0 217 $plugins = &drupal_static('ctools_plugins', array());
danielebarchiesi@0 218 $info = ctools_plugin_get_plugin_type_info();
danielebarchiesi@0 219
danielebarchiesi@0 220 // Bail out noisily if an invalid module/type combination is requested.
danielebarchiesi@0 221 if (!isset($info[$module][$type])) {
danielebarchiesi@0 222 watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
danielebarchiesi@0 223 return array();
danielebarchiesi@0 224 }
danielebarchiesi@0 225
danielebarchiesi@0 226 // Make sure our plugins array is populated.
danielebarchiesi@0 227 if (!isset($plugins[$module][$type])) {
danielebarchiesi@0 228 $plugins[$module][$type] = array();
danielebarchiesi@0 229 }
danielebarchiesi@0 230
danielebarchiesi@0 231 // Attempt to shortcut this whole piece of code if we already have
danielebarchiesi@0 232 // the requested plugin:
danielebarchiesi@0 233 if ($id && array_key_exists($id, $plugins[$module][$type])) {
danielebarchiesi@0 234 return $plugins[$module][$type][$id];
danielebarchiesi@0 235 }
danielebarchiesi@0 236
danielebarchiesi@0 237 // Store the status of plugin loading. If a module plugin type pair is true,
danielebarchiesi@0 238 // then it is fully loaded and no searching or setup needs to be done.
danielebarchiesi@0 239 $setup = &drupal_static('ctools_plugin_setup', array());
danielebarchiesi@0 240
danielebarchiesi@0 241 // We assume we don't need to build a cache.
danielebarchiesi@0 242 $build_cache = FALSE;
danielebarchiesi@0 243
danielebarchiesi@0 244 // If the plugin info says this can be cached, check cache first.
danielebarchiesi@0 245 if ($info[$module][$type]['cache'] && empty($setup[$module][$type])) {
danielebarchiesi@0 246 $cache = cache_get("plugins:$module:$type", $info[$module][$type]['cache table']);
danielebarchiesi@0 247
danielebarchiesi@0 248 if (!empty($cache->data)) {
danielebarchiesi@0 249 // Cache load succeeded so use the cached plugin list.
danielebarchiesi@0 250 $plugins[$module][$type] = $cache->data;
danielebarchiesi@0 251 // Set $setup to true so we know things where loaded.
danielebarchiesi@0 252 $setup[$module][$type] = TRUE;
danielebarchiesi@0 253 }
danielebarchiesi@0 254 else {
danielebarchiesi@0 255 // Cache load failed so store that we need to build and write the cache.
danielebarchiesi@0 256 $build_cache = TRUE;
danielebarchiesi@0 257 }
danielebarchiesi@0 258 }
danielebarchiesi@0 259
danielebarchiesi@0 260 // Always load all hooks if we need them. Note we only need them now if the
danielebarchiesi@0 261 // plugin asks for them. We can assume that if we have plugins we've already
danielebarchiesi@0 262 // called the global hook.
danielebarchiesi@0 263 if (!empty($info[$module][$type]['use hooks']) && empty($plugins[$module][$type])) {
danielebarchiesi@0 264 $plugins[$module][$type] = ctools_plugin_load_hooks($info[$module][$type]);
danielebarchiesi@0 265 }
danielebarchiesi@0 266
danielebarchiesi@0 267 // Then see if we should load all files. We only do this if we
danielebarchiesi@0 268 // want a list of all plugins or there was a cache miss.
danielebarchiesi@0 269 if (empty($setup[$module][$type]) && ($build_cache || !$id)) {
danielebarchiesi@0 270 $setup[$module][$type] = TRUE;
danielebarchiesi@0 271 $plugins[$module][$type] = array_merge($plugins[$module][$type], ctools_plugin_load_includes($info[$module][$type]));
danielebarchiesi@0 272 // If the plugin can have child plugins, and we're loading all plugins,
danielebarchiesi@0 273 // go through the list of plugins we have and find child plugins.
danielebarchiesi@0 274 if (!$id && !empty($info[$module][$type]['child plugins'])) {
danielebarchiesi@0 275 // If a plugin supports children, go through each plugin and ask.
danielebarchiesi@0 276 $temp = array();
danielebarchiesi@0 277 foreach ($plugins[$module][$type] as $name => $plugin) {
danielebarchiesi@0 278 // The strpos ensures that we don't try to find children for plugins
danielebarchiesi@0 279 // that are already children.
danielebarchiesi@0 280 if (!empty($plugin['get children']) && function_exists($plugin['get children']) && strpos($name, ':') === FALSE) {
danielebarchiesi@0 281 $temp = array_merge($plugin['get children']($plugin, $name), $temp);
danielebarchiesi@0 282 }
danielebarchiesi@0 283 else {
danielebarchiesi@0 284 $temp[$name] = $plugin;
danielebarchiesi@0 285 }
danielebarchiesi@0 286 }
danielebarchiesi@0 287 $plugins[$module][$type] = $temp;
danielebarchiesi@0 288 }
danielebarchiesi@0 289 }
danielebarchiesi@0 290
danielebarchiesi@0 291
danielebarchiesi@0 292 // If we were told earlier that this is cacheable and the cache was
danielebarchiesi@0 293 // empty, give something back.
danielebarchiesi@0 294 if ($build_cache) {
danielebarchiesi@0 295 cache_set("plugins:$module:$type", $plugins[$module][$type], $info[$module][$type]['cache table']);
danielebarchiesi@0 296 }
danielebarchiesi@0 297
danielebarchiesi@0 298 // If no id was requested, we are finished here:
danielebarchiesi@0 299 if (!$id) {
danielebarchiesi@0 300 // Use array_filter because looking for unknown plugins could cause NULL
danielebarchiesi@0 301 // entries to appear in the list later.
danielebarchiesi@0 302 return array_filter($plugins[$module][$type]);
danielebarchiesi@0 303 }
danielebarchiesi@0 304
danielebarchiesi@0 305 // Check to see if we need to look for the file
danielebarchiesi@0 306 if (!array_key_exists($id, $plugins[$module][$type])) {
danielebarchiesi@0 307 // If we can have child plugins, check to see if the plugin name is in the
danielebarchiesi@0 308 // format of parent:child and break it up if it is.
danielebarchiesi@0 309 if (!empty($info[$module][$type]['child plugins']) && strpos($id, ':') !== FALSE) {
danielebarchiesi@0 310 list($parent, $child) = explode(':', $id, 2);
danielebarchiesi@0 311 }
danielebarchiesi@0 312 else {
danielebarchiesi@0 313 $parent = $id;
danielebarchiesi@0 314 }
danielebarchiesi@0 315
danielebarchiesi@0 316 if (!array_key_exists($parent, $plugins[$module][$type])) {
danielebarchiesi@0 317 $result = ctools_plugin_load_includes($info[$module][$type], $parent);
danielebarchiesi@0 318 // Set to either what was returned or NULL.
danielebarchiesi@0 319 $plugins[$module][$type][$parent] = isset($result[$parent]) ? $result[$parent] : NULL;
danielebarchiesi@0 320 }
danielebarchiesi@0 321
danielebarchiesi@0 322 // If we are looking for a child, and have the parent, ask the parent for the child.
danielebarchiesi@0 323 if (!empty($child) && !empty($plugins[$module][$type][$parent]) && function_exists($plugins[$module][$type][$parent]['get child'])) {
danielebarchiesi@0 324 $plugins[$module][$type][$id] = $plugins[$module][$type][$parent]['get child']($plugins[$module][$type][$parent], $parent, $child);
danielebarchiesi@0 325 }
danielebarchiesi@0 326 }
danielebarchiesi@0 327
danielebarchiesi@0 328 // At this point we should either have the plugin, or a NULL.
danielebarchiesi@0 329 return $plugins[$module][$type][$id];
danielebarchiesi@0 330 }
danielebarchiesi@0 331
danielebarchiesi@0 332 /**
danielebarchiesi@0 333 * Return the full list of plugin type info for all plugin types registered in
danielebarchiesi@0 334 * the current system.
danielebarchiesi@0 335 *
danielebarchiesi@0 336 * This function manages its own cache getting/setting, and should always be
danielebarchiesi@0 337 * used as the way to initially populate the list of plugin types. Make sure you
danielebarchiesi@0 338 * call this function to properly populate the ctools_plugin_type_info static
danielebarchiesi@0 339 * variable.
danielebarchiesi@0 340 *
danielebarchiesi@0 341 * @return array
danielebarchiesi@0 342 * A multilevel array of plugin type info, the outer array keyed on module
danielebarchiesi@0 343 * name and each inner array keyed on plugin type name.
danielebarchiesi@0 344 */
danielebarchiesi@0 345 function ctools_plugin_get_plugin_type_info($flush = FALSE) {
danielebarchiesi@0 346 $info_loaded = &drupal_static('ctools_plugin_type_info_loaded', FALSE);
danielebarchiesi@0 347 $all_type_info = &drupal_static('ctools_plugin_type_info', array());
danielebarchiesi@0 348
danielebarchiesi@0 349 // Only trigger info loading once.
danielebarchiesi@0 350 if ($info_loaded && !$flush) {
danielebarchiesi@0 351 return $all_type_info;
danielebarchiesi@0 352 }
danielebarchiesi@0 353 $info_loaded = TRUE;
danielebarchiesi@0 354
danielebarchiesi@0 355 $cache = cache_get('ctools_plugin_type_info');
danielebarchiesi@0 356 if (!empty($cache->data) && !$flush) {
danielebarchiesi@0 357 // Plugin type info cache is warm, use it.
danielebarchiesi@0 358 $all_type_info = $cache->data;
danielebarchiesi@0 359 }
danielebarchiesi@0 360 else {
danielebarchiesi@0 361 // Cache expired, refill it.
danielebarchiesi@0 362 foreach (module_implements('ctools_plugin_type') as $module) {
danielebarchiesi@0 363 $module_infos = array();
danielebarchiesi@0 364 $function = $module . '_ctools_plugin_type';
danielebarchiesi@0 365 $module_infos = $function();
danielebarchiesi@0 366
danielebarchiesi@0 367 foreach ($module_infos as $plugin_type_name => $plugin_type_info) {
danielebarchiesi@0 368 // Apply defaults. Array addition will not overwrite pre-existing keys.
danielebarchiesi@0 369 $plugin_type_info += array(
danielebarchiesi@0 370 'module' => $module,
danielebarchiesi@0 371 'type' => $plugin_type_name,
danielebarchiesi@0 372 'cache' => FALSE,
danielebarchiesi@0 373 'cache table' => 'cache',
danielebarchiesi@0 374 'classes' => array(),
danielebarchiesi@0 375 'use hooks' => FALSE,
danielebarchiesi@0 376 'defaults' => array(),
danielebarchiesi@0 377 'process' => '',
danielebarchiesi@0 378 'alterable' => TRUE,
danielebarchiesi@0 379 'extension' => 'inc',
danielebarchiesi@0 380 'info file' => FALSE,
danielebarchiesi@0 381 'hook' => $module . '_' . $plugin_type_name,
danielebarchiesi@0 382 'load themes' => FALSE,
danielebarchiesi@0 383 );
danielebarchiesi@0 384 $all_type_info[$module][$plugin_type_name] = $plugin_type_info;
danielebarchiesi@0 385 }
danielebarchiesi@0 386 }
danielebarchiesi@0 387 cache_set('ctools_plugin_type_info', $all_type_info);
danielebarchiesi@0 388 }
danielebarchiesi@0 389
danielebarchiesi@0 390 return $all_type_info;
danielebarchiesi@0 391 }
danielebarchiesi@0 392
danielebarchiesi@0 393 /**
danielebarchiesi@0 394 * Reset all static caches that affect the result of ctools_get_plugins().
danielebarchiesi@0 395 */
danielebarchiesi@0 396 function ctools_get_plugins_reset() {
danielebarchiesi@0 397 drupal_static_reset('ctools_plugins');
danielebarchiesi@0 398 drupal_static_reset('ctools_plugin_setup');
danielebarchiesi@0 399 drupal_static_reset('ctools_plugin_load_includes');
danielebarchiesi@0 400 drupal_static_reset('ctools_plugin_api_info');
danielebarchiesi@0 401 }
danielebarchiesi@0 402
danielebarchiesi@0 403 /**
danielebarchiesi@0 404 * Load plugins from a directory.
danielebarchiesi@0 405 *
danielebarchiesi@0 406 * @param $info
danielebarchiesi@0 407 * The plugin info as returned by ctools_plugin_get_info()
danielebarchiesi@0 408 * @param $file
danielebarchiesi@0 409 * The file to load if we're looking for just one particular plugin.
danielebarchiesi@0 410 *
danielebarchiesi@0 411 * @return
danielebarchiesi@0 412 * An array of information created for this plugin.
danielebarchiesi@0 413 */
danielebarchiesi@0 414 function ctools_plugin_load_includes($info, $filename = NULL) {
danielebarchiesi@0 415 // Keep a static array so we don't hit file_scan_directory more than necessary.
danielebarchiesi@0 416 $all_files = &drupal_static(__FUNCTION__, array());
danielebarchiesi@0 417
danielebarchiesi@0 418 // store static of plugin arrays for reference because they can't be reincluded.
danielebarchiesi@0 419 static $plugin_arrays = array();
danielebarchiesi@0 420
danielebarchiesi@0 421 // If we're being asked for all plugins of a type, skip any caching
danielebarchiesi@0 422 // we may have done because this is an admin task and it's ok to
danielebarchiesi@0 423 // spend the extra time.
danielebarchiesi@0 424 if (!isset($filename)) {
danielebarchiesi@0 425 $all_files[$info['module']][$info['type']] = NULL;
danielebarchiesi@0 426 }
danielebarchiesi@0 427
danielebarchiesi@0 428 if (!isset($all_files[$info['module']][$info['type']])) {
danielebarchiesi@0 429 // If a filename was set, we will try to load our list of files from
danielebarchiesi@0 430 // cache. This is considered normal operation and we try to reduce
danielebarchiesi@0 431 // the time spent finding files.
danielebarchiesi@0 432 if (isset($filename)) {
danielebarchiesi@0 433 $cache = cache_get("ctools_plugin_files:$info[module]:$info[type]");
danielebarchiesi@0 434 if ($cache) {
danielebarchiesi@0 435 $all_files[$info['module']][$info['type']] = $cache->data;
danielebarchiesi@0 436 }
danielebarchiesi@0 437 }
danielebarchiesi@0 438
danielebarchiesi@0 439 if (!isset($all_files[$info['module']][$info['type']])) {
danielebarchiesi@0 440 $all_files[$info['module']][$info['type']] = array();
danielebarchiesi@0 441 // Load all our plugins.
danielebarchiesi@0 442 $directories = ctools_plugin_get_directories($info);
danielebarchiesi@0 443 $extension = (empty($info['info file']) || ($info['extension'] != 'inc')) ? $info['extension'] : 'info';
danielebarchiesi@0 444
danielebarchiesi@0 445 foreach ($directories as $module => $path) {
danielebarchiesi@0 446 $all_files[$info['module']][$info['type']][$module] = file_scan_directory($path, '/\.' . $extension . '$/', array('key' => 'name'));
danielebarchiesi@0 447 }
danielebarchiesi@0 448
danielebarchiesi@0 449 cache_set("ctools_plugin_files:$info[module]:$info[type]", $all_files[$info['module']][$info['type']]);
danielebarchiesi@0 450 }
danielebarchiesi@0 451 }
danielebarchiesi@0 452 $file_list = $all_files[$info['module']][$info['type']];
danielebarchiesi@0 453 $plugins = array();
danielebarchiesi@0 454
danielebarchiesi@0 455 // Iterate through all the plugin .inc files, load them and process the hook
danielebarchiesi@0 456 // that should now be available.
danielebarchiesi@0 457 foreach (array_filter($file_list) as $module => $files) {
danielebarchiesi@0 458 if ($filename) {
danielebarchiesi@0 459 $files = isset($files[$filename]) ? array($filename => $files[$filename]) : array();
danielebarchiesi@0 460 }
danielebarchiesi@0 461 foreach ($files as $file) {
danielebarchiesi@0 462 if (!empty($info['info file'])) {
danielebarchiesi@0 463 // Parse a .info file
danielebarchiesi@0 464 $result = ctools_plugin_process_info($info, $module, $file);
danielebarchiesi@0 465 }
danielebarchiesi@0 466 else {
danielebarchiesi@0 467 // Parse a hook.
danielebarchiesi@0 468 $plugin = NULL; // ensure that we don't have something leftover from earlier.
danielebarchiesi@0 469
danielebarchiesi@0 470 if (isset($plugin_arrays[$file->uri])) {
danielebarchiesi@0 471 $identifier = $plugin_arrays[$file->uri];
danielebarchiesi@0 472 }
danielebarchiesi@0 473 else {
danielebarchiesi@0 474
danielebarchiesi@0 475 require_once DRUPAL_ROOT . '/' . $file->uri;
danielebarchiesi@0 476 // .inc files have a special format for the hook identifier.
danielebarchiesi@0 477 // For example, 'foo.inc' in the module 'mogul' using the plugin
danielebarchiesi@0 478 // whose hook is named 'borg_type' should have a function named (deep breath)
danielebarchiesi@0 479 // mogul_foo_borg_type()
danielebarchiesi@0 480
danielebarchiesi@0 481 // If, however, the .inc file set the quasi-global $plugin array, we
danielebarchiesi@0 482 // can use that and not even call a function. Set the $identifier
danielebarchiesi@0 483 // appropriately and ctools_plugin_process() will handle it.
danielebarchiesi@0 484 if (isset($plugin)) {
danielebarchiesi@0 485 $plugin_arrays[$file->uri] = $plugin;
danielebarchiesi@0 486 $identifier = $plugin;
danielebarchiesi@0 487 }
danielebarchiesi@0 488 else {
danielebarchiesi@0 489 $identifier = $module . '_' . $file->name;
danielebarchiesi@0 490 }
danielebarchiesi@0 491 }
danielebarchiesi@0 492
danielebarchiesi@0 493 $result = ctools_plugin_process($info, $module, $identifier, dirname($file->uri), basename($file->uri), $file->name);
danielebarchiesi@0 494 }
danielebarchiesi@0 495 if (is_array($result)) {
danielebarchiesi@0 496 $plugins = array_merge($plugins, $result);
danielebarchiesi@0 497 }
danielebarchiesi@0 498 }
danielebarchiesi@0 499 }
danielebarchiesi@0 500 return $plugins;
danielebarchiesi@0 501 }
danielebarchiesi@0 502
danielebarchiesi@0 503 /**
danielebarchiesi@0 504 * Get a list of directories to search for plugins of the given type.
danielebarchiesi@0 505 *
danielebarchiesi@0 506 * This utilizes hook_ctools_plugin_directory() to determine a complete list of
danielebarchiesi@0 507 * directories. Only modules that implement this hook and return a string
danielebarchiesi@0 508 * value will have their directories included.
danielebarchiesi@0 509 *
danielebarchiesi@0 510 * @param $info
danielebarchiesi@0 511 * The $info array for the plugin as returned by ctools_plugin_get_info().
danielebarchiesi@0 512 *
danielebarchiesi@0 513 * @return array $directories
danielebarchiesi@0 514 * An array of directories to search.
danielebarchiesi@0 515 */
danielebarchiesi@0 516 function ctools_plugin_get_directories($info) {
danielebarchiesi@0 517 $directories = array();
danielebarchiesi@0 518
danielebarchiesi@0 519 foreach (module_implements('ctools_plugin_directory') as $module) {
danielebarchiesi@0 520 $function = $module . '_ctools_plugin_directory';
danielebarchiesi@0 521 $result = $function($info['module'], $info['type']);
danielebarchiesi@0 522 if ($result && is_string($result)) {
danielebarchiesi@0 523 $directories[$module] = drupal_get_path('module', $module) . '/' . $result;
danielebarchiesi@0 524 }
danielebarchiesi@0 525 }
danielebarchiesi@0 526
danielebarchiesi@0 527 if (!empty($info['load themes'])) {
danielebarchiesi@0 528 $themes = _ctools_list_themes();
danielebarchiesi@0 529 foreach ($themes as $name => $theme) {
danielebarchiesi@0 530 if (!empty($theme->info['plugins'][$info['module']][$info['type']])) {
danielebarchiesi@0 531 $directories[$name] = drupal_get_path('theme', $name) . '/' . $theme->info['plugins'][$info['module']][$info['type']];
danielebarchiesi@0 532 }
danielebarchiesi@0 533 }
danielebarchiesi@0 534 }
danielebarchiesi@0 535 return $directories;
danielebarchiesi@0 536 }
danielebarchiesi@0 537
danielebarchiesi@0 538 /**
danielebarchiesi@0 539 * Helper function to build a ctools-friendly list of themes capable of
danielebarchiesi@0 540 * providing plugins.
danielebarchiesi@0 541 *
danielebarchiesi@0 542 * @return array $themes
danielebarchiesi@0 543 * A list of themes that can act as plugin providers, sorted parent-first with
danielebarchiesi@0 544 * the active theme placed last.
danielebarchiesi@0 545 */
danielebarchiesi@0 546 function _ctools_list_themes() {
danielebarchiesi@0 547 static $themes;
danielebarchiesi@0 548 if (is_null($themes)) {
danielebarchiesi@0 549 $current = variable_get('theme_default', FALSE);
danielebarchiesi@0 550 $themes = $active = array();
danielebarchiesi@0 551 $all_themes = list_themes();
danielebarchiesi@0 552 foreach ($all_themes as $name => $theme) {
danielebarchiesi@0 553 // Only search from active themes
danielebarchiesi@0 554 if (empty($theme->status) && $theme->name != $current) {
danielebarchiesi@0 555 continue;
danielebarchiesi@0 556 }
danielebarchiesi@0 557 $active[$name] = $theme;
danielebarchiesi@0 558 // Prior to drupal 6.14, $theme->base_themes does not exist. Build it.
danielebarchiesi@0 559 if (!isset($theme->base_themes) && !empty($theme->base_theme)) {
danielebarchiesi@0 560 $active[$name]->base_themes = ctools_find_base_themes($all_themes, $name);
danielebarchiesi@0 561 }
danielebarchiesi@0 562 }
danielebarchiesi@0 563
danielebarchiesi@0 564 // Construct a parent-first list of all themes
danielebarchiesi@0 565 foreach ($active as $name => $theme) {
danielebarchiesi@0 566 $base_themes = isset($theme->base_themes) ? $theme->base_themes : array();
danielebarchiesi@0 567 $themes = array_merge($themes, $base_themes, array($name => $theme->info['name']));
danielebarchiesi@0 568 }
danielebarchiesi@0 569 // Put the actual theme info objects into the array
danielebarchiesi@0 570 foreach (array_keys($themes) as $name) {
danielebarchiesi@0 571 if (isset($all_themes[$name])) {
danielebarchiesi@0 572 $themes[$name] = $all_themes[$name];
danielebarchiesi@0 573 }
danielebarchiesi@0 574 }
danielebarchiesi@0 575
danielebarchiesi@0 576 // Make sure the current default theme always gets the last word
danielebarchiesi@0 577 if ($current_key = array_search($current, array_keys($themes))) {
danielebarchiesi@0 578 $themes += array_splice($themes, $current_key, 1);
danielebarchiesi@0 579 }
danielebarchiesi@0 580 }
danielebarchiesi@0 581 return $themes;
danielebarchiesi@0 582 }
danielebarchiesi@0 583
danielebarchiesi@0 584
danielebarchiesi@0 585 /**
danielebarchiesi@0 586 * Find all the base themes for the specified theme.
danielebarchiesi@0 587 *
danielebarchiesi@0 588 * Themes can inherit templates and function implementations from earlier themes.
danielebarchiesi@0 589 *
danielebarchiesi@0 590 * NOTE: this is a verbatim copy of system_find_base_themes(), which was not
danielebarchiesi@0 591 * implemented until 6.14. It is included here only as a fallback for outdated
danielebarchiesi@0 592 * versions of drupal core.
danielebarchiesi@0 593 *
danielebarchiesi@0 594 * @param $themes
danielebarchiesi@0 595 * An array of available themes.
danielebarchiesi@0 596 * @param $key
danielebarchiesi@0 597 * The name of the theme whose base we are looking for.
danielebarchiesi@0 598 * @param $used_keys
danielebarchiesi@0 599 * A recursion parameter preventing endless loops.
danielebarchiesi@0 600 * @return
danielebarchiesi@0 601 * Returns an array of all of the theme's ancestors; the first element's value
danielebarchiesi@0 602 * will be NULL if an error occurred.
danielebarchiesi@0 603 */
danielebarchiesi@0 604 function ctools_find_base_themes($themes, $key, $used_keys = array()) {
danielebarchiesi@0 605 $base_key = $themes[$key]->info['base theme'];
danielebarchiesi@0 606 // Does the base theme exist?
danielebarchiesi@0 607 if (!isset($themes[$base_key])) {
danielebarchiesi@0 608 return array($base_key => NULL);
danielebarchiesi@0 609 }
danielebarchiesi@0 610
danielebarchiesi@0 611 $current_base_theme = array($base_key => $themes[$base_key]->info['name']);
danielebarchiesi@0 612
danielebarchiesi@0 613 // Is the base theme itself a child of another theme?
danielebarchiesi@0 614 if (isset($themes[$base_key]->info['base theme'])) {
danielebarchiesi@0 615 // Do we already know the base themes of this theme?
danielebarchiesi@0 616 if (isset($themes[$base_key]->base_themes)) {
danielebarchiesi@0 617 return $themes[$base_key]->base_themes + $current_base_theme;
danielebarchiesi@0 618 }
danielebarchiesi@0 619 // Prevent loops.
danielebarchiesi@0 620 if (!empty($used_keys[$base_key])) {
danielebarchiesi@0 621 return array($base_key => NULL);
danielebarchiesi@0 622 }
danielebarchiesi@0 623 $used_keys[$base_key] = TRUE;
danielebarchiesi@0 624 return ctools_find_base_themes($themes, $base_key, $used_keys) + $current_base_theme;
danielebarchiesi@0 625 }
danielebarchiesi@0 626 // If we get here, then this is our parent theme.
danielebarchiesi@0 627 return $current_base_theme;
danielebarchiesi@0 628 }
danielebarchiesi@0 629
danielebarchiesi@0 630
danielebarchiesi@0 631 /**
danielebarchiesi@0 632 * Load plugin info for the provided hook; this is handled separately from
danielebarchiesi@0 633 * plugins from files.
danielebarchiesi@0 634 *
danielebarchiesi@0 635 * @param $info
danielebarchiesi@0 636 * The info array about the plugin as created by ctools_plugin_get_info()
danielebarchiesi@0 637 *
danielebarchiesi@0 638 * @return
danielebarchiesi@0 639 * An array of info supplied by any hook implementations.
danielebarchiesi@0 640 */
danielebarchiesi@0 641 function ctools_plugin_load_hooks($info) {
danielebarchiesi@0 642 $hooks = array();
danielebarchiesi@0 643 foreach (module_implements($info['hook']) as $module) {
danielebarchiesi@0 644 $result = ctools_plugin_process($info, $module, $module, drupal_get_path('module', $module));
danielebarchiesi@0 645 if (is_array($result)) {
danielebarchiesi@0 646 $hooks = array_merge($hooks, $result);
danielebarchiesi@0 647 }
danielebarchiesi@0 648 }
danielebarchiesi@0 649 return $hooks;
danielebarchiesi@0 650 }
danielebarchiesi@0 651
danielebarchiesi@0 652 /**
danielebarchiesi@0 653 * Process a single hook implementation of a ctools plugin.
danielebarchiesi@0 654 *
danielebarchiesi@0 655 * @param $info
danielebarchiesi@0 656 * The $info array about the plugin as returned by ctools_plugin_get_info()
danielebarchiesi@0 657 * @param $module
danielebarchiesi@0 658 * The module that implements the plugin being processed.
danielebarchiesi@0 659 * @param $identifier
danielebarchiesi@0 660 * The plugin identifier, which is used to create the name of the hook
danielebarchiesi@0 661 * function being called.
danielebarchiesi@0 662 * @param $path
danielebarchiesi@0 663 * The path where files utilized by this plugin will be found.
danielebarchiesi@0 664 * @param $file
danielebarchiesi@0 665 * The file that was loaded for this plugin, if it exists.
danielebarchiesi@0 666 * @param $base
danielebarchiesi@0 667 * The base plugin name to use. If a file was loaded for the plugin, this
danielebarchiesi@0 668 * is the plugin to assume must be present. This is used to automatically
danielebarchiesi@0 669 * translate the array to make the syntax more friendly to plugin
danielebarchiesi@0 670 * implementors.
danielebarchiesi@0 671 */
danielebarchiesi@0 672 function ctools_plugin_process($info, $module, $identifier, $path, $file = NULL, $base = NULL) {
danielebarchiesi@0 673 if (is_array($identifier)) {
danielebarchiesi@0 674 $result = $identifier;
danielebarchiesi@0 675 }
danielebarchiesi@0 676 else {
danielebarchiesi@0 677 $function = $identifier . '_' . $info['hook'];
danielebarchiesi@0 678 if (!function_exists($function)) {
danielebarchiesi@0 679 return NULL;
danielebarchiesi@0 680 }
danielebarchiesi@0 681 $result = $function();
danielebarchiesi@0 682 if (!isset($result) || !is_array($result)) {
danielebarchiesi@0 683 return NULL;
danielebarchiesi@0 684 }
danielebarchiesi@0 685 }
danielebarchiesi@0 686
danielebarchiesi@0 687 // Automatically convert to the proper format that lets plugin implementations
danielebarchiesi@0 688 // not nest arrays as deeply as they used to, but still support the older
danielebarchiesi@0 689 // format where they do:
danielebarchiesi@0 690 if ($base && (!isset($result[$base]) || !is_array($result[$base]))) {
danielebarchiesi@0 691 $result = array($base => $result);
danielebarchiesi@0 692 }
danielebarchiesi@0 693
danielebarchiesi@0 694 return _ctools_process_data($result, $info, $module, $path, $file);
danielebarchiesi@0 695 }
danielebarchiesi@0 696
danielebarchiesi@0 697 /**
danielebarchiesi@0 698 * Fill in default values and run hooks for data loaded for one or
danielebarchiesi@0 699 * more plugins.
danielebarchiesi@0 700 */
danielebarchiesi@0 701 function _ctools_process_data($result, $plugin_type_info, $module, $path, $file) {
danielebarchiesi@0 702 // Fill in global defaults.
danielebarchiesi@0 703 foreach ($result as $name => $plugin) {
danielebarchiesi@0 704 $result[$name] += array(
danielebarchiesi@0 705 'module' => $module,
danielebarchiesi@0 706 'name' => $name,
danielebarchiesi@0 707 'path' => $path,
danielebarchiesi@0 708 'file' => $file,
danielebarchiesi@0 709 'plugin module' => $plugin_type_info['module'],
danielebarchiesi@0 710 'plugin type' => $plugin_type_info['type'],
danielebarchiesi@0 711 );
danielebarchiesi@0 712
danielebarchiesi@0 713 // Fill in plugin-specific defaults, if they exist.
danielebarchiesi@0 714 if (!empty($plugin_type_info['defaults'])) {
danielebarchiesi@0 715 if (is_array($plugin_type_info['defaults'])) {
danielebarchiesi@0 716 $result[$name] += $plugin_type_info['defaults'];
danielebarchiesi@0 717 }
danielebarchiesi@0 718 }
danielebarchiesi@0 719
danielebarchiesi@0 720 // Allow the plugin to be altered before processing.
danielebarchiesi@0 721 if (!empty($plugin_type_info['alterable']) && $plugin_type_info['alterable']) {
danielebarchiesi@0 722 drupal_alter('ctools_plugin_pre', $result[$name], $plugin_type_info);
danielebarchiesi@0 723 }
danielebarchiesi@0 724
danielebarchiesi@0 725 // Allow the plugin owner to do additional processing.
danielebarchiesi@0 726 if (!empty($plugin_type_info['process']) && $function = ctools_plugin_get_function($plugin_type_info, 'process')) {
danielebarchiesi@0 727 $function($result[$name], $plugin_type_info);
danielebarchiesi@0 728 }
danielebarchiesi@0 729
danielebarchiesi@0 730 // Allow the plugin to be altered after processing.
danielebarchiesi@0 731 if (!empty($plugin_type_info['alterable']) && $plugin_type_info['alterable']) {
danielebarchiesi@0 732 drupal_alter('ctools_plugin_post', $result[$name], $plugin_type_info);
danielebarchiesi@0 733 }
danielebarchiesi@0 734 }
danielebarchiesi@0 735 return $result;
danielebarchiesi@0 736 }
danielebarchiesi@0 737
danielebarchiesi@0 738
danielebarchiesi@0 739 /**
danielebarchiesi@0 740 * Process an info file for plugin information, rather than a hook.
danielebarchiesi@0 741 */
danielebarchiesi@0 742 function ctools_plugin_process_info($info, $module, $file) {
danielebarchiesi@0 743 $result = drupal_parse_info_file($file->uri);
danielebarchiesi@0 744 if ($result) {
danielebarchiesi@0 745 $result = array($file->name => $result);
danielebarchiesi@0 746 return _ctools_process_data($result, $info, $module, dirname($file->uri), basename($file->uri));
danielebarchiesi@0 747 }
danielebarchiesi@0 748 }
danielebarchiesi@0 749
danielebarchiesi@0 750 /**
danielebarchiesi@0 751 * Ask a module for info about a particular plugin type.
danielebarchiesi@0 752 */
danielebarchiesi@0 753 function ctools_plugin_get_info($module, $type) {
danielebarchiesi@0 754 $all_info = ctools_plugin_get_plugin_type_info();
danielebarchiesi@0 755 return isset($all_info[$module][$type]) ? $all_info[$module][$type] : array();
danielebarchiesi@0 756 }
danielebarchiesi@0 757
danielebarchiesi@0 758 /**
danielebarchiesi@0 759 * Get a function from a plugin, if it exists. If the plugin is not already
danielebarchiesi@0 760 * loaded, try ctools_plugin_load_function() instead.
danielebarchiesi@0 761 *
danielebarchiesi@0 762 * @param $plugin_definition
danielebarchiesi@0 763 * The loaded plugin type.
danielebarchiesi@0 764 * @param $function_name
danielebarchiesi@0 765 * The identifier of the function. For example, 'settings form'.
danielebarchiesi@0 766 *
danielebarchiesi@0 767 * @return
danielebarchiesi@0 768 * The actual name of the function to call, or NULL if the function
danielebarchiesi@0 769 * does not exist.
danielebarchiesi@0 770 */
danielebarchiesi@0 771 function ctools_plugin_get_function($plugin_definition, $function_name) {
danielebarchiesi@0 772 // If cached the .inc file may not have been loaded. require_once is quite safe
danielebarchiesi@0 773 // and fast so it's okay to keep calling it.
danielebarchiesi@0 774 if (isset($plugin_definition['file'])) {
danielebarchiesi@0 775 // Plugins that are loaded from info files have the info file as
danielebarchiesi@0 776 // $plugin['file']. Don't try to run those.
danielebarchiesi@0 777 $info = ctools_plugin_get_info($plugin_definition['plugin module'], $plugin_definition['plugin type']);
danielebarchiesi@0 778 if (empty($info['info file'])) {
danielebarchiesi@0 779 require_once DRUPAL_ROOT . '/' . $plugin_definition['path'] . '/' . $plugin_definition['file'];
danielebarchiesi@0 780 }
danielebarchiesi@0 781 }
danielebarchiesi@0 782
danielebarchiesi@0 783 if (!isset($plugin_definition[$function_name])) {
danielebarchiesi@0 784 return;
danielebarchiesi@0 785 }
danielebarchiesi@0 786
danielebarchiesi@0 787 if (is_array($plugin_definition[$function_name]) && isset($plugin_definition[$function_name]['function'])) {
danielebarchiesi@0 788 $function = $plugin_definition[$function_name]['function'];
danielebarchiesi@0 789 if (isset($plugin_definition[$function_name]['file'])) {
danielebarchiesi@0 790 $file = $plugin_definition[$function_name]['file'];
danielebarchiesi@0 791 if (isset($plugin_definition[$function_name]['path'])) {
danielebarchiesi@0 792 $file = $plugin_definition[$function_name]['path'] . '/' . $file;
danielebarchiesi@0 793 }
danielebarchiesi@0 794 require_once DRUPAL_ROOT . '/' . $file;
danielebarchiesi@0 795 }
danielebarchiesi@0 796 }
danielebarchiesi@0 797 else {
danielebarchiesi@0 798 $function = $plugin_definition[$function_name];
danielebarchiesi@0 799 }
danielebarchiesi@0 800
danielebarchiesi@0 801 if (function_exists($function)) {
danielebarchiesi@0 802 return $function;
danielebarchiesi@0 803 }
danielebarchiesi@0 804 }
danielebarchiesi@0 805
danielebarchiesi@0 806 /**
danielebarchiesi@0 807 * Load a plugin and get a function name from it, returning success only
danielebarchiesi@0 808 * if the function exists.
danielebarchiesi@0 809 *
danielebarchiesi@0 810 * @param $module
danielebarchiesi@0 811 * The module that owns the plugin type.
danielebarchiesi@0 812 * @param $type
danielebarchiesi@0 813 * The type of plugin.
danielebarchiesi@0 814 * @param $id
danielebarchiesi@0 815 * The id of the specific plugin to load.
danielebarchiesi@0 816 * @param $function_name
danielebarchiesi@0 817 * The identifier of the function. For example, 'settings form'.
danielebarchiesi@0 818 *
danielebarchiesi@0 819 * @return
danielebarchiesi@0 820 * The actual name of the function to call, or NULL if the function
danielebarchiesi@0 821 * does not exist.
danielebarchiesi@0 822 */
danielebarchiesi@0 823 function ctools_plugin_load_function($module, $type, $id, $function_name) {
danielebarchiesi@0 824 $plugin = ctools_get_plugins($module, $type, $id);
danielebarchiesi@0 825 return ctools_plugin_get_function($plugin, $function_name);
danielebarchiesi@0 826 }
danielebarchiesi@0 827
danielebarchiesi@0 828 /**
danielebarchiesi@0 829 * Get a class from a plugin, if it exists. If the plugin is not already
danielebarchiesi@0 830 * loaded, try ctools_plugin_load_class() instead.
danielebarchiesi@0 831 *
danielebarchiesi@0 832 * @param $plugin_definition
danielebarchiesi@0 833 * The loaded plugin type.
danielebarchiesi@0 834 * @param $class_name
danielebarchiesi@0 835 * The identifier of the class. For example, 'handler'.
danielebarchiesi@0 836 *
danielebarchiesi@0 837 * @return
danielebarchiesi@0 838 * The actual name of the class to call, or NULL if the class does not exist.
danielebarchiesi@0 839 */
danielebarchiesi@0 840 function ctools_plugin_get_class($plugin_definition, $class_name) {
danielebarchiesi@0 841 // If cached the .inc file may not have been loaded. require_once is quite safe
danielebarchiesi@0 842 // and fast so it's okay to keep calling it.
danielebarchiesi@0 843 if (isset($plugin_definition['file'])) {
danielebarchiesi@0 844 // Plugins that are loaded from info files have the info file as
danielebarchiesi@0 845 // $plugin['file']. Don't try to run those.
danielebarchiesi@0 846 $info = ctools_plugin_get_info($plugin_definition['plugin module'], $plugin_definition['plugin type']);
danielebarchiesi@0 847 if (empty($info['info file'])) {
danielebarchiesi@0 848 require_once DRUPAL_ROOT . '/' . $plugin_definition['path'] . '/' . $plugin_definition['file'];
danielebarchiesi@0 849 }
danielebarchiesi@0 850 }
danielebarchiesi@0 851
danielebarchiesi@0 852 $return = FALSE;
danielebarchiesi@0 853 if (!isset($plugin_definition[$class_name])) {
danielebarchiesi@0 854 return;
danielebarchiesi@0 855 }
danielebarchiesi@0 856 else if (is_string($plugin_definition[$class_name])) {
danielebarchiesi@0 857 // Plugin uses the string form shorthand.
danielebarchiesi@0 858 $return = $plugin_definition[$class_name];
danielebarchiesi@0 859 }
danielebarchiesi@0 860 else if (isset($plugin_definition[$class_name]['class'])) {
danielebarchiesi@0 861 // Plugin uses the verbose array form.
danielebarchiesi@0 862 $return = $plugin_definition[$class_name]['class'];
danielebarchiesi@0 863 }
danielebarchiesi@0 864 // @todo consider adding an else {watchdog(...)} here
danielebarchiesi@0 865
danielebarchiesi@0 866 return ($return && class_exists($return)) ? $return : NULL;
danielebarchiesi@0 867 }
danielebarchiesi@0 868
danielebarchiesi@0 869 /**
danielebarchiesi@0 870 * Load a plugin and get a class name from it, returning success only if the
danielebarchiesi@0 871 * class exists.
danielebarchiesi@0 872 *
danielebarchiesi@0 873 * @param $module
danielebarchiesi@0 874 * The module that owns the plugin type.
danielebarchiesi@0 875 * @param $type
danielebarchiesi@0 876 * The type of plugin.
danielebarchiesi@0 877 * @param $id
danielebarchiesi@0 878 * The id of the specific plugin to load.
danielebarchiesi@0 879 * @param $class_name
danielebarchiesi@0 880 * The identifier of the class. For example, 'handler'.
danielebarchiesi@0 881 *
danielebarchiesi@0 882 * @return
danielebarchiesi@0 883 * The actual name of the class to call, or NULL if the class does not exist.
danielebarchiesi@0 884 */
danielebarchiesi@0 885 function ctools_plugin_load_class($module, $type, $id, $class_name) {
danielebarchiesi@0 886 $plugin = ctools_get_plugins($module, $type, $id);
danielebarchiesi@0 887 return ctools_plugin_get_class($plugin, $class_name);
danielebarchiesi@0 888 }
danielebarchiesi@0 889
danielebarchiesi@0 890 /**
danielebarchiesi@0 891 * Sort callback for sorting plugins naturally.
danielebarchiesi@0 892 *
danielebarchiesi@0 893 * Sort first by weight, then by title.
danielebarchiesi@0 894 */
danielebarchiesi@0 895 function ctools_plugin_sort($a, $b) {
danielebarchiesi@0 896 if (is_object($a)) {
danielebarchiesi@0 897 $a = (array) $a;
danielebarchiesi@0 898 }
danielebarchiesi@0 899 if (is_object($b)) {
danielebarchiesi@0 900 $b = (array) $b;
danielebarchiesi@0 901 }
danielebarchiesi@0 902
danielebarchiesi@0 903 if (empty($a['weight'])) {
danielebarchiesi@0 904 $a['weight'] = 0;
danielebarchiesi@0 905 }
danielebarchiesi@0 906
danielebarchiesi@0 907 if (empty($b['weight'])) {
danielebarchiesi@0 908 $b['weight'] = 0;
danielebarchiesi@0 909 }
danielebarchiesi@0 910
danielebarchiesi@0 911 if ($a['weight'] == $b['weight']) {
danielebarchiesi@0 912 return strnatcmp(strtolower($a['title']), strtolower($b['title']));
danielebarchiesi@0 913 }
danielebarchiesi@0 914 return ($a['weight'] < $b['weight']) ? -1 : 1;
danielebarchiesi@0 915 }