trigger.module

  1. drupal
    1. 6 modules/trigger/trigger.module
    2. 7 modules/trigger/trigger.module

Enables functions to be stored and executed at a later time.

Functions & methods

NameDescription
trigger_actions_deleteImplements hook_actions_delete().
trigger_comment_deleteImplements hook_comment_delete().
trigger_comment_insertImplements hook_comment_insert().
trigger_comment_presaveImplements hook_comment_presave().
trigger_comment_updateImplements hook_comment_update().
trigger_comment_viewImplements hook_comment_view().
trigger_cronImplements hook_cron().
trigger_formsImplements hook_forms().
trigger_get_assigned_actionsGets the action IDs of actions to be executed for a hook.
trigger_helpImplements hook_help().
trigger_menuImplements hook_menu().
trigger_node_deleteImplements hook_node_delete().
trigger_node_insertImplements hook_node_insert().
trigger_node_presaveImplements hook_node_presave().
trigger_node_updateImplements hook_node_update().
trigger_node_viewImplements hook_node_view().
trigger_taxonomy_term_deleteImplements hook_taxonomy_term_delete().
trigger_taxonomy_term_insertImplements hook_taxonomy_term_insert().
trigger_taxonomy_term_updateImplements hook_taxonomy_term_update().
trigger_themeImplements hook_theme().
trigger_trigger_infoImplements hook_trigger_info().
trigger_user_cancelImplements hook_user_cancel().
trigger_user_deleteImplements hook_user_delete().
trigger_user_insertImplements hook_user_insert().
trigger_user_loginImplements hook_user_login().
trigger_user_logoutImplements hook_user_logout().
trigger_user_updateImplements hook_user_update().
trigger_user_viewImplements hook_user_view().
_trigger_commentCalls action functions for comment triggers.
_trigger_get_all_infoRetrieves and caches information from hook_trigger_info() implementations.
_trigger_nodeCalls action functions for node triggers.
_trigger_normalize_comment_contextLoads associated objects for comment triggers.
_trigger_normalize_node_contextLoads associated objects for node triggers.
_trigger_normalize_user_contextLoads associated objects for user triggers.
_trigger_tab_informationGathers information about tabs on the triggers administration screen.
_trigger_taxonomyCalls action functions for taxonomy triggers.
_trigger_userCalls action functions for user triggers.

File

