diff options
Diffstat (limited to 'modules/trigger')
-rw-r--r-- | modules/trigger/tests/trigger_test.module | 74 | ||||
-rw-r--r-- | modules/trigger/trigger.admin.inc | 185 | ||||
-rw-r--r-- | modules/trigger/trigger.api.php | 166 | ||||
-rw-r--r-- | modules/trigger/trigger.install | 24 | ||||
-rw-r--r-- | modules/trigger/trigger.module | 384 | ||||
-rw-r--r-- | modules/trigger/trigger.test | 164 |
6 files changed, 573 insertions, 424 deletions
diff --git a/modules/trigger/tests/trigger_test.module b/modules/trigger/tests/trigger_test.module index bb973ba11..4793ad05f 100644 --- a/modules/trigger/tests/trigger_test.module +++ b/modules/trigger/tests/trigger_test.module @@ -10,22 +10,64 @@ * Implementation of hook_action_info(). */ function trigger_test_action_info() { - // Register an action that can be assigned to the trigger "cron run". + // Register an action that can be assigned to the trigger "cron". return array( 'trigger_test_system_cron_action' => array( 'type' => 'system', - 'description' => t('Cron test action'), + 'label' => t('Cron test action'), 'configurable' => FALSE, - 'hooks' => array( - 'cron' => array('run'), - ), + 'triggers' => array('cron'), ), 'trigger_test_system_cron_conf_action' => array( 'type' => 'system', - 'description' => t('Cron test configurable action'), + 'label' => t('Cron test configurable action'), 'configurable' => TRUE, - 'hooks' => array( - 'cron' => array('run'), + 'triggers' => array('cron'), + ), + 'trigger_test_generic_action' => array( + 'type' => 'system', + 'label' => t('Generic test action'), + 'configurable' => FALSE, + 'triggers' => array( + 'taxonomy_term_insert', + 'taxonomy_term_update', + 'taxonomy_delete', + 'comment_insert', + 'comment_update', + 'comment_delete', + 'user_insert', + 'user_update', + 'user_delete', + 'user_login', + 'user_logout', + 'user_view', + ), + ), + 'trigger_test_generic_any_action' => array( + 'type' => 'system', + 'label' => t('Generic test action for any trigger'), + 'configurable' => FALSE, + 'triggers' => array('any'), + ), + ); +} + +/** + * Implements hook_trigger_info(). + */ +function trigger_test_trigger_info() { + // Register triggers that this module provides. The first is an additional + // node trigger and the second is our own, which should create a new tab + // on the trigger assignment page. + return array( + 'node' => array( + 'node_triggertest' => array( + 'runs when' => t('A test trigger is fired'), + ), + ), + 'trigger_test' => array( + 'trigger_test_triggertest' => array( + 'runs when' => t('Another test trigger is fired'), ), ), ); @@ -74,3 +116,19 @@ function trigger_test_system_cron_conf_action_submit($form, $form_state) { ); return $params; } + +/** + * Action fired during the "taxonomy", "comment", and "user" trigger tests. + */ +function trigger_test_generic_action($context) { + // Indicate successful execution by setting a persistent variable. + variable_set('trigger_test_generic_action', TRUE); +} + +/** + * Action fired during the additional trigger tests. + */ +function trigger_test_generic_any_action($context) { + // Indicate successful execution by setting a persistent variable. + variable_set('trigger_test_generic_any_action', TRUE); +} diff --git a/modules/trigger/trigger.admin.inc b/modules/trigger/trigger.admin.inc index 5e4c3f408..9db7a928f 100644 --- a/modules/trigger/trigger.admin.inc +++ b/modules/trigger/trigger.admin.inc @@ -7,29 +7,29 @@ */ /** - * Build the form that allows users to assign actions to hooks. + * Builds the form that allows users to assign actions to triggers. * - * @param $type - * Name of hook. + * @param $module_to_display + * Which tab of triggers to display. E.g., 'node' for all + * node-related triggers. * @return * HTML form. */ -function trigger_assign($type = NULL) { +function trigger_assign($module_to_display = NULL) { // If no type is specified we default to node actions, since they // are the most common. - if (!isset($type)) { + if (!isset($module_to_display)) { drupal_goto('admin/structure/trigger/node'); } $build = array(); - $hooks = module_invoke_all('hook_info'); - foreach ($hooks as $module => $module_hooks) { - if ($module == $type) { - foreach ($module_hooks as $hook => $data) { - foreach ($data as $op => $description) { - $form_id = 'trigger_' . $hook . '_' . $op . '_assign_form'; - $build[$form_id] = drupal_get_form($form_id, $hook, $op, $description['runs when']); - } + $trigger_info = module_invoke_all('trigger_info'); + drupal_alter('trigger_info', $trigger_info); + foreach ($trigger_info as $module => $hooks) { + if ($module == $module_to_display) { + foreach ($hooks as $hook => $description) { + $form_id = 'trigger_' . $hook . '_assign_form'; + $build[$form_id] = drupal_get_form($form_id, $module, $hook, $description['label']); } } } @@ -39,25 +39,27 @@ function trigger_assign($type = NULL) { /** * Confirm removal of an assigned action. * + * @param $module + * The tab of triggers the user will be directed to after successful + * removal of the action, or if the confirmation form is cancelled. * @param $hook - * @param $op * @param $aid * The action ID. * @ingroup forms * @see trigger_unassign_submit() */ -function trigger_unassign($form, $form_state, $hook = NULL, $op = NULL, $aid = NULL) { - if (!($hook && $op && $aid)) { - drupal_goto('admin/structure/trigger/assign'); +function trigger_unassign($form, $form_state, $module, $hook = NULL, $aid = NULL) { + if (!($hook && $aid)) { + drupal_goto('admin/structure/trigger'); } $form['hook'] = array( '#type' => 'value', '#value' => $hook, ); - $form['operation'] = array( + $form['module'] = array( '#type' => 'value', - '#value' => $op, + '#value' => $module, ); $form['aid'] = array( '#type' => 'value', @@ -67,30 +69,31 @@ function trigger_unassign($form, $form_state, $hook = NULL, $op = NULL, $aid = N $action = actions_function_lookup($aid); $actions = actions_get_all_actions(); - $destination = 'admin/structure/trigger/' . ($hook == 'node' ? 'node' : $hook); + $destination = 'admin/structure/trigger/' . $module; return confirm_form($form, - t('Are you sure you want to unassign the action %title?', array('%title' => $actions[$action]['description'])), + t('Are you sure you want to unassign the action %title?', array('%title' => $actions[$action]['label'])), $destination, t('You can assign it again later if you wish.'), t('Unassign'), t('Cancel') ); } +/** + * Submit callback for trigger_unassign() form. + */ function trigger_unassign_submit($form, &$form_state) { $form_values = $form_state['values']; if ($form_values['confirm'] == 1) { $aid = actions_function_lookup($form_values['aid']); db_delete('trigger_assignments') ->condition('hook', $form_values['hook']) - ->condition('op', $form_values['operation']) ->condition('aid', $aid) ->execute(); $actions = actions_get_all_actions(); - watchdog('actions', 'Action %action has been unassigned.', array('%action' => check_plain($actions[$aid]['description']))); - drupal_set_message(t('Action %action has been unassigned.', array('%action' => $actions[$aid]['description']))); - $hook = $form_values['hook'] == 'node' ? 'node' : $form_values['hook']; - $form_state['redirect'] = 'admin/structure/trigger/' . $hook; + watchdog('actions', 'Action %action has been unassigned.', array('%action' => check_plain($actions[$aid]['label']))); + drupal_set_message(t('Action %action has been unassigned.', array('%action' => $actions[$aid]['label']))); + $form_state['redirect'] = 'admin/structure/trigger/' . $form_values['module']; } else { drupal_goto('admin/structure/trigger'); @@ -98,30 +101,27 @@ function trigger_unassign_submit($form, &$form_state) { } /** - * Create the form definition for assigning an action to a hook-op combination. + * Returns the form for assigning an action to a trigger. * - * @param $form_state - * Information about the current form. + * @param $module + * The name of the trigger group, e.g., 'node'. * @param $hook - * The name of the hook, e.g., 'node'. - * @param $op - * The name of the hook operation, e.g., 'insert'. - * @param $description - * A plain English description of what this hook operation does. - * @return + * The name of the trigger hook, e.g., 'node_insert'. + * @param $label + * A plain English description of what this trigger does. * * @ingoup forms * @see trigger_assign_form_validate() * @see trigger_assign_form_submit() */ -function trigger_assign_form($form, $form_state, $hook, $op, $description) { - $form['hook'] = array( +function trigger_assign_form($form, $form_state, $module, $hook, $label) { + $form['module'] = array( '#type' => 'hidden', - '#value' => $hook, + '#value' => $module, ); - $form['operation'] = array( + $form['hook'] = array( '#type' => 'hidden', - '#value' => $op, + '#value' => $hook, ); // All of these forms use the same validate and submit functions. $form['#validate'][] = 'trigger_assign_form_validate'; @@ -129,53 +129,53 @@ function trigger_assign_form($form, $form_state, $hook, $op, $description) { $options = array(); $functions = array(); - // Restrict the options list to actions that declare support for this hook-op - // combination. + // Restrict the options list to actions that declare support for this hook. foreach (actions_list() as $func => $metadata) { - if (isset($metadata['hooks']['any']) || (isset($metadata['hooks'][$hook]) && is_array($metadata['hooks'][$hook]) && (in_array($op, $metadata['hooks'][$hook])))) { + if (in_array('any', $metadata['triggers']) || in_array($hook, $metadata['triggers'])) { $functions[] = $func; } } foreach (actions_actions_map(actions_get_all_actions()) as $aid => $action) { if (in_array($action['callback'], $functions)) { - $options[$action['type']][$aid] = $action['description']; + $options[$action['type']][$aid] = $action['label']; } } - $form[$op] = array( + $form[$hook] = array( '#type' => 'fieldset', - '#title' => t('Trigger: ') . $description, + '#title' => t('Trigger: ') . $label, '#theme' => 'trigger_display' - ); - // Retrieve actions that are already assigned to this hook-op combination. - $actions = _trigger_get_hook_actions($hook, $op); - $form[$op]['assigned']['#type'] = 'value'; - $form[$op]['assigned']['#value'] = array(); - foreach ($actions as $aid => $description) { - $form[$op]['assigned']['#value'][$aid] = array( - 'description' => $description, - 'link' => l(t('unassign'), "admin/structure/trigger/unassign/$hook/$op/" . md5($aid)) + ); + + // Retrieve actions that are already assigned to this hook combination. + $actions = trigger_get_assigned_actions($hook); + $form[$hook]['assigned']['#type'] = 'value'; + $form[$hook]['assigned']['#value'] = array(); + foreach ($actions as $aid => $info) { + $form[$hook]['assigned']['#value'][$aid] = array( + 'label' => $info['label'], + 'link' => l(t('unassign'), "admin/structure/trigger/unassign/$module/$hook/" . md5($aid)), ); } - $form[$op]['parent'] = array( + $form[$hook]['parent'] = array( '#prefix' => "<div class='container-inline'>", '#suffix' => '</div>', ); // List possible actions that may be assigned. if (count($options) != 0) { array_unshift($options, t('Choose an action')); - $form[$op]['parent']['aid'] = array( + $form[$hook]['parent']['aid'] = array( '#type' => 'select', '#options' => $options, ); - $form[$op]['parent']['submit'] = array( + $form[$hook]['parent']['submit'] = array( '#type' => 'submit', '#value' => t('Assign') ); } else { - $form[$op]['none'] = array( + $form[$hook]['none'] = array( '#markup' => t('No actions available for this trigger. <a href="@link">Add action</a>.', array('@link' => url('admin/config/system/actions/manage'))) ); } @@ -191,13 +191,12 @@ function trigger_assign_form_validate($form, $form_state) { $form_values = $form_state['values']; if (!empty($form_values['aid'])) { $aid = actions_function_lookup($form_values['aid']); - $aid_exists = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND op = :op AND aid = :aid", array( + $aid_exists = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND aid = :aid", array( ':hook' => $form_values['hook'], - ':op' => $form_values['operation'], ':aid' => $aid, ))->fetchField(); if ($aid_exists) { - form_set_error($form_values['operation'], t('The action you chose is already assigned to that trigger.')); + form_set_error($form_values['hook'], t('The action you chose is already assigned to that trigger.')); } } } @@ -210,54 +209,51 @@ function trigger_assign_form_submit($form, $form_state) { if (!empty($form_values['aid'])) { $aid = actions_function_lookup($form_values['aid']); - $weight = db_query("SELECT MAX(weight) FROM {trigger_assignments} WHERE hook = :hook AND op = :op", array( + $weight = db_query("SELECT MAX(weight) FROM {trigger_assignments} WHERE hook = :hook", array( ':hook' => $form_values['hook'], - ':op' => $form_values['operation'], ))->fetchField(); db_insert('trigger_assignments') ->fields(array( - 'hook' => $form_values['hook'], - 'op' => $form_values['operation'], - 'aid' => $aid, + 'hook' => $form_values['hook'], + 'aid' => $aid, 'weight' => $weight + 1, )) ->execute(); // If this action changes a node property, we need to save the node // so the change will persist. + $actions = actions_list(); - if (isset($actions[$aid]['behavior']) && in_array('changes_node_property', $actions[$aid]['behavior']) && ($form_values['operation'] != 'presave')) { - // Delete previous node_save_action if it exists, and re-add a new one at a higher weight. - $save_post_action_assigned = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND op = :op AND aid = :aid", array( + if (isset($actions[$aid]['behavior']) && in_array('changes_node_property', $actions[$aid]['behavior']) && ($form_values['hook'] != 'node_presave') && ($form_values['hook'] != 'comment_presave')) { + // Delete previous node_save_action if it exists, and re-add a new one at + // a higher weight. + $save_post_action_assigned = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND aid = :aid", array( ':hook' => $form_values['hook'], - ':op' => $form_values['operation'], ':aid' => 'node_save_action', ))->fetchField(); if ($save_post_action_assigned) { db_delete('trigger_assignments') ->condition('hook', $form_values['hook']) - ->condition('op', $form_values['operation']) ->condition('aid', 'node_save_action') ->execute(); } db_insert('trigger_assignments') ->fields(array( - 'hook' => $form_values['hook'], - 'op' => $form_values['operation'], - 'aid' => 'node_save_action', + 'hook' => $form_values['hook'], + 'aid' => 'node_save_action', 'weight' => $weight + 2, )) ->execute(); if (!$save_post_action_assigned) { - drupal_set_message(t('You have added an action that changes a the property of a post. A Save post action has been added so that the property change will be saved.')); + drupal_set_message(t("You have added an action that changes a the property of some content. Your 'Save content' action has been moved later in the list so that the property change will be saved.")); } } } } /** - * Display actions assigned to this hook-op combination in a table. + * Displays actions assigned to this hook in a table. * * @param array $element * The fieldset including all assigned actions. @@ -269,12 +265,12 @@ function trigger_assign_form_submit($form, $form_state) { function theme_trigger_display($element) { $header = array(); $rows = array(); - if (count($element['assigned']['#value'])) { + if (isset($element['assigned']) && count($element['assigned']['#value'])) { $header = array(array('data' => t('Name')), array('data' => t('Operation'))); $rows = array(); foreach ($element['assigned']['#value'] as $aid => $info) { $rows[] = array( - $info['description'], + $info['label'], $info['link'] ); } @@ -289,34 +285,3 @@ function theme_trigger_display($element) { return $output; } - -/** - * Get the actions that have already been defined for this - * type-hook-op combination. - * - * @param $type - * One of 'node', 'user', 'comment'. - * @param $hook - * The name of the hook for which actions have been assigned, - * e.g. 'node'. - * @param $op - * The hook operation for which the actions have been assigned, - * e.g., 'view'. - * @return - * An array of action descriptions keyed by action IDs. - */ -function _trigger_get_hook_actions($hook, $op, $type = NULL) { - if ($type) { - return db_query("SELECT h.aid, a.description FROM {trigger_assignments} h LEFT JOIN {actions} a on a.aid = h.aid WHERE a.type = :type AND h.hook = :hook AND h.op = :op ORDER BY h.weight", array( - ':type' => $type, - ':hook' => $hook, - ':op' => $op, - ))->fetchAllKeyed(); - } - else { - return db_query("SELECT h.aid, a.description FROM {trigger_assignments} h LEFT JOIN {actions} a on a.aid = h.aid WHERE h.hook = :hook AND h.op = :op ORDER BY h.weight", array( - ':hook' => $hook, - ':op' => $op, - ))->fetchAllKeyed(); - } -} diff --git a/modules/trigger/trigger.api.php b/modules/trigger/trigger.api.php index cc63d5c1a..0f7834e80 100644 --- a/modules/trigger/trigger.api.php +++ b/modules/trigger/trigger.api.php @@ -12,142 +12,50 @@ */ /** - * Declare information about one or more Drupal actions. + * Declares triggers (events) for users to assign actions to. * - * Any module can define any number of Drupal actions. The trigger module is an - * example of a module that uses actions. An action consists of two or three - * parts: (1) an action definition (returned by this hook), (2) a function which - * does the action (which by convention is named module + '_' + description of - * what the function does + '_action'), and an optional form definition - * function that defines a configuration form (which has the name of the action - * with '_form' appended to it.) + * This hook is used by the trigger module to create a list of triggers (events) + * that users can assign actions to. Your module is responsible for detecting + * that the events have occurred, calling trigger_get_assigned_actions() to find + * out which actions the user has associated with your trigger, and then calling + * actions_do() to fire off the actions. * - * @return - * - An array of action descriptions. Each action description is an associative - * array, where the key of the item is the action's function, and the - * following key-value pairs: - * - 'type': (required) the type is determined by what object the action - * acts on. Possible choices are node, user, comment, and system. Or - * whatever your own custom type is. So, for the nodequeue module, the - * type might be set to 'nodequeue' if the action would be performed on a - * nodequeue. - * - 'description': (required) The human-readable name of the action. - * - 'configurable': (required) If FALSE, then the action doesn't require - * any extra configuration. If TRUE, then you should define a form - * function with the same name as the key, but with '_form' appended to - * it (i.e., the form for 'node_assign_owner_action' is - * 'node_assign_owner_action_form'.) - * This function will take the $context as the only parameter, and is - * paired with the usual _submit function, and possibly a _validate - * function. - * - 'hooks': (required) An array of all of the operations this action is - * appropriate for, keyed by hook name. The trigger module uses this to - * filter out inappropriate actions when presenting the interface for - * assigning actions to events. If you are writing actions in your own - * modules and you simply want to declare support for all possible hooks, - * you can set 'hooks' => array('any' => TRUE). Common hooks are 'user', - * 'node', 'comment', or 'taxonomy'. Any hook that has been described - * to Drupal in hook_hook_info() will work is a possiblity. - * - 'behavior': (optional) Human-readable array of behavior descriptions. - * The only one we have now is 'changes node property'. You will almost - * certainly never have to return this in your own implementations of this - * hook. - * - * The function that is called when the action is triggered is passed two - * parameters - an object of the same type as the 'type' value of the - * hook_action_info array, and a context variable that contains the context - * under which the action is currently running, sent as an array. For example, - * the actions module sets the 'hook' and 'op' keys of the context array (so, - * 'hook' may be 'node' and 'op' may be 'insert'). - */ -function hook_action_info() { - return array( - 'comment_unpublish_action' => array( - 'description' => t('Unpublish comment'), - 'type' => 'comment', - 'configurable' => FALSE, - 'hooks' => array( - 'comment' => array('insert', 'update'), - ) - ), - 'comment_unpublish_by_keyword_action' => array( - 'description' => t('Unpublish comment containing keyword(s)'), - 'type' => 'comment', - 'configurable' => TRUE, - 'hooks' => array( - 'comment' => array('insert', 'update'), - ) - ) - ); -} - -/** - * Execute code after an action is deleted. - * - * @param $aid - * The action ID. - */ -function hook_actions_delete($aid) { - db_delete('actions_assignments') - ->condition('aid', $aid) - ->execute(); -} - -/** - * Alter the actions declared by another module. - * - * Called by actions_list() to allow modules to alter the return - * values from implementations of hook_action_info(). - * - * @see trigger_example_action_info_alter(). - */ -function hook_action_info_alter(&$actions) { - $actions['node_unpublish_action']['description'] = t('Unpublish and remove from public view.'); -} - -/** - * Expose a list of triggers (events) that your module is allowing users to - * assign actions to. - * - * This hook is used by the Triggers API to present information about triggers - * (or events) that your module allows users to assign actions to. - * - * See also hook_action_info(). + * @see hook_action_info(). * * @return - * - A nested array. The outermost key defines the module that the triggers - * are from. The menu system will use the key to look at the .info file of - * the module and make a local task (a tab) in the trigger UI. - * - The next key defines the hook being described. - * - Inside of that array are a list of arrays keyed by hook operation. - * - Each of those arrays have a key of 'runs when' and a value which is - * an English description of the hook. - * - * For example, the node_hook_info implementation has 'node' as the outermost - * key, as that's the module it's in. Next it has 'node' as the next key, - * as hook_node() is what applies to changes in nodes. Finally the keys - * after that are the various operations for hook_node() that the node module - * is exposing as triggers. + * A nested associative array. + * - The outermost key is the name of the module that is defining the triggers. + * This will be used to create a local task (tab) in the trigger module's + * user interface. A contrib module may supply a trigger for a core module by + * giving the core module's name as the key. For example, you could use the + * 'node' key to add a node-related trigger. + * - Within each module, each individual trigger is keyed by a hook name + * describing the particular trigger (this is not visible to the user, but + * can be used by your module for identification). + * - Each trigger is described by an associative array. Currently, the only + * key-value pair is 'label', which contains a translated human-readable + * description of the triggering event. + * For example, the trigger set for the 'node' module has 'node' as the + * outermost key and defines triggers for 'node_insert', 'node_update', + * 'node_delete' etc. that fire when a node is saved, updated, etc. */ -function hook_hook_info() { +function hook_trigger_info() { return array( 'node' => array( - 'node' => array( - 'presave' => array( - 'runs when' => t('When either saving a new post or updating an existing post'), - ), - 'insert' => array( - 'runs when' => t('After saving a new post'), - ), - 'update' => array( - 'runs when' => t('After saving an updated post'), - ), - 'delete' => array( - 'runs when' => t('After deleting a post') - ), - 'view' => array( - 'runs when' => t('When content is viewed by an authenticated user') - ), + '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'), ), ), ); diff --git a/modules/trigger/trigger.install b/modules/trigger/trigger.install index 2e014d071..b8553e48c 100644 --- a/modules/trigger/trigger.install +++ b/modules/trigger/trigger.install @@ -26,14 +26,7 @@ function trigger_schema() { 'length' => 32, 'not null' => TRUE, 'default' => '', - 'description' => 'Primary Key: The name of the internal Drupal hook upon which an action is firing; for example, node.', - ), - 'op' => array( - 'type' => 'varchar', - 'length' => 32, - 'not null' => TRUE, - 'default' => '', - 'description' => 'Primary Key: The specific operation of the hook upon which an action is firing: for example, presave.', + 'description' => 'Primary Key: The name of the internal Drupal hook; for example, node_insert.', ), 'aid' => array( 'type' => 'varchar', @@ -49,7 +42,7 @@ function trigger_schema() { 'description' => 'The weight of the trigger assignment in relation to other triggers.', ), ), - 'primary key' => array('hook', 'op', 'aid'), + 'primary key' => array('hook', 'aid'), 'foreign keys' => array( 'aid' => array('actions' => 'aid'), ), @@ -57,4 +50,17 @@ function trigger_schema() { return $schema; } +/** + * Adds operation names to the hook names and drops the "op" field. + */ +function trigger_update_7000() { + $ret = array(); + $result = db_query("SELECT hook, op, aid FROM {trigger_assignments} WHERE op <> ''"); + while ($row = db_fetch_object($result)) { + $ret[] = update_sql("UPDATE {trigger_assignments} SET hook = '%s' WHERE hook = '%s' AND op = '%s' AND aid = '%s'", $row->hook . '_' . $row->op, $row->hook, $row->op, $row->aid); + } + $ret[] = update_sql("ALTER TABLE {trigger_assignments} DROP op"); + + return $ret; +} 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; +} + diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test index 884982f83..4889bc59e 100644 --- a/modules/trigger/trigger.test +++ b/modules/trigger/trigger.test @@ -59,7 +59,7 @@ class TriggerContentTestCase extends DrupalWebTestCase { $this->assertRaw(t('The action you chose is already assigned to that trigger.'), t('Check to make sure an error occurs when assigning an action to a trigger twice.')); // Test 3: The action should be able to be unassigned from a trigger. - $this->drupalPost('admin/structure/trigger/unassign/node/presave/' . $hash, array(), t('Unassign')); + $this->drupalPost('admin/structure/trigger/unassign/node/node_presave/' . $hash, array(), t('Unassign')); $this->assertRaw(t('Action %action has been unassigned.', array('%action' => ucfirst($info['name']))), t('Check to make sure the @action action can be unassigned from the trigger.', array('@action' => $info['name']))); $assigned = db_query("SELECT COUNT(*) FROM {trigger_assignments} WHERE aid IN (:keys)", array(':keys' => $content_actions))->fetchField(); $this->assertFalse($assigned, t('Check to make sure unassign worked properly at the database level.')); @@ -79,32 +79,32 @@ class TriggerContentTestCase extends DrupalWebTestCase { 'node_publish_action' => array( 'property' => 'status', 'expected' => 1, - 'name' => t('publish post'), + 'name' => t('publish content'), ), 'node_unpublish_action' => array( 'property' => 'status', 'expected' => 0, - 'name' => t('unpublish post'), + 'name' => t('unpublish content'), ), 'node_make_sticky_action' => array( 'property' => 'sticky', 'expected' => 1, - 'name' => t('make post sticky'), + 'name' => t('make content sticky'), ), 'node_make_unsticky_action' => array( 'property' => 'sticky', 'expected' => 0, - 'name' => t('make post unsticky'), + 'name' => t('make content unsticky'), ), 'node_promote_action' => array( 'property' => 'promote', 'expected' => 1, - 'name' => t('promote post to front page'), + 'name' => t('promote content to front page'), ), 'node_unpromote_action' => array( 'property' => 'promote', 'expected' => 0, - 'name' => t('remove post from front page'), + 'name' => t('remove content from front page'), ), ); return $info[$action]; @@ -138,41 +138,161 @@ class TriggerCronTestCase extends DrupalWebTestCase { // Create an administrative user. $test_user = $this->drupalCreateUser(array('administer actions')); $this->drupalLogin($test_user); - + // Assign a non-configurable action to the cron run trigger. $edit = array('aid' => md5('trigger_test_system_cron_action')); - $this->drupalPost('admin/structure/trigger/cron', $edit, t('Assign')); - + $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign')); + // Assign a configurable action to the cron trigger. $hash = md5('trigger_test_system_cron_conf_action'); - $action_description = $this->randomName(); + $action_label = $this->randomName(); $edit = array( - 'actions_description' => $action_description, - 'subject' => $action_description, + 'actions_label' => $action_label, + 'subject' => $action_label, ); $this->drupalPost('admin/config/system/actions/configure/' . $hash, $edit, t('Save')); $edit = array('aid' => md5('1')); - $this->drupalPost('admin/structure/trigger/cron', $edit, t('Assign')); - + $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign')); + // Add a second configurable action to the cron trigger. - $action_description = $this->randomName(); + $action_label = $this->randomName(); $edit = array( - 'actions_description' => $action_description, - 'subject' => $action_description, + 'actions_label' => $action_label, + 'subject' => $action_label, ); $this->drupalPost('admin/config/system/actions/configure/' . $hash, $edit, t('Save')); $edit = array('aid' => md5('2')); - $this->drupalPost('admin/structure/trigger/cron', $edit, t('Assign')); - + $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign')); + // Force a cron run. drupal_cron_run(); - + // Make sure the non-configurable action has fired. $action_run = variable_get('trigger_test_system_cron_action', FALSE); $this->assertTrue($action_run, t('Check that the cron run triggered the test action.')); - + // Make sure that both configurable actions have fired. $action_run = variable_get('trigger_test_system_cron_conf_action', 0) == 2; $this->assertTrue($action_run, t('Check that the cron run triggered both complex actions.')); } } + +/** + * Test other triggers. + */ +class TriggerOtherTestCase extends DrupalWebTestCase { + var $_cleanup_roles = array(); + var $_cleanup_users = array(); + + public static function getInfo() { + return array( + 'name' => 'Trigger other actions', + 'description' => 'Test triggering of user, comment, taxonomy actions.' , + 'group' => 'Trigger', + ); + } + + function setUp() { + parent::setUp('trigger', 'trigger_test'); + } + + /** + * Test triggering on user create. + */ + function testActionsUser() { + // Assign an action to the create user trigger. + $test_user = $this->drupalCreateUser(array('administer actions')); + $this->drupalLogin($test_user); + $action_id = 'trigger_test_generic_action'; + $hash = md5($action_id); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign')); + + // Set action variable to FALSE. + variable_set( $action_id, FALSE ); + + // Create an unblocked user + $web_user = $this->drupalCreateUser(array('administer users')); + $this->drupalLogin($web_user); + $name = $this->randomName(); + $pass = user_password(); + $edit = array(); + $edit['name'] = $name; + $edit['mail'] = $name . '@example.com'; + $edit['pass[pass1]'] = $pass; + $edit['pass[pass2]'] = $pass; + $edit['status'] = 1; + $this->drupalPost('admin/people/create', $edit, t('Create new account')); + + // Verify that the action variable has been set. + $this->assertTrue(variable_get($action_id, FALSE), t('Check that creating a user triggered the test action.')); + + // Reset the action variable. + variable_set( $action_id, FALSE ); + } + + /** + * Test triggering on comment save. + */ + function testActionsComment() { + // Assign an action to the comment save trigger. + $test_user = $this->drupalCreateUser(array('administer actions')); + $this->drupalLogin($test_user); + $action_id = 'trigger_test_generic_action'; + $hash = md5($action_id); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/comment', $edit, t('Assign')); + + // Set action variable to FALSE. + variable_set( $action_id, FALSE ); + + // Create a node and add a comment to it. + $web_user = $this->drupalCreateUser(array('create article content', 'access content', 'post comments without approval', 'post comments')); + $this->drupalLogin($web_user); + $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1)); + $edit = array(); + $edit['subject'] = $this->randomName(10); + $edit['comment'] = $this->randomName(10) . ' ' . $this->randomName(10); + $this->drupalGet('comment/reply/' . $node->nid); + $this->drupalPost(NULL, $edit, t('Save')); + + // Verify that the action variable has been set. + $this->assertTrue(variable_get($action_id, FALSE), t('Check that creating a comment triggered the action.')); + } + + /** + * Test triggering on taxonomy new term. + */ + function testActionsTaxonomy() { + // Assign an action to the taxonomy term save trigger. + $test_user = $this->drupalCreateUser(array('administer actions')); + $this->drupalLogin($test_user); + $action_id = 'trigger_test_generic_action'; + $hash = md5($action_id); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/taxonomy', $edit, t('Assign')); + + // Set action variable to FALSE. + variable_set( $action_id, FALSE ); + + // Create a taxonomy vocabulary and add a term to it. + + // Create a vocabulary. + $vocabulary = new stdClass(); + $vocabulary->name = $this->randomName(); + $vocabulary->description = $this->randomName(); + $vocabulary->machine_name = drupal_strtolower($this->randomName()); + $vocabulary->help = ''; + $vocabulary->nodes = array('article' => 'article'); + $vocabulary->weight = mt_rand(0, 10); + taxonomy_vocabulary_save($vocabulary); + + $term = new stdClass(); + $term->name = $this->randomName(); + $term->vid = $vocabulary->vid; + taxonomy_term_save($term); + + // Verify that the action variable has been set. + $this->assertTrue(variable_get($action_id, FALSE), t('Check that creating a taxonomy term triggered the action.')); + } +} |