webform_rules.module 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. /**
  3. * @file
  4. * Adds rules integration for webform submissions.
  5. */
  6. /**
  7. * Implements hook_webform_submission_insert().
  8. *
  9. * @param $node
  10. * The webform node.
  11. * @param $submission
  12. * The webform submission.
  13. */
  14. function webform_rules_webform_submission_insert($node, $submission) {
  15. // Invoke event.
  16. webform_rules_rules_invoke_event($submission, $node, 'insert');
  17. }
  18. /**
  19. * Implements hook_webform_submission_update().
  20. *
  21. * @param $node
  22. * The webform node.
  23. * @param $submission
  24. * The webform submission.
  25. */
  26. function webform_rules_webform_submission_update($node, $submission) {
  27. // Invoke event.
  28. webform_rules_rules_invoke_event($submission, $node, 'update');
  29. }
  30. /**
  31. * Implements hook_webform_submission_delete().
  32. *
  33. * @param $node
  34. * The webform node.
  35. * @param $submission
  36. * The webform submission.
  37. */
  38. function webform_rules_webform_submission_delete($node, $submission) {
  39. // Invoke event.
  40. webform_rules_rules_invoke_event($submission, $node, 'delete');
  41. }
  42. /**
  43. * Implements of hook_form_alter().
  44. */
  45. function webform_rules_form_alter(&$form, $form_state, $form_id) {
  46. if (strpos($form_id, 'webform_client_form_') !== FALSE) {
  47. // Add custom submit handler to webform form.
  48. $form['#submit'][] = 'webform_rules_client_form_submit';
  49. }
  50. }
  51. /**
  52. * Custom submit handler for webform submissions.
  53. *
  54. * This is needed to catch submissions of saved webform drafts as
  55. * hook_webform_submission_insert() only fires once and its not possible in
  56. * hook_webform_submission_update() to check if the data has been submitted
  57. * before (e.g. saved as draft).
  58. */
  59. function webform_rules_client_form_submit($form, &$form_state) {
  60. // If the webform is NOT completed, don't run the submit handler!
  61. // This is relevant for multistep forms.
  62. if (!$form_state['webform_completed']) {
  63. return;
  64. }
  65. // If we've got to this point, then we are not mid-way through a form submission.
  66. $values = $form_state['values'];
  67. // Check if user is submitting as a draft.
  68. if ($values['op'] == t('Save Draft')) {
  69. // Saving the webform as draft is handled by hook_webform_submission_insert().
  70. return;
  71. }
  72. if ($form['#is_draft'] && isset($form_state['values']['details']['sid'])) {
  73. $submission = $form['#submission'];
  74. // Map submitted data to submission data.
  75. foreach ($form_state['values']['submitted'] as $cid => $value) {
  76. if (isset($submission->data[$cid])) {
  77. if (isset($value['value'])) {
  78. $submission->data[$cid]['value'] = $value;
  79. }
  80. else {
  81. $submission->data[$cid] = $value;
  82. }
  83. }
  84. }
  85. // Invoke event.
  86. webform_rules_rules_invoke_event($submission, $form['#node'], 'submit');
  87. }
  88. }
  89. /**
  90. * Invoke rules event with submitted data.
  91. *
  92. * @param $submission_data
  93. * Data from webform prepared by webform_submission_data().
  94. * @param $node
  95. * The submitted webform node.
  96. * @param $op
  97. * Type of submission: 'insert', 'update', 'delete', 'submit.
  98. */
  99. function webform_rules_rules_invoke_event($submission, $node, $op = 'insert') {
  100. global $user;
  101. if (!is_array($submission->data) || count($submission->data) == 0) {
  102. return;
  103. }
  104. $is_draft = (isset($submission->is_draft) && $submission->is_draft);
  105. $webform = $node->webform;
  106. $data = array(
  107. 'op' => $op,
  108. 'sid' => $submission->sid,
  109. 'components' => array(),
  110. );
  111. $form_id = 'webform-client-form-' . $webform['nid'];
  112. // Map values to field names.
  113. foreach ($submission->data as $cid => $value) {
  114. $component = $webform['components'][$cid];
  115. $data['components'][$component['form_key']]['value'] = isset($value['value']) ? $value['value'] : $value;
  116. if (!is_array($data['components'][$component['form_key']]['value'])) {
  117. // Convert the value to an array to equalize the data with saved
  118. // submissions.
  119. $data['components'][$component['form_key']]['value'] = array($data['components'][$component['form_key']]['value']);
  120. }
  121. $data['components'][$component['form_key']]['component'] = $component;
  122. }
  123. // Invoke the rules event.
  124. switch ($op) {
  125. case 'insert':
  126. if ($is_draft) {
  127. rules_invoke_event('webform_rules_submit_as_draft', $user, $node, $data, $form_id);
  128. }
  129. else {
  130. rules_invoke_event('webform_rules_submit', $user, $node, $data, $form_id);
  131. }
  132. break;
  133. case 'submit':
  134. rules_invoke_event('webform_rules_insert', $user, $node, $data, $form_id);
  135. break;
  136. case 'update':
  137. rules_invoke_event('webform_rules_update', $user, $node, $data, $form_id);
  138. break;
  139. case 'delete':
  140. rules_invoke_event('webform_rules_delete', $user, $node, $data, $form_id);
  141. break;
  142. }
  143. }
  144. /**
  145. * Implements hook_token_info().
  146. */
  147. function webform_rules_token_info() {
  148. $types['webform'] = array(
  149. 'name' => t('Webform data'),
  150. 'description' => t('Tokens related to data submitted by webforms.'),
  151. );
  152. $webform['sid'] = array(
  153. 'name' => t('Submission Id'),
  154. 'description' => t('The unique identifier of the submission.'),
  155. );
  156. $webform['data'] = array(
  157. 'name' => t('Submitted data'),
  158. 'description' => t('The submitted webform data.'),
  159. );
  160. $webform['data-raw'] = array(
  161. 'name' => t('Raw submitted data'),
  162. 'description' => t('The unfiltered submitted webform data.'),
  163. );
  164. $webform['{component}-title'] = array(
  165. 'name' => t('Component title'),
  166. 'description' => t('The title of the selected component, e.g. "email-title".'),
  167. );
  168. $webform['{component}-value'] = array(
  169. 'name' => t('Component value'),
  170. 'description' => t('The value of the selected component, e.g. "email-value".'),
  171. );
  172. $webform['{component}-value-html'] = array(
  173. 'name' => t('Component value as html'),
  174. 'description' => t('The value of the selected component rendered as html, e.g. "email-value-html".'),
  175. );
  176. $webform['{component}-value-raw'] = array(
  177. 'name' => t('Raw component value'),
  178. 'description' => t('The raw value of the selected component, e.g. "email-value-raw". However this is not cleaned up by check_plain(). This is raw user input so take care if you use this somewhere else.'),
  179. );
  180. $webform['{component}-display'] = array(
  181. 'name' => t('Component display'),
  182. 'description' => t('Title and value of the selected component, e.g. "email-display".'),
  183. );
  184. $webform['{component}-display-html'] = array(
  185. 'name' => t('Component display as html'),
  186. 'description' => t('Title and value of the selected component rendered as html, e.g. "email-display-html".'),
  187. );
  188. return array(
  189. 'types' => $types,
  190. 'tokens' => array(
  191. 'webform' => $webform,
  192. ),
  193. );
  194. }
  195. /**
  196. * Implements hook_tokens().
  197. */
  198. function webform_rules_tokens($type, $tokens, array $data = array(), array $options = array()) {
  199. $replacements = array();
  200. if ($type == 'webform') {
  201. $component_names = array_keys($data[$type]['components']);
  202. foreach ($tokens as $name => $original) {
  203. if ($name == 'sid') {
  204. $replacements[$original] = $data[$type]['sid'];
  205. }
  206. elseif ($name == 'data') {
  207. $replacements[$original] = webform_rules_prepare_component_value($data[$type]);
  208. }
  209. elseif ($name == 'data-raw') {
  210. $replacements[$original] = webform_rules_prepare_component_value($data[$type], TRUE);
  211. }
  212. else {
  213. // Split token name to get the components name.
  214. $token = explode('-', $name);
  215. $component_name = array_shift($token);
  216. if (!in_array($component_name, $component_names)) {
  217. continue;
  218. }
  219. // Join token name (without component name).
  220. $token = implode('-', $token);
  221. // Webform component.
  222. $component = $data[$type]['components'][$component_name]['component'];
  223. $component_value = $data[$type]['components'][$component_name]['value'];
  224. switch ($token) {
  225. case 'title':
  226. $replacements[$original] = $component['name'];
  227. break;
  228. case 'display':
  229. $replacements[$original] = webform_rules_render_component($component, $component_value);
  230. break;
  231. case 'display-html':
  232. $replacements[$original] = webform_rules_render_component($component, $component_value, 'html');
  233. break;
  234. case 'value':
  235. $replacements[$original] = webform_rules_render_component($component, $component_value, 'text', FALSE);
  236. break;
  237. case 'value-html':
  238. $replacements[$original] = webform_rules_render_component($component, $component_value, 'html', FALSE);
  239. break;
  240. case 'value-raw':
  241. $replacements[$original] = webform_rules_prepare_component_value($component_value, TRUE);
  242. break;
  243. }
  244. }
  245. }
  246. }
  247. return $replacements;
  248. }
  249. /**
  250. * Prepare component value for output.
  251. * Code adapted from drupal_to_js().
  252. *
  253. * @param $component_value
  254. * Value of submitted component.
  255. * @param $raw
  256. * If TRUE, leave all values unfiltered.
  257. */
  258. function webform_rules_prepare_component_value($component_value, $raw = FALSE) {
  259. switch (gettype($component_value)) {
  260. case 'boolean':
  261. return $component_value ? 'true' : 'false'; // Lowercase necessary!
  262. case 'integer':
  263. case 'double':
  264. return $component_value;
  265. case 'resource':
  266. case 'string':
  267. return $raw ? $component_value : check_plain($component_value);
  268. case 'array':
  269. // If the array is empty or if it has sequential whole number keys
  270. // starting with 0, it's not associative so we can go ahead and
  271. // convert it as an array.
  272. if (empty($component_value) || array_keys($component_value) === range(0, sizeof($component_value) - 1)) {
  273. $output = array();
  274. foreach ($component_value as $v) {
  275. $output[] = webform_rules_prepare_component_value($v, $raw);
  276. }
  277. return implode(', ', $output);
  278. }
  279. // Otherwise, fall through to convert the array as an object.
  280. // This is usefull for more readable output.
  281. case 'object':
  282. $output = array();
  283. foreach ($component_value as $k => $v) {
  284. $output[] = webform_rules_prepare_component_value(strval($k), $raw) . ': ' . webform_rules_prepare_component_value($v, $raw);
  285. }
  286. return implode(', ', $output);
  287. default:
  288. return 'null';
  289. }
  290. }
  291. /**
  292. * Render value of component.
  293. *
  294. * @param $component
  295. * Webform component to render.
  296. * @param $value
  297. * Submitted value of webform component.
  298. * @param $format
  299. * How to render the components value ('html' or 'text'). Defaults to 'text'.
  300. * @param $title
  301. * Renders the component title if set to TRUE.
  302. *
  303. * @return
  304. * The rendered component value.
  305. */
  306. function webform_rules_render_component($component, $value, $format = 'text', $title = TRUE) {
  307. if ($format != 'text') {
  308. $format = 'html';
  309. }
  310. $display_element = webform_component_invoke($component['type'], 'display', $component, $value, $format);
  311. $display_element['#parents'] = array('submitted', $component['form_key']);
  312. if (!isset($display_element['#id'])) {
  313. $display_element['#id'] = drupal_clean_css_identifier('edit-' . implode('-', $display_element['#parents']));
  314. }
  315. if (!$title) {
  316. $display_element['#title'] = NULL;
  317. }
  318. if (!isset($display_element['#webform_component'])) {
  319. $display_element['#webform_component'] = $component;
  320. }
  321. return drupal_render($display_element);
  322. }