modules/trigger/trigger.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Enables functions to be stored and executed at a later time.
  5. */
  6. /**
  7. * Implements hook_help().
  8. */
  9. function trigger_help($path, $arg) {
  10. // Generate help text for admin/structure/trigger/(module) tabs.
  11. $matches = array();
  12. if (preg_match('|^admin/structure/trigger/(.*)$|', $path, $matches)) {
  13. $explanation = '<p>' . t('Triggers are events on your site, such as new content being added or a user logging in. The Trigger module associates these triggers with actions (functional tasks), such as unpublishing content containing certain keywords 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 advanced actions (actions requiring configuration, such as an e-mail address or a list of banned words).', array('@url' => url('admin/config/system/actions'))) . '</p>';
  14. $module = $matches[1];
  15. $trigger_info = _trigger_tab_information();
  16. if (!empty($trigger_info[$module])) {
  17. $explanation .= '<p>' . t('There is a tab on this page for each module that defines triggers. On this tab you can assign actions to run when triggers from the <a href="@module-help">@module-name module</a> happen.', array('@module-help' => url('admin/help/' . $module), '@module-name' => $trigger_info[$module])) . '</p>';
  18. }
  19. return $explanation;
  20. }
  21. if ($path == 'admin/help#trigger') {
  22. $output = '';
  23. $output .= '<h3>' . t('About') . '</h3>';
  24. $output .= '<p>' . t('The Trigger module provides the ability to cause <em>actions</em> to run when certain <em>triggers</em> take place on your site. Triggers are events, such as new content being added to your site or a user logging in, and actions are tasks, such as unpublishing content or e-mailing an administrator. For more information, see the online handbook entry for <a href="@trigger">Trigger module</a>.', array('@trigger' => 'http://drupal.org/documentation/modules/trigger/')) . '</p>';
  25. $output .= '<h3>' . t('Uses') . '</h3>';
  26. $output .= '<dl>';
  27. $output .= '<dt>' . t('Configuring triggers and actions') . '</dt>';
  28. $output .= '<dd>' . t('The combination of actions and triggers can perform many useful tasks, such as e-mailing an administrator if a user account is deleted, or automatically unpublishing comments that contain certain words. To set up a trigger/action combination, first visit the <a href="@actions-page">Actions configuration page</a>, where you can either verify that the action you want is already listed, or create a new <em>advanced</em> action. You will need to set up an advanced action if there are configuration options in your trigger/action combination, such as specifying an e-mail address or a list of banned words. After configuring or verifying your action, visit the <a href="@triggers-page">Triggers configuration page</a> and choose the appropriate tab (Comment, Taxonomy, etc.), where you can assign the action to run when the trigger event occurs.', array('@triggers-page' => url('admin/structure/trigger'), '@actions-page' => url('admin/config/system/actions'))) . '</dd>';
  29. $output .= '</dl>';
  30. return $output;
  31. }
  32. }
  33. /**
  34. * Implements hook_menu().
  35. */
  36. function trigger_menu() {
  37. $items['admin/structure/trigger'] = array(
  38. 'title' => 'Triggers',
  39. 'description' => 'Configure when to execute actions.',
  40. 'page callback' => 'trigger_assign',
  41. 'access arguments' => array('administer actions'),
  42. 'file' => 'trigger.admin.inc',
  43. );
  44. $trigger_info = _trigger_tab_information();
  45. foreach ($trigger_info as $module => $module_name) {
  46. $items["admin/structure/trigger/$module"] = array(
  47. 'title' => $module_name,
  48. 'page callback' => 'trigger_assign',
  49. 'page arguments' => array($module),
  50. 'access arguments' => array('administer actions'),
  51. 'type' => MENU_LOCAL_TASK,
  52. 'file' => 'trigger.admin.inc',
  53. );
  54. }
  55. $items['admin/structure/trigger/unassign'] = array(
  56. 'title' => 'Unassign',
  57. 'description' => 'Unassign an action from a trigger.',
  58. 'page callback' => 'drupal_get_form',
  59. 'page arguments' => array('trigger_unassign'),
  60. 'access arguments' => array('administer actions'),
  61. 'file' => 'trigger.admin.inc',
  62. );
  63. return $items;
  64. }
  65. /**
  66. * Implements hook_trigger_info().
  67. *
  68. * Defines all the triggers that this module implements triggers for.
  69. */
  70. function trigger_trigger_info() {
  71. return array(
  72. 'node' => array(
  73. 'node_presave' => array(
  74. 'label' => t('When either saving new content or updating existing content'),
  75. ),
  76. 'node_insert' => array(
  77. 'label' => t('After saving new content'),
  78. ),
  79. 'node_update' => array(
  80. 'label' => t('After saving updated content'),
  81. ),
  82. 'node_delete' => array(
  83. 'label' => t('After deleting content'),
  84. ),
  85. 'node_view' => array(
  86. 'label' => t('When content is viewed by an authenticated user'),
  87. ),
  88. ),
  89. 'comment' => array(
  90. 'comment_presave' => array(
  91. 'label' => t('When either saving a new comment or updating an existing comment'),
  92. ),
  93. 'comment_insert' => array(
  94. 'label' => t('After saving a new comment'),
  95. ),
  96. 'comment_update' => array(
  97. 'label' => t('After saving an updated comment'),
  98. ),
  99. 'comment_delete' => array(
  100. 'label' => t('After deleting a comment'),
  101. ),
  102. 'comment_view' => array(
  103. 'label' => t('When a comment is being viewed by an authenticated user'),
  104. ),
  105. ),
  106. 'taxonomy' => array(
  107. 'taxonomy_term_insert' => array(
  108. 'label' => t('After saving a new term to the database'),
  109. ),
  110. 'taxonomy_term_update' => array(
  111. 'label' => t('After saving an updated term to the database'),
  112. ),
  113. 'taxonomy_term_delete' => array(
  114. 'label' => t('After deleting a term'),
  115. ),
  116. ),
  117. 'system' => array(
  118. 'cron' => array(
  119. 'label' => t('When cron runs'),
  120. ),
  121. ),
  122. 'user' => array(
  123. 'user_insert' => array(
  124. 'label' => t('After creating a new user account'),
  125. ),
  126. 'user_update' => array(
  127. 'label' => t('After updating a user account'),
  128. ),
  129. 'user_delete' => array(
  130. 'label' => t('After a user has been deleted'),
  131. ),
  132. 'user_login' => array(
  133. 'label' => t('After a user has logged in'),
  134. ),
  135. 'user_logout' => array(
  136. 'label' => t('After a user has logged out'),
  137. ),
  138. 'user_view' => array(
  139. 'label' => t("When a user's profile is being viewed"),
  140. ),
  141. ),
  142. );
  143. }
  144. /**
  145. * Gets the action IDs of actions to be executed for a hook.
  146. *
  147. * @param $hook
  148. * The name of the hook being fired.
  149. *
  150. * @return
  151. * An array whose keys are action IDs that the user has associated with
  152. * this trigger, and whose values are arrays containing the action type and
  153. * label.
  154. */
  155. function trigger_get_assigned_actions($hook) {
  156. $actions = &drupal_static(__FUNCTION__, array());
  157. if (!isset($actions[$hook])) {
  158. $actions[$hook] = 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(
  159. ':hook' => $hook,
  160. ))->fetchAllAssoc('aid', PDO::FETCH_ASSOC);
  161. }
  162. return $actions[$hook];
  163. }
  164. /**
  165. * Implements hook_theme().
  166. */
  167. function trigger_theme() {
  168. return array(
  169. 'trigger_display' => array(
  170. 'render element' => 'element',
  171. 'file' => 'trigger.admin.inc',
  172. ),
  173. );
  174. }
  175. /**
  176. * Implements hook_forms().
  177. *
  178. * We re-use code by using the same assignment form definition for each hook.
  179. */
  180. function trigger_forms() {
  181. $trigger_info = _trigger_get_all_info();
  182. $forms = array();
  183. foreach ($trigger_info as $module => $hooks) {
  184. foreach ($hooks as $hook => $description) {
  185. $forms['trigger_' . $hook . '_assign_form'] = array('callback' => 'trigger_assign_form');
  186. }
  187. }
  188. return $forms;
  189. }
  190. /**
  191. * Loads associated objects for node triggers.
  192. *
  193. * When an action is called in a context that does not match its type, the
  194. * object that the action expects must be retrieved. For example, when an action
  195. * that works on users is called during a node hook implementation, the user
  196. * object is not available since the node hook call doesn't pass it. So here we
  197. * load the object the action expects.
  198. *
  199. * @param $type
  200. * The type of action that is about to be called.
  201. * @param $node
  202. * The node that was passed via the node hook.
  203. *
  204. * @return
  205. * The object expected by the action that is about to be called.
  206. */
  207. function _trigger_normalize_node_context($type, $node) {
  208. // Note that comment-type actions are not supported in node contexts,
  209. // because we wouldn't know which comment to choose.
  210. switch ($type) {
  211. // An action that works on users is being called in a node context.
  212. // Load the user object of the node's author.
  213. case 'user':
  214. return user_load($node->uid);
  215. }
  216. }
  217. /**
  218. * Calls action functions for node triggers.
  219. *
  220. * @param $node
  221. * Node object.
  222. * @param $hook
  223. * Hook to trigger.
  224. * @param $a3
  225. * Additional argument to action function.
  226. * @param $a4
  227. * Additional argument to action function.
  228. */
  229. function _trigger_node($node, $hook, $a3 = NULL, $a4 = NULL) {
  230. // Keep objects for reuse so that changes actions make to objects can persist.
  231. static $objects;
  232. // Prevent recursion by tracking which operations have already been called.
  233. static $recursion;
  234. $aids = trigger_get_assigned_actions($hook);
  235. if (!$aids) {
  236. return;
  237. }
  238. if (isset($recursion[$hook])) {
  239. return;
  240. }
  241. $recursion[$hook] = TRUE;
  242. $context = array(
  243. 'group' => 'node',
  244. 'hook' => $hook,
  245. );
  246. // We need to get the expected object if the action's type is not 'node'.
  247. // We keep the object in $objects so we can reuse it if we have multiple actions
  248. // that make changes to an object.
  249. foreach ($aids as $aid => $info) {
  250. $type = $info['type'];
  251. if ($type != 'node') {
  252. if (!isset($objects[$type])) {
  253. $objects[$type] = _trigger_normalize_node_context($type, $node);
  254. }
  255. // Since we know about the node, we pass that info along to the action.
  256. $context['node'] = $node;
  257. $result = actions_do($aid, $objects[$type], $context, $a3, $a4);
  258. }
  259. else {
  260. actions_do($aid, $node, $context, $a3, $a4);
  261. }
  262. }
  263. unset($recursion[$hook]);
  264. }
  265. /**
  266. * Implements hook_node_view().
  267. */
  268. function trigger_node_view($node, $view_mode) {
  269. _trigger_node($node, 'node_view', $view_mode);
  270. }
  271. /**
  272. * Implements hook_node_update().
  273. */
  274. function trigger_node_update($node) {
  275. _trigger_node($node, 'node_update');
  276. }
  277. /**
  278. * Implements hook_node_presave().
  279. */
  280. function trigger_node_presave($node) {
  281. _trigger_node($node, 'node_presave');
  282. }
  283. /**
  284. * Implements hook_node_insert().
  285. */
  286. function trigger_node_insert($node) {
  287. _trigger_node($node, 'node_insert');
  288. }
  289. /**
  290. * Implements hook_node_delete().
  291. */
  292. function trigger_node_delete($node) {
  293. _trigger_node($node, 'node_delete');
  294. }
  295. /**
  296. * Loads associated objects for comment triggers.
  297. *
  298. * When an action is called in a context that does not match its type, the
  299. * object that the action expects must be retrieved. For example, when an action
  300. * that works on nodes is called during the comment hook, the node object is not
  301. * available since the comment hook doesn't pass it. So here we load the object
  302. * the action expects.
  303. *
  304. * @param $type
  305. * The type of action that is about to be called.
  306. * @param $comment
  307. * The comment that was passed via the comment hook.
  308. *
  309. * @return
  310. * The object expected by the action that is about to be called.
  311. */
  312. function _trigger_normalize_comment_context($type, $comment) {
  313. switch ($type) {
  314. // An action that works with nodes is being called in a comment context.
  315. case 'node':
  316. return node_load(is_array($comment) ? $comment['nid'] : $comment->nid);
  317. // An action that works on users is being called in a comment context.
  318. case 'user':
  319. return user_load(is_array($comment) ? $comment['uid'] : $comment->uid);
  320. }
  321. }
  322. /**
  323. * Implements hook_comment_presave().
  324. */
  325. function trigger_comment_presave($comment) {
  326. _trigger_comment($comment, 'comment_presave');
  327. }
  328. /**
  329. * Implements hook_comment_insert().
  330. */
  331. function trigger_comment_insert($comment) {
  332. _trigger_comment($comment, 'comment_insert');
  333. }
  334. /**
  335. * Implements hook_comment_update().
  336. */
  337. function trigger_comment_update($comment) {
  338. _trigger_comment($comment, 'comment_update');
  339. }
  340. /**
  341. * Implements hook_comment_delete().
  342. */
  343. function trigger_comment_delete($comment) {
  344. _trigger_comment($comment, 'comment_delete');
  345. }
  346. /**
  347. * Implements hook_comment_view().
  348. */
  349. function trigger_comment_view($comment) {
  350. _trigger_comment($comment, 'comment_view');
  351. }
  352. /**
  353. * Calls action functions for comment triggers.
  354. *
  355. * @param $a1
  356. * Comment object or array of form values.
  357. * @param $hook
  358. * Hook to trigger.
  359. */
  360. function _trigger_comment($a1, $hook) {
  361. // Keep objects for reuse so that changes actions make to objects can persist.
  362. static $objects;
  363. $aids = trigger_get_assigned_actions($hook);
  364. $context = array(
  365. 'group' => 'comment',
  366. 'hook' => $hook,
  367. );
  368. // We need to get the expected object if the action's type is not 'comment'.
  369. // We keep the object in $objects so we can reuse it if we have multiple
  370. // actions that make changes to an object.
  371. foreach ($aids as $aid => $info) {
  372. $type = $info['type'];
  373. if ($type != 'comment') {
  374. if (!isset($objects[$type])) {
  375. $objects[$type] = _trigger_normalize_comment_context($type, $a1);
  376. }
  377. // Since we know about the comment, we pass it along to the action
  378. // in case it wants to peek at it.
  379. $context['comment'] = (object) $a1;
  380. actions_do($aid, $objects[$type], $context);
  381. }
  382. else {
  383. actions_do($aid, $a1, $context);
  384. }
  385. }
  386. }
  387. /**
  388. * Implements hook_cron().
  389. */
  390. function trigger_cron() {
  391. $aids = trigger_get_assigned_actions('cron');
  392. $context = array(
  393. 'group' => 'cron',
  394. 'hook' => 'cron',
  395. );
  396. // Cron does not act on any specific object.
  397. $object = NULL;
  398. actions_do(array_keys($aids), $object, $context);
  399. }
  400. /**
  401. * Loads associated objects for user triggers.
  402. *
  403. * When an action is called in a context that does not match its type, the
  404. * object that the action expects must be retrieved. For example, when an action
  405. * that works on nodes is called during the user hook, the node object is not
  406. * available since the user hook doesn't pass it. So here we load the object the
  407. * action expects.
  408. *
  409. * @param $type
  410. * The type of action that is about to be called.
  411. * @param $account
  412. * The account object that was passed via the user hook.
  413. *
  414. * @return
  415. * The object expected by the action that is about to be called.
  416. */
  417. function _trigger_normalize_user_context($type, $account) {
  418. // Note that comment-type actions are not supported in user contexts,
  419. // because we wouldn't know which comment to choose.
  420. switch ($type) {
  421. // An action that works with nodes is being called in a user context.
  422. // If a single node is being viewed, return the node.
  423. case 'node':
  424. // If we are viewing an individual node, return the node.
  425. if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == NULL) {
  426. return node_load(array('nid' => arg(1)));
  427. }
  428. break;
  429. }
  430. }
  431. /**
  432. * Implements hook_user_login().
  433. */
  434. function trigger_user_login(&$edit, $account, $category) {
  435. _trigger_user('user_login', $edit, $account, $category);
  436. }
  437. /**
  438. * Implements hook_user_logout().
  439. */
  440. function trigger_user_logout($account) {
  441. $edit = array();
  442. _trigger_user('user_logout', $edit, $account);
  443. }
  444. /**
  445. * Implements hook_user_insert().
  446. */
  447. function trigger_user_insert(&$edit, $account, $category) {
  448. _trigger_user('user_insert', $edit, $account, $category);
  449. }
  450. /**
  451. * Implements hook_user_update().
  452. */
  453. function trigger_user_update(&$edit, $account, $category) {
  454. _trigger_user('user_update', $edit, $account, $category);
  455. }
  456. /**
  457. * Implements hook_user_cancel().
  458. */
  459. function trigger_user_cancel($edit, $account, $method) {
  460. switch ($method) {
  461. case 'user_cancel_reassign':
  462. _trigger_user('user_delete', $edit, $account, $method);
  463. break;
  464. }
  465. }
  466. /**
  467. * Implements hook_user_delete().
  468. */
  469. function trigger_user_delete($account) {
  470. $edit = array();
  471. _trigger_user('user_delete', $edit, $account, NULL);
  472. }
  473. /**
  474. * Implements hook_user_view().
  475. */
  476. function trigger_user_view($account) {
  477. $edit = NULL;
  478. _trigger_user('user_view', $edit, $account, NULL);
  479. }
  480. /**
  481. * Calls action functions for user triggers.
  482. *
  483. * @param $hook
  484. * The hook that called this function.
  485. * @param $edit
  486. * Edit variable passed in to the hook or empty array if not needed.
  487. * @param $account
  488. * Account variable passed in to the hook.
  489. * @param $method
  490. * Method variable passed in to the hook or NULL if not needed.
  491. */
  492. function _trigger_user($hook, &$edit, $account, $category = NULL) {
  493. // Keep objects for reuse so that changes actions make to objects can persist.
  494. static $objects;
  495. $aids = trigger_get_assigned_actions($hook);
  496. $context = array(
  497. 'group' => 'user',
  498. 'hook' => $hook,
  499. 'form_values' => &$edit,
  500. );
  501. foreach ($aids as $aid => $info) {
  502. $type = $info['type'];
  503. if ($type != 'user') {
  504. if (!isset($objects[$type])) {
  505. $objects[$type] = _trigger_normalize_user_context($type, $account);
  506. }
  507. $context['user'] = $account;
  508. actions_do($aid, $objects[$type], $context);
  509. }
  510. else {
  511. actions_do($aid, $account, $context, $category);
  512. }
  513. }
  514. }
  515. /**
  516. * Calls action functions for taxonomy triggers.
  517. *
  518. * @param $hook
  519. * Hook to trigger actions for taxonomy_term_insert(),
  520. * taxonomy_term_update(), and taxonomy_term_delete().
  521. * @param $array
  522. * Item on which operation is being performed, either a term or
  523. * form values.
  524. */
  525. function _trigger_taxonomy($hook, $array) {
  526. $aids = trigger_get_assigned_actions($hook);
  527. $context = array(
  528. 'group' => 'taxonomy',
  529. 'hook' => $hook
  530. );
  531. actions_do(array_keys($aids), (object) $array, $context);
  532. }
  533. /**
  534. * Implements hook_taxonomy_term_insert().
  535. */
  536. function trigger_taxonomy_term_insert($term) {
  537. _trigger_taxonomy('taxonomy_term_insert', (array) $term);
  538. }
  539. /**
  540. * Implements hook_taxonomy_term_update().
  541. */
  542. function trigger_taxonomy_term_update($term) {
  543. _trigger_taxonomy('taxonomy_term_update', (array) $term);
  544. }
  545. /**
  546. * Implements hook_taxonomy_term_delete().
  547. */
  548. function trigger_taxonomy_term_delete($term) {
  549. _trigger_taxonomy('taxonomy_term_delete', (array) $term);
  550. }
  551. /**
  552. * Implements hook_actions_delete().
  553. *
  554. * Removes all trigger entries for the given action, when an action is deleted.
  555. */
  556. function trigger_actions_delete($aid) {
  557. db_delete('trigger_assignments')
  558. ->condition('aid', $aid)
  559. ->execute();
  560. drupal_static_reset('trigger_get_assigned_actions');
  561. }
  562. /**
  563. * Retrieves and caches information from hook_trigger_info() implementations.
  564. *
  565. * @return
  566. * Array of all triggers.
  567. */
  568. function _trigger_get_all_info() {
  569. $triggers = &drupal_static(__FUNCTION__);
  570. if (!isset($triggers)) {
  571. $triggers = module_invoke_all('trigger_info');
  572. drupal_alter('trigger_info', $triggers);
  573. }
  574. return $triggers;
  575. }
  576. /**
  577. * Gathers information about tabs on the triggers administration screen.
  578. *
  579. * @return
  580. * Array of modules that have triggers, with the keys being the
  581. * machine-readable name of the module, and the values being the
  582. * human-readable name of the module.
  583. */
  584. function _trigger_tab_information() {
  585. // Gather information about all triggers and modules.
  586. $trigger_info = _trigger_get_all_info();
  587. $modules = system_get_info('module');
  588. $modules = array_intersect_key($modules, $trigger_info);
  589. $return_info = array();
  590. foreach ($modules as $name => $info) {
  591. $return_info[$name] = $info['name'];
  592. }
  593. return $return_info;
  594. }
Login or register to post comments