From 2348e7de6f9714496316ee42d5598efeb0faaee3 Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Fri, 29 Jun 2007 18:06:51 +0000 Subject: - Patch #148410 by jvandyk: added rewrite of the actions module! This is a very important patch, but one that is merely an enabler. Hopefully we'll see more people submitting "action patches" in the near future. Thanks for the hard work and persistence, John. *If* you decide to update the Drupal Pro Development book to Drupal 6, make sure to add a chapter on actions. ;) --- includes/actions.inc | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 includes/actions.inc (limited to 'includes/actions.inc') diff --git a/includes/actions.inc b/includes/actions.inc new file mode 100644 index 000000000..77a06e841 --- /dev/null +++ b/includes/actions.inc @@ -0,0 +1,227 @@ + variable_get('actions_max_stack', 35)) { + watchdog('actions', 'Stack overflow: too many calls to actions_do(). Aborting to prevent infinite recursion.', WATCHDOG_ERROR); + return; + } + $actions = array(); + $available_actions = actions_list(); + $result = array(); + if (is_array($action_ids)) { + $where = array(); + $where_values = array(); + foreach ($action_ids as $action_id) { + if (is_numeric($action_id)) { + $where[] = 'OR aid = %d'; + $where_values[] = $action_id; + } + elseif (isset($available_actions[$action_id])) { + $actions[$action_id] = $available_actions[$action_id]; + } + } + + // When we have action instances we must go to the database to + // retrieve instance data. + if ($where) { + $where_clause = implode(' ', $where); + // Strip off leading 'OR '. + $where_clause = '('. strstr($where_clause, " ") .')'; + $result_db = db_query('SELECT * FROM {actions} WHERE '. $where_clause, $where_values); + while ($action = db_fetch_object($result_db)) { + $action_id = $action->action_id; + $actions[$action_id] = $action->params ? unserialize($data->parameters) : array(); + $actions[$action_id]['callback'] = $action->callback; + $actions[$action_id]['type'] = $action->type; + } + } + + // Fire actions, in no particular order. + foreach ($actions as $action_id => $params) { + if (is_numeric($action_id)) { // Configurable actions need parameters. + $function = $params['callback']; + $context = array_merge($context, $params); + $result[$action_id] = $function($object, $context, $a1, $a2); + } + // Singleton action; $action_id is the function name. + else { + $result[$action_id] = $action_id($object, $context, $a1, $a2); + } + } + } + // Optimized execution of single action. + else { + // If it's a configurable action, retrieve stored parameters. + if (is_numeric($action_ids)) { + $action = db_fetch_object(db_query("SELECT * FROM {actions} WHERE aid = %d", $action_ids)); + $function = $action->callback; + $context = array_merge($context, unserialize($action->parameters)); + $result[$action_ids] = $function($object, $context, $a1, $a2); + } + // Singleton action; $action_ids is the function name. + else { + $result[$action_ids] = $action_ids($object, $context, $a1, $a2); + } + } + return $result; +} + + +/** + * Discover all action functions by invoking hook_action_info(). + * + * mymodule_action_info() { + * return array( + * 'mymodule_functiondescription_action' => array( + * 'type' => 'node', + * 'description' => t('Save node'), + * 'configurable' => FALSE, + * 'hooks' => array( + * 'nodeapi' => array('delete','insert','update', 'view'), + * 'comment' => array('delete','insert','update', 'view'), + * ) + * ) + * ); + * } + * + * The description is used in presenting possible actions to the user for + * configuration. The type is used to present these actions in a logical + * grouping and to denote context. Some types are 'node', 'user', 'comment', + * and 'system'. If an action is configurable it will provide form, + * validation and submission functions. The hooks the action supports + * are declared in the 'hooks' array. + * + * @return + * An associative array keyed on function name. The value of each key is + * an array containing information about the action, such as type of + * action and description of the action, e.g., + * + * $actions['actions_node_publish'] = ('description' => 'Publish a node' ... ) + */ +function actions_list() { + static $actions; + if (isset($actions)) { + return $actions; + } + + $actions = module_invoke_all('action_info'); + drupal_alter('action_info', $actions); + return $actions; +} + +/** + * Retrieve all action instances from the database. + * Compare with actions_list() which gathers actions by + * invoking hook_action_info(). The two are synchronized + * by visiting /admin/build/actions (when actions.module is + * enabled) which runs actions_synchronize(). + * + * @return + * Associative array keyed by action ID. Each value is + * an associative array with keys 'callback', 'description', + * 'type' and 'configurable'. + */ +function actions_get_all_actions() { + $actions = array(); + $result = db_query("SELECT * FROM {actions}"); + while ($action = db_fetch_object($result)) { + $actions[$action->aid] = array( + 'callback' => $action->callback, + 'description' => $action->description, + 'type' => $action->type, + 'configurable' => (bool) $action->parameters, + ); + } + return $actions; +} + +/** + * Create an associative array keyed by md5 hashes of function names. + * Hashes are used to prevent actual function names from going out into + * HTML forms and coming back. + * + * @param $actions + * An associative array with function names as keys and associative + * arrays with keys 'description', 'type', etc. as values. Generally + * the output of actions_list() or actions_get_all_actions() is given + * as input to this function. + * + * @return + * An associative array keyed on md5 hash of function name. The value of + * each key is an associative array of function, description, and type + * for the action. + */ +function actions_actions_map($actions) { + $actions_map = array(); + foreach ($actions as $callback => $array) { + $key = md5($callback); + $actions_map[$key]['callback'] = isset($array['callback']) ? $array['callback'] : $callback; + $actions_map[$key]['description'] = $array['description']; + $actions_map[$key]['type'] = $array['type']; + $actions_map[$key]['configurable'] = $array['configurable']; + } + return $actions_map; +} + +/** + * Given an md5 hash of a function name, return the function name. + * Faster than actions_actions_map() when you only need the function name. + * + * @param $hash + * MD5 hash of a function name + * + * @return + * Function name + */ +function actions_function_lookup($hash) { + $actions_list = actions_list(); + foreach ($actions_list as $function => $array) { + if (md5($function) == $hash) { + return $function; + } + } + + // Must be an instance; must check database. + $aid = db_result(db_query("SELECT aid FROM {actions} WHERE MD5(aid) = '%s' AND parameters != ''", $hash)); + return $aid; +} -- cgit v1.2.3