Index: modules/trigger/trigger.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/trigger/trigger.admin.inc,v retrieving revision 1.21 diff -u -p -r1.21 trigger.admin.inc --- modules/trigger/trigger.admin.inc 6 Nov 2009 03:59:06 -0000 1.21 +++ modules/trigger/trigger.admin.inc 26 Feb 2010 21:59:26 -0000 @@ -153,10 +153,20 @@ function trigger_assign_form($form, $for $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)), - ); + // If action is defined unassign it otherwise offer to delete all orphaned + // actions. + if (actions_function_lookup(md5($aid))) { + $form[$hook]['assigned']['#value'][$aid] = array( + 'label' => $info['label'], + 'link' => l(t('unassign'), "admin/structure/trigger/unassign/$module/$hook/" . md5($aid)), + ); + } + else { + $form[$hook]['assigned']['#value'][$aid] = array( + 'label' => $info['label'], + 'link' => l(t('Remove orphaned actions'), "admin/config/system/actions/orphan"), + ); + } } $form[$hook]['parent'] = array( Index: modules/trigger/trigger.module =================================================================== RCS file: /cvs/drupal/drupal/modules/trigger/trigger.module,v retrieving revision 1.58 diff -u -p -r1.58 trigger.module --- modules/trigger/trigger.module 26 Dec 2009 16:50:09 -0000 1.58 +++ modules/trigger/trigger.module 26 Feb 2010 21:59:26 -0000 @@ -610,7 +610,7 @@ function trigger_actions_delete($aid) { */ function _trigger_get_all_info() { static $triggers = NULL; - if( $triggers ) { + if ( $triggers ) { return $triggers; } Index: modules/trigger/trigger.test =================================================================== RCS file: /cvs/drupal/drupal/modules/trigger/trigger.test,v retrieving revision 1.26 diff -u -p -r1.26 trigger.test --- modules/trigger/trigger.test 9 Feb 2010 12:29:39 -0000 1.26 +++ modules/trigger/trigger.test 26 Feb 2010 21:59:26 -0000 @@ -299,3 +299,57 @@ class TriggerOtherTestCase extends Drupa $this->assertTrue(variable_get($action_id, FALSE), t('Check that creating a taxonomy term triggered the action.')); } } + +/** + * Test that orphaned actions are properly handled. + */ +class TriggerOrphanedActionsTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Trigger orphaned actions', + 'description' => 'Test triggering an action that has since been removed.' , + 'group' => 'Trigger', + ); + } + + function setUp() { + parent::setUp('trigger', 'trigger_test'); + } + + function testActionsOrphaned() { + $action = 'trigger_test_generic_any_action'; + $hash = md5($action); + + // Test 1: Assign an action from a disable-able module to a trigger, + // then pull the trigger, and make sure the actions fire. + $test_user = $this->drupalCreateUser(array('administer actions')); + $this->drupalLogin($test_user); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign')); + + // Create an unpublished node. + $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'access content', 'administer nodes')); + $this->drupalLogin($web_user); + $edit = array(); + $langcode = LANGUAGE_NONE; + $edit["title"] = '!SimpleTest test node! ' . $this->randomName(10); + $edit["body[$langcode][0][value]"] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32); + $this->drupalPost('node/add/page', $edit, t('Save')); + $this->assertRaw(t('!post %title has been created.', array('!post' => 'Basic page', '%title' => $edit["title"])), t('Make sure the Basic page has actually been created')); + + // Action should have been fired. + $this->assertTrue(variable_get('trigger_test_generic_any_action', FALSE), t('Trigger test action successfully fired.')); + + // Test 2: Disable the module that provides the action and make sure the + // trigger doesn't white screen. + module_disable(array('trigger_test')); + $loaded_node = $this->drupalGetNodeByTitle($edit["title"]); + $edit["body[$langcode][0][value]"] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32); + $this->drupalPost("node/$loaded_node->nid/edit", $edit, t('Save')); + + // If the node body was updated successfully we have dealt with the + // unavailable action. + $this->assertRaw(t('!post %title has been updated.', array('!post' => 'Basic page', '%title' => $edit["title"])), t('Make sure the Basic page can be updated with the missing trigger function.')); + } +} Index: modules/trigger/tests/trigger_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/trigger/tests/trigger_test.module,v retrieving revision 1.5 diff -u -p -r1.5 trigger_test.module --- modules/trigger/tests/trigger_test.module 4 Dec 2009 16:49:47 -0000 1.5 +++ modules/trigger/tests/trigger_test.module 26 Feb 2010 21:59:26 -0000 @@ -63,12 +63,12 @@ function trigger_test_trigger_info() { return array( 'node' => array( 'node_triggertest' => array( - 'runs when' => t('A test trigger is fired'), + 'label' => t('A test trigger is fired'), ), ), 'trigger_test' => array( 'trigger_test_triggertest' => array( - 'runs when' => t('Another test trigger is fired'), + 'label' => t('Another test trigger is fired'), ), ), ); Index: includes/actions.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/actions.inc,v retrieving revision 1.35 diff -u -p -r1.35 actions.inc --- includes/actions.inc 26 Feb 2010 16:55:18 -0000 1.35 +++ includes/actions.inc 26 Feb 2010 21:59:26 -0000 @@ -129,7 +129,12 @@ function actions_do($action_ids, $object } // Singleton action; $action_ids is the function name. else { - $actions_result[$action_ids] = $action_ids($object, $context, $a1, $a2); + if (function_exists($action_ids)) { + $actions_result[$action_ids] = $action_ids($object, $context, $a1, $a2); + } + else { + $actions_result[$action_ids] = FALSE; + } } } $stack--; @@ -153,7 +158,7 @@ function actions_do($action_ids, $object * @see hook_action_info() */ function actions_list($reset = FALSE) { - static $actions; + $actions = &drupal_static(__FUNCTION__); if (!isset($actions) || $reset) { $actions = module_invoke_all('action_info'); drupal_alter('action_info', $actions);