From 0a5d33a151e89648ab9fc7f495c909d29fb3767a Mon Sep 17 00:00:00 2001
From: Earl Miles <merlin@logrus.com>
Date: Tue, 13 Jan 2009 18:07:56 +0000
Subject: [PATCH] Update plugins to be able to easily handle the
 $module.views.inc style of includes.

---
 delegator/plugins/tasks/node_view.inc |  9 ++++
 help/plugins-api.html                 | 46 +++++++++++++++++++
 help/plugins-creating.html            |  3 +-
 includes/plugins.inc                  | 64 +++++++++++++++++++++++++++
 plugins/access/node_access.inc        |  2 +-
 5 files changed, 122 insertions(+), 2 deletions(-)
 create mode 100644 help/plugins-api.html

diff --git a/delegator/plugins/tasks/node_view.inc b/delegator/plugins/tasks/node_view.inc
index 827a2cc7..a02cb0ef 100644
--- a/delegator/plugins/tasks/node_view.inc
+++ b/delegator/plugins/tasks/node_view.inc
@@ -1,6 +1,15 @@
 <?php
 // $Id$
 
+/**
+ * @file
+ * Handle the 'node view' override task.
+ *
+ * This plugin overrides node/%node and reroutes it to the delegator, where
+ * a list of tasks can be used to service this request based upon criteria
+ * supplied by access plugins.
+ */
+
 /**
  * Specialized implementation of hook_delegator_tasks(). See api-task.html for
  * more information.
diff --git a/help/plugins-api.html b/help/plugins-api.html
new file mode 100644
index 00000000..24a69e80
--- /dev/null
+++ b/help/plugins-api.html
@@ -0,0 +1,46 @@
+<!-- $Id$ -->
+
+APIs are a form of plugins that are tightly associated with a module. Instead of a module providing any number of plugins, each module provides only one file for an API and this file can contain hooks that the module should invoke.
+
+Modules support this API by implementing hook_ctools_plugin_api($module, $api). If they support the API, they return a packet of data:
+
+function mymodule_ctools_plugin_api($module, $api) {
+  if ($module == 'some module' && $api = 'some api') {
+    return array(
+      'version' => The minimum API version this system supports. If this API version is incompatible then the .inc file will not be loaded.
+      'path' => Where to find the file. Optional; if not specified it will be the module's directory.
+      'file' => an alternative version of the filename. If not specified it will be $module.$api.inc
+    );
+  }
+}
+
+This implementation must be in the .module file.
+
+Modules utilizing this can invole ctools_plugin_api_include() in order to ensure all modules that support the API will have their files loaded as necessary. It's usually easiest to create a small helper function like this:
+
+define('MYMODULE_MINIMUM_VERSION', 1);
+define('MYMODULE_VERSION', 1);
+
+function mymodule_include_api() {
+  ctools_include('plugins');
+  return ctools_plugin_api_include('mymodule', 'myapi', MYMODULE_MINIMUM_VERSION, MYMODULE_VERSION);
+}
+
+Using a define will ensure your use of version numbers is consistent and easy to update when you make API changes. You can then use the usual module_invoke type commands:
+
+mymodule_include_api();
+module_invoke('myhook', $data);
+
+If you need to pass references, this construct is standard:
+
+foreach (mymodule_include_api() as $module => $info) {
+  $function = $module . '_hookname';
+  // Just because they implement the API and include a file does not guarantee they implemented
+  // a hook function!
+  if (!function_exists($function)) {
+    continue;
+  }
+
+  // Typically array_merge() is used below if data is returned.
+  $result = $function($data1, $data2, $data3);
+}
\ No newline at end of file
diff --git a/help/plugins-creating.html b/help/plugins-creating.html
index ca020442..54c11c14 100644
--- a/help/plugins-creating.html
+++ b/help/plugins-creating.html
@@ -44,4 +44,5 @@ General feature for callbacks:
     'function' => 'function_name'
   ),
 
-  Using ctools_plugin_get_function() or ctools_plugin_load_function() will take advantage.
\ No newline at end of file
+  Using ctools_plugin_get_function() or ctools_plugin_load_function() will take advantage.
+
diff --git a/includes/plugins.inc b/includes/plugins.inc
index 61235643..fce5132e 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -9,6 +9,70 @@
  * necessary.
  */
 
+/**
+ * Load a group of API files.
+ *
+ * This will ask each module if they support the given API, and if they do
+ * it will load the specified file name. The API and the file name
+ * coincide by design.
+ *
+ * This function invokes hook_ctools_api. This invokation is statically
+ * cached, so feel free to call it as often per page run as you like, it
+ * will cost very little.
+ *
+ * @param $owner
+ *   The name of the module that controls the API.
+ * @param $api
+ *   The name of the api. The api name forms the file name:
+ *   $module.$api.inc
+ * @param $minimum_version
+ *   The lowest version API that is compatible with this one. If a module
+ *   reports its API as older than this, its files will not be loaded. This
+ *   should never change during operation.
+ * @param $current_version
+ *   The current version of the api. If a module reports its minimum API as
+ *   higher than this, its files will not be loaded. This should never change
+ *   during operation.
+ *
+ * @return
+ *   The API information, in case you need it.
+ */
+function ctools_plugin_api_include($owner, $api, $minimum_version, $current_version) {
+  static $cache = array();
+  if (!isset($cache[$owner][$api])) {
+    $cache[$owner][$api] = array();
+    foreach (module_implements('ctools_plugin_api') as $module) {
+      $function = $module . '_ctools_plugin_api';
+      $info = $function();
+      if (!isset($info['version'])) {
+        continue;
+      }
+
+      // Only process if version is between minimum and current, inclusive.
+      if ($info['version'] >= $minimum_version && $info_version <= $current_version) {
+        if (!isset($info['path'])) {
+          $info['path'] = drupal_get_path('module', $module);
+        }
+        if (!isset($info['file'])) {
+          $info['file'] = "$module.$api.inc";
+        }
+        $cache[$owner][$api][$module] = $info;
+      }
+    }
+
+    // Now that we have a list, do our includes.
+    foreach ($cache[$owner][$api] as $module => $info) {
+      if (file_exists("./$info[path]/$info[file]")) {
+        $cache[$owner][$api][$module]['included'] = TRUE;
+        require_once "./$info[path]/$info[file]";
+      }
+    }
+
+  }
+
+  return $cache[$module][$api];
+}
+
 /**
  * Fetch a group of plugins by name.
  *
diff --git a/plugins/access/node_access.inc b/plugins/access/node_access.inc
index 55a9cc62..bf5393ce 100644
--- a/plugins/access/node_access.inc
+++ b/plugins/access/node_access.inc
@@ -11,7 +11,7 @@
  */
 function ctools_node_access_ctools_access() {
   $args['node_access'] = array(
-    'title' => t("Node access"),
+    'title' => t("Operation"),
     'description' => t('Control access with built in Drupal node access test.'),
     'callback' => 'ctools_node_access_ctools_access_check',
     'default' => array('type' => 'view'),
-- 
GitLab