summaryrefslogtreecommitdiff
path: root/modules/trigger/trigger.module
diff options
context:
space:
mode:
Diffstat (limited to 'modules/trigger/trigger.module')
-rw-r--r--modules/trigger/trigger.module384
1 files changed, 238 insertions, 146 deletions
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
index 281400fe5..d889007e4 100644
--- a/modules/trigger/trigger.module
+++ b/modules/trigger/trigger.module
@@ -11,13 +11,13 @@
* Implement hook_help().
*/
function trigger_help($path, $arg) {
- $explanation = '<p>' . t('Triggers are system events, such as when new content is added or when a user logs in. Trigger module combines these triggers with actions (functional tasks), such as unpublishing content or e-mailing an administrator. The <a href="@url">Actions settings page</a> contains a list of existing actions and provides the ability to create and configure additional actions.', array('@url' => url('admin/config/system/actions'))) . '</p>';
+ $explanation = '<p>' . t('Triggers are system events, such as when new content is added or when a user logs in. The trigger module associates these triggers with actions (functional tasks), such as unpublishing content or e-mailing an administrator. The <a href="@url">Actions settings page</a> contains a list of existing actions and provides the ability to create and configure additional actions.', array('@url' => url('admin/config/system/actions'))) . '</p>';
switch ($path) {
case 'admin/structure/trigger/comment':
return $explanation . '<p>' . t('Below you can assign actions to run when certain comment-related triggers happen. For example, you could promote a post to the front page when a comment is added.') . '</p>';
case 'admin/structure/trigger/node':
- return $explanation . '<p>' . t('Below you can assign actions to run when certain content-related triggers happen. For example, you could send an e-mail to an administrator when a post is created or updated.') . '</p>';
- case 'admin/structure/trigger/cron':
+ return $explanation . '<p>' . t('Below you can assign actions to run when certain content-related triggers happen. For example, you could send an e-mail to an administrator when content is created or updated.') . '</p>';
+ case 'admin/structure/trigger/system':
return $explanation . '<p>' . t('Below you can assign actions to run during each pass of a <a href="@cron">cron maintenance task</a>.', array('@cron' => url('admin/reports/status'))) . '</p>';
case 'admin/structure/trigger/taxonomy':
return $explanation . '<p>' . t('Below you can assign actions to run when certain taxonomy-related triggers happen. For example, you could send an e-mail to an administrator when a term is deleted.') . '</p>';
@@ -37,46 +37,36 @@ function trigger_help($path, $arg) {
function trigger_menu() {
$items['admin/structure/trigger'] = array(
'title' => 'Triggers',
- 'description' => 'Tell Drupal when to execute actions.',
+ 'description' => 'Configure when to execute actions.',
'page callback' => 'trigger_assign',
'access arguments' => array('administer actions'),
'file' => 'trigger.admin.inc',
);
- // Explicitly define the system menu item so we can label it "cron" rather
- // than "system".
- $items['admin/structure/trigger/cron'] = array(
- 'title' => 'Cron',
- 'page callback' => 'trigger_assign',
- 'page arguments' => array('system'),
- 'access arguments' => array('administer actions'),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'trigger.admin.inc',
- );
-
// We want contributed modules to be able to describe
// their hooks and have actions assignable to them.
- $hooks = module_invoke_all('hook_info');
- foreach ($hooks as $module => $hook) {
- // We've already done system.module.
- if ($module == 'system') {
- continue;
- }
+ $trigger_info = module_invoke_all('trigger_info');
+ drupal_alter('trigger_info', $trigger_info);
+
+ foreach ($trigger_info as $module => $hooks) {
$info = db_select('system')
->fields('system', array('info'))
->condition('name', $module)
+ ->condition('status', 1)
->execute()
->fetchField();
- $info = unserialize($info);
- $nice_name = $info['name'];
- $items["admin/structure/trigger/$module"] = array(
- 'title' => $nice_name,
- 'page callback' => 'trigger_assign',
- 'page arguments' => array($module),
- 'access arguments' => array('administer actions'),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'trigger.admin.inc',
- );
+ if ($info) {
+ $info = unserialize($info);
+ $nice_name = $info['name'];
+ $items["admin/structure/trigger/$module"] = array(
+ 'title' => $nice_name,
+ 'page callback' => 'trigger_assign',
+ 'page arguments' => array($module),
+ 'access arguments' => array('administer actions'),
+ 'type' => MENU_LOCAL_TASK,
+ 'file' => 'trigger.admin.inc',
+ );
+ }
}
$items['admin/structure/trigger/unassign'] = array(
'title' => 'Unassign',
@@ -92,21 +82,96 @@ function trigger_menu() {
}
/**
- * Get the aids of actions to be executed for a hook-op combination.
+ * Implement hook_trigger_info().
+ *
+ * Defines all the triggers that this module implements triggers for.
+ */
+function trigger_trigger_info() {
+ return array(
+ 'node' => array(
+ 'node_presave' => array(
+ 'label' => t('When either saving new content or updating existing content'),
+ ),
+ 'node_insert' => array(
+ 'label' => t('After saving new content'),
+ ),
+ 'node_update' => array(
+ 'label' => t('After saving updated content'),
+ ),
+ 'node_delete' => array(
+ 'label' => t('After deleting content'),
+ ),
+ 'node_view' => array(
+ 'label' => t('When content is viewed by an authenticated user'),
+ ),
+ ),
+ 'comment' => array(
+ 'comment_insert' => array(
+ 'label' => t('After saving a new comment'),
+ ),
+ 'comment_update' => array(
+ 'label' => t('After saving an updated comment'),
+ ),
+ 'comment_delete' => array(
+ 'label' => t('After deleting a comment'),
+ ),
+ 'comment_view' => array(
+ 'label' => t('When a comment is being viewed by an authenticated user'),
+ ),
+ ),
+ 'taxonomy' => array(
+ 'taxonomy_term_insert' => array(
+ 'label' => t('After saving a new term to the database'),
+ ),
+ 'taxonomy_term_update' => array(
+ 'label' => t('After saving an updated term to the database'),
+ ),
+ 'taxonomy_term_delete' => array(
+ 'label' => t('After deleting a term'),
+ ),
+ ),
+ 'system' => array(
+ 'cron' => array(
+ 'label' => t('When cron runs'),
+ ),
+ ),
+ 'user' => array(
+ 'user_insert' => array(
+ 'label' => t('After a user account has been created'),
+ ),
+ 'user_update' => array(
+ 'label' => t("After a user's profile has been updated"),
+ ),
+ 'user_delete' => array(
+ 'label' => t('After a user has been deleted'),
+ ),
+ 'user_login' => array(
+ 'label' => t('After a user has logged in'),
+ ),
+ 'user_logout' => array(
+ 'label' => t('After a user has logged out'),
+ ),
+ 'user_view' => array(
+ 'label' => t("When a user's profile is being viewed"),
+ ),
+ ),
+ );
+ }
+
+/**
+ * Gets the action IDs of actions to be executed for a hook.
*
* @param $hook
* The name of the hook being fired.
- * @param $op
- * The name of the operation being executed. Defaults to an empty string
- * because some hooks (e.g., hook_cron()) do not have operations.
* @return
- * An array of action IDs.
+ * An array whose keys are action IDs that the user has associated with
+ * this trigger, and whose values are arrays containing the action type and
+ * label.
*/
-function _trigger_get_hook_aids($hook, $op = '') {
- return db_query("SELECT ta.aid, a.type FROM {trigger_assignments} ta LEFT JOIN {actions} a ON ta.aid = a.aid WHERE ta.hook = :hook AND ta.op = :op ORDER BY ta.weight", array(
+function trigger_get_assigned_actions($hook) {
+ return db_query("SELECT ta.aid, a.type, a.label FROM {trigger_assignments} ta LEFT JOIN {actions} a ON ta.aid = a.aid WHERE ta.hook = :hook ORDER BY ta.weight", array(
':hook' => $hook,
- ':op' => $op,
- ))->fetchAllKeyed();
+ ))->fetchAllAssoc( 'aid', PDO::FETCH_ASSOC);
}
/**
@@ -122,16 +187,16 @@ function trigger_theme() {
}
/**
- * Implement hook_forms(). We reuse code by using the
- * same assignment form definition for each node-op combination.
+ * Implement hook_forms().
+ *
+ * We re-use code by using the same assignment form definition for each hook.
*/
function trigger_forms() {
- $hooks = module_invoke_all('hook_info');
- foreach ($hooks as $module => $info) {
- foreach ($hooks[$module] as $hook => $ops) {
- foreach ($ops as $op => $description) {
- $forms['trigger_' . $hook . '_' . $op . '_assign_form'] = array('callback' => 'trigger_assign_form');
- }
+ $trigger_info = _trigger_get_all_info();
+ $forms = array();
+ foreach ($trigger_info as $module => $hooks) {
+ foreach ($hooks as $hook => $description) {
+ $forms['trigger_' . $hook . '_assign_form'] = array('callback' => 'trigger_assign_form');
}
}
@@ -139,26 +204,26 @@ function trigger_forms() {
}
/**
- * When an action is called in a context that does not match its type,
- * the object that the action expects must be retrieved. For example, when
- * an action that works on users is called during the node hook, the
- * user object is not available since the node hook doesn't pass it.
- * So here we load the object the action expects.
+ * Loads associated objects for node triggers.
+ *
+ * When an action is called in a context that does not match its type, the
+ * object that the action expects must be retrieved. For example, when an action
+ * that works on users is called during a node hook implementation, the user
+ * object is not available since the node hook call doesn't pass it. So here we
+ * load the object the action expects.
*
* @param $type
* The type of action that is about to be called.
* @param $node
* The node that was passed via the node hook.
+ *
* @return
* The object expected by the action that is about to be called.
*/
function _trigger_normalize_node_context($type, $node) {
+ // Note that comment-type actions are not supported in node contexts,
+ // because we wouldn't know which comment to choose.
switch ($type) {
- // If an action that works on comments is being called in a node context,
- // the action is expecting a comment object. But we do not know which comment
- // to give it. The first? The most recent? All of them? So comment actions
- // in a node context are not supported.
-
// An action that works on users is being called in a node context.
// Load the user object of the node's author.
case 'user':
@@ -167,33 +232,41 @@ function _trigger_normalize_node_context($type, $node) {
}
/**
- * Simple wrapper function to make user hooks work with new entry points.
+ * Calls action functions for node triggers.
*
- * @TODO: Take advantage of the new API and reorganise/remove this function.
+ * @param $node
+ * Node object.
+ * @param $op
+ * Operation to trigger.
+ * @param $a3
+ * Additional argument to action function.
+ * @param $a4
+ * Additional argument to action function.
*/
-function _trigger_node($node, $op, $a3 = NULL, $a4 = NULL) {
+function _trigger_node($node, $hook, $a3 = NULL, $a4 = NULL) {
// Keep objects for reuse so that changes actions make to objects can persist.
static $objects;
// Prevent recursion by tracking which operations have already been called.
static $recursion;
- if (isset($recursion[$op])) {
+ if (isset($recursion[$hook])) {
return;
}
- $recursion[$op] = TRUE;
+ $recursion[$hook] = TRUE;
- $aids = _trigger_get_hook_aids('node', $op);
+ $aids = trigger_get_assigned_actions($hook);
if (!$aids) {
return;
}
$context = array(
- 'hook' => 'node',
- 'op' => $op,
+ 'group' => 'node',
+ 'hook' => $hook,
);
// We need to get the expected object if the action's type is not 'node'.
// We keep the object in $objects so we can reuse it if we have multiple actions
// that make changes to an object.
- foreach ($aids as $aid => $type) {
+ foreach ($aids as $aid => $info) {
+ $type = $info['type'];
if ($type != 'node') {
if (!isset($objects[$type])) {
$objects[$type] = _trigger_normalize_node_context($type, $node);
@@ -212,48 +285,51 @@ function _trigger_node($node, $op, $a3 = NULL, $a4 = NULL) {
* Implement hook_node_view().
*/
function trigger_node_view($node, $build_mode) {
- _trigger_node($node, 'view', $build_mode);
+ _trigger_node($node, 'node_view', $build_mode);
}
/**
* Implement hook_node_update().
*/
function trigger_node_update($node) {
- _trigger_node($node, 'update');
+ _trigger_node($node, 'node_update');
}
/**
* Implement hook_node_presave().
*/
function trigger_node_presave($node) {
- _trigger_node($node, 'presave');
+ _trigger_node($node, 'node_presave');
}
/**
* Implement hook_node_insert().
*/
function trigger_node_insert($node) {
- _trigger_node($node, 'insert');
+ _trigger_node($node, 'node_insert');
}
/**
* Implement hook_node_delete().
*/
function trigger_node_delete($node) {
- _trigger_node($node, 'delete');
+ _trigger_node($node, 'node_delete');
}
/**
- * When an action is called in a context that does not match its type,
- * the object that the action expects must be retrieved. For example, when
- * an action that works on nodes is called during the comment hook, the
- * node object is not available since the comment hook doesn't pass it.
- * So here we load the object the action expects.
+ * Loads associated objects for comment triggers.
+ *
+ * When an action is called in a context that does not match its type, the
+ * object that the action expects must be retrieved. For example, when an action
+ * that works on nodes is called during the comment hook, the node object is not
+ * available since the comment hook doesn't pass it. So here we load the object
+ * the action expects.
*
* @param $type
* The type of action that is about to be called.
* @param $comment
* The comment that was passed via the comment hook.
+ *
* @return
* The object expected by the action that is about to be called.
*/
@@ -273,51 +349,51 @@ function _trigger_normalize_comment_context($type, $comment) {
* Implement hook_comment_insert().
*/
function trigger_comment_insert($comment) {
- _trigger_comment($comment, 'insert');
+ _trigger_comment($comment, 'comment_insert');
}
/**
* Implement hook_comment_update().
*/
function trigger_comment_update($comment) {
- _trigger_comment($comment, 'update');
+ _trigger_comment($comment, 'comment_update');
}
/**
* Implement hook_comment_delete().
*/
function trigger_comment_delete($comment) {
- _trigger_comment($comment, 'delete');
+ _trigger_comment($comment, 'comment_delete');
}
/**
* Implement hook_comment_view().
*/
function trigger_comment_view($comment) {
- _trigger_comment($comment, 'view');
+ _trigger_comment($comment, 'comment_view');
}
/**
- * Helper function for implementations of hook_comment_op().
+ * Calls action functions for comment triggers.
*
* @param $a1
- * Argument, which will be passed to the action.
- * It can be a array of form values or a comment.
+ * Comment object or array of form values.
* @param $op
- * What kind of action is being performed.
+ * Operation to trigger.
*/
-function _trigger_comment($a1, $op) {
+function _trigger_comment($a1, $hook) {
// Keep objects for reuse so that changes actions make to objects can persist.
static $objects;
- $aids = _trigger_get_hook_aids('comment', $op);
+ $aids = trigger_get_assigned_actions($hook);
$context = array(
- 'hook' => 'comment',
- 'op' => $op,
+ 'group' => 'comment',
+ 'hook' => $hook,
);
// We need to get the expected object if the action's type is not 'comment'.
- // We keep the object in $objects so we can reuse it if we have multiple actions
- // that make changes to an object.
- foreach ($aids as $aid => $type) {
+ // We keep the object in $objects so we can reuse it if we have multiple
+ // actions that make changes to an object.
+ foreach ($aids as $aid => $info) {
+ $type = $info['type'];
if ($type != 'comment') {
if (!isset($objects[$type])) {
$objects[$type] = _trigger_normalize_comment_context($type, $a1);
@@ -338,10 +414,10 @@ function _trigger_comment($a1, $op) {
* Implement hook_cron().
*/
function trigger_cron() {
- $aids = _trigger_get_hook_aids('cron', 'run');
+ $aids = trigger_get_assigned_actions('cron');
$context = array(
+ 'group' => 'cron',
'hook' => 'cron',
- 'op' => 'run',
);
// Cron does not act on any specific object.
$object = NULL;
@@ -349,11 +425,13 @@ function trigger_cron() {
}
/**
- * When an action is called in a context that does not match its type,
- * the object that the action expects must be retrieved. For example, when
- * an action that works on nodes is called during the user hook, the
- * node object is not available since the user hook doesn't pass it.
- * So here we load the object the action expects.
+ * Loads associated objects for user triggers.
+ *
+ * When an action is called in a context that does not match its type, the
+ * object that the action expects must be retrieved. For example, when an action
+ * that works on nodes is called during the user hook, the node object is not
+ * available since the user hook doesn't pass it. So here we load the object the
+ * action expects.
*
* @param $type
* The type of action that is about to be called.
@@ -363,12 +441,9 @@ function trigger_cron() {
* The object expected by the action that is about to be called.
*/
function _trigger_normalize_user_context($type, $account) {
+ // Note that comment-type actions are not supported in user contexts,
+ // because we wouldn't know which comment to choose.
switch ($type) {
- // If an action that works on comments is being called in a user context,
- // the action is expecting a comment object. But we have no way of
- // determining the appropriate comment object to pass. So comment
- // actions in a user context are not supported.
-
// An action that works with nodes is being called in a user context.
// If a single node is being viewed, return the node.
case 'node':
@@ -376,35 +451,36 @@ function _trigger_normalize_user_context($type, $account) {
if ((arg(0) == 'node') && is_numeric(arg(1)) && (arg(2) == NULL)) {
return node_load(array('nid' => arg(1)));
}
+ break;
}
}
/**
- * trigger_user_login
+ * Implement hook_user_login().
*/
function trigger_user_login(&$edit, $account, $category) {
- _trigger_user('login', $edit, $account, $category);
+ _trigger_user('user_login', $edit, $account, $category);
}
/**
* Implement hook_user_logout().
*/
function trigger_user_logout($account) {
- _trigger_user('logout', $edit = NULL, $account);
+ _trigger_user('user_logout', $edit = NULL, $account);
}
/**
* Implement hook_user_insert().
*/
function trigger_user_insert(&$edit, $account, $category) {
- _trigger_user('insert', $edit, $account, $category);
+ _trigger_user('user_insert', $edit, $account, $category);
}
/**
* Implement hook_user_update().
*/
function trigger_user_update(&$edit, $account, $category) {
- _trigger_user('update', $edit, $account, $category);
+ _trigger_user('user_update', $edit, $account, $category);
}
/**
@@ -414,7 +490,7 @@ function trigger_user_cancel($edit, $account, $method) {
switch ($method) {
case 'user_cancel_reassign':
case 'user_cancel_delete':
- _trigger_user('delete', $edit, $account, $method);
+ _trigger_user('user_delete', $edit, $account, $method);
break;
}
}
@@ -423,24 +499,23 @@ function trigger_user_cancel($edit, $account, $method) {
* Implement hook_user_view().
*/
function trigger_user_view($account) {
- _trigger_user('view', $edit = NULL, $account, NULL);
+ _trigger_user('user_view', $edit = NULL, $account, NULL);
}
/**
- * Simple wrapper function to make user hooks work with new entry points.
- *
- * @TODO: Take advantage of the new API and reorganise/remove this function.
+ * Calls action functions for user triggers.
*/
-function _trigger_user($op, &$edit, $account, $category = NULL) {
+function _trigger_user($hook, &$edit, $account, $category = NULL) {
// Keep objects for reuse so that changes actions make to objects can persist.
static $objects;
- $aids = _trigger_get_hook_aids('user', $op);
+ $aids = trigger_get_assigned_actions($hook);
$context = array(
- 'hook' => 'user',
- 'op' => $op,
+ 'group' => 'user',
+ 'hook' => $hook,
'form_values' => &$edit,
);
- foreach ($aids as $aid => $type) {
+ foreach ($aids as $aid => $info) {
+ $type = $info['type'];
if ($type != 'user') {
if (!isset($objects[$type])) {
$objects[$type] = _trigger_normalize_user_context($type, $account);
@@ -455,50 +530,67 @@ function _trigger_user($op, &$edit, $account, $category = NULL) {
}
/**
- * Implement hook_taxonomy().
+ * Calls action functions for taxonomy triggers.
+ *
+ * @param $hook
+ * Hook to trigger actions for taxonomy_term_insert(),
+ * taxonomy_term_update(), and taxonomy_term_delete().
+ * @param $array
+ * Item on which operation is being performed, either a term or
+ * form values.
*/
-function trigger_taxonomy($op, $type, $array) {
- if ($type != 'term') {
- return;
- }
- $aids = _trigger_get_hook_aids('taxonomy', $op);
+function _trigger_taxonomy($hook, $array) {
+ $aids = trigger_get_assigned_actions($hook);
$context = array(
- 'hook' => 'taxonomy',
- 'op' => $op
+ 'group' => 'taxonomy',
+ 'hook' => $hook
);
actions_do(array_keys($aids), (object) $array, $context);
}
/**
- * Often we generate a select field of all actions. This function
- * generates the options for that select.
- *
- * @param $type
- * One of 'node', 'user', 'comment'.
- * @return
- * Array keyed by action ID.
+ * Implement hook_taxonomy_term_insert().
*/
-function trigger_options($type = 'all') {
- $options = array(t('Choose an action'));
- foreach (actions_actions_map(actions_get_all_actions()) as $aid => $action) {
- $options[$action['type']][$aid] = $action['description'];
- }
+function trigger_taxonomy_term_insert($term) {
+ _trigger_taxonomy('taxonomy_term_insert', (array) $term);
+}
- if ($type == 'all') {
- return $options;
- }
- else {
- return $options[$type];
- }
+/**
+ * Implement hook_taxonomy_term_update().
+ */
+function trigger_taxonomy_term_update($term) {
+ _trigger_taxonomy('taxonomy_term_update', (array) $term);
+}
+
+/**
+ * Implement hook_taxonomy_term_delete().
+ */
+function trigger_taxonomy_term_delete($term) {
+ _trigger_taxonomy('taxonomy_term_delete', (array) $term);
}
/**
* Implement hook_actions_delete().
*
- * Remove all trigger entries for the given action, when deleted.
+ * Removes all trigger entries for the given action, when an action is deleted.
*/
function trigger_actions_delete($aid) {
db_delete('trigger_assignments')
->condition('aid', $aid)
->execute();
}
+
+/**
+ * Retrieves and caches information from hook_trigger_info() implementations.
+ */
+function _trigger_get_all_info() {
+ static $triggers = NULL;
+ if( $triggers ) {
+ return $triggers;
+ }
+
+ $triggers = module_invoke_all('trigger_info');
+ drupal_alter('trigger_info', $triggers);
+ return $triggers;
+}
+