1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * Sample hooks demonstrating usage in Webform. |
---|
6 | */ |
---|
7 | |
---|
8 | /** |
---|
9 | * @defgroup webform_hooks Webform Module Hooks |
---|
10 | * @{ |
---|
11 | * Webform's hooks enable other modules to intercept events within Webform, such |
---|
12 | * as the completion of a submission or adding validation. Webform's hooks also |
---|
13 | * allow other modules to provide additional components for use within forms. |
---|
14 | */ |
---|
15 | |
---|
16 | /** |
---|
17 | * Define callbacks that can be used as select list options. |
---|
18 | * |
---|
19 | * When users create a select component, they may select a pre-built list of |
---|
20 | * certain options. Webform core provides a few of these lists such as the |
---|
21 | * United States, countries of the world, and days of the week. This hook |
---|
22 | * provides additional lists that may be utilized. |
---|
23 | * |
---|
24 | * @see webform_options_example() |
---|
25 | * @see hook_webform_select_options_info_alter() |
---|
26 | * |
---|
27 | * @return |
---|
28 | * An array of callbacks that can be used for select list options. This array |
---|
29 | * should be keyed by the "name" of the pre-defined list. The values should |
---|
30 | * be an array with the following additional keys: |
---|
31 | * - title: The translated title for this list. |
---|
32 | * - options callback: The name of the function that will return the list. |
---|
33 | * - options arguments: Any additional arguments to send to the callback. |
---|
34 | * - file: Optional. The file containing the options callback, relative to |
---|
35 | * the module root. |
---|
36 | */ |
---|
37 | function hook_webform_select_options_info() { |
---|
38 | $items = array(); |
---|
39 | |
---|
40 | $items['days'] = array( |
---|
41 | 'title' => t('Days of the week'), |
---|
42 | 'options callback' => 'webform_options_days', |
---|
43 | 'file' => 'includes/webform.options.inc', |
---|
44 | ); |
---|
45 | |
---|
46 | return $items; |
---|
47 | } |
---|
48 | |
---|
49 | /** |
---|
50 | * Alter the list of select list options provided by Webform and other modules. |
---|
51 | * |
---|
52 | * @see hook_webform_select_options_info(). |
---|
53 | */ |
---|
54 | function hook_webform_select_options_info_alter(&$items) { |
---|
55 | // Remove the days of the week options. |
---|
56 | unset($items['days']); |
---|
57 | } |
---|
58 | |
---|
59 | /** |
---|
60 | * This is an example function to demonstrate a webform options callback. |
---|
61 | * |
---|
62 | * This function returns a list of options that Webform may use in a select |
---|
63 | * component. In order to be called, the function name |
---|
64 | * ("webform_options_example" in this case), needs to be specified as a callback |
---|
65 | * in hook_webform_select_options_info(). |
---|
66 | * |
---|
67 | * @param $component |
---|
68 | * The Webform component array for the select component being displayed. |
---|
69 | * @param $flat |
---|
70 | * Boolean value indicating whether the returned list needs to be a flat array |
---|
71 | * of key => value pairs. Select components support up to one level of |
---|
72 | * nesting, but when results are displayed, the list needs to be returned |
---|
73 | * without the nesting. |
---|
74 | * @param $filter |
---|
75 | * Boolean value indicating whether the included options should be passed |
---|
76 | * through the _webform_filter_values() function for token replacement (only) |
---|
77 | * needed if your list contains tokens). |
---|
78 | * @param $arguments |
---|
79 | * The "options arguments" specified in hook_webform_select_options_info(). |
---|
80 | * @return |
---|
81 | * An array of key => value pairs suitable for a select list's #options |
---|
82 | * FormAPI property. |
---|
83 | */ |
---|
84 | function webform_options_example($component, $flat, $filter, $arguments) { |
---|
85 | $options = array( |
---|
86 | 'one' => t('Pre-built option one'), |
---|
87 | 'two' => t('Pre-built option two'), |
---|
88 | 'three' => t('Pre-built option three'), |
---|
89 | ); |
---|
90 | |
---|
91 | return $options; |
---|
92 | } |
---|
93 | |
---|
94 | /** |
---|
95 | * Respond to the loading of Webform submissions. |
---|
96 | * |
---|
97 | * @param $submissions |
---|
98 | * An array of Webform submissions that are being loaded, keyed by the |
---|
99 | * submission ID. Modifications to the submissions are done by reference. |
---|
100 | */ |
---|
101 | function hook_webform_submission_load(&$submissions) { |
---|
102 | foreach ($submissions as $sid => $submission) { |
---|
103 | $submissions[$sid]->new_property = 'foo'; |
---|
104 | } |
---|
105 | } |
---|
106 | |
---|
107 | /** |
---|
108 | * Modify a Webform submission, prior to saving it in the database. |
---|
109 | * |
---|
110 | * @param $node |
---|
111 | * The Webform node on which this submission was made. |
---|
112 | * @param $submission |
---|
113 | * The Webform submission that is about to be saved to the database. |
---|
114 | */ |
---|
115 | function hook_webform_submission_presave($node, &$submission) { |
---|
116 | // Update some component's value before it is saved. |
---|
117 | $component_id = 4; |
---|
118 | $submission->data[$component_id]['value'][0] = 'foo'; |
---|
119 | } |
---|
120 | |
---|
121 | /** |
---|
122 | * Respond to a Webform submission being inserted. |
---|
123 | * |
---|
124 | * Note that this hook is called after a submission has already been saved to |
---|
125 | * the database. If needing to modify the submission prior to insertion, use |
---|
126 | * hook_webform_submission_presave(). |
---|
127 | * |
---|
128 | * @param $node |
---|
129 | * The Webform node on which this submission was made. |
---|
130 | * @param $submission |
---|
131 | * The Webform submission that was just inserted into the database. |
---|
132 | */ |
---|
133 | function hook_webform_submission_insert($node, $submission) { |
---|
134 | // Insert a record into a 3rd-party module table when a submission is added. |
---|
135 | db_query("INSERT INTO {mymodule_table} nid = %d, sid = %d, foo = '%s'", $node->nid, $submission->sid, 'foo_data'); |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * Respond to a Webform submission being updated. |
---|
140 | * |
---|
141 | * Note that this hook is called after a submission has already been saved to |
---|
142 | * the database. If needing to modify the submission prior to updating, use |
---|
143 | * hook_webform_submission_presave(). |
---|
144 | * |
---|
145 | * @param $node |
---|
146 | * The Webform node on which this submission was made. |
---|
147 | * @param $submission |
---|
148 | * The Webform submission that was just updated in the database. |
---|
149 | */ |
---|
150 | function hook_webform_submission_update($node, $submission) { |
---|
151 | // Update a record in a 3rd-party module table when a submission is updated. |
---|
152 | db_query("UPDATE {mymodule_table} SET (foo) VALUES ('%s') WHERE nid = %d, sid = %d", 'foo_data', $node->nid, $submission->sid); |
---|
153 | } |
---|
154 | |
---|
155 | /** |
---|
156 | * Respond to a Webform submission being deleted. |
---|
157 | * |
---|
158 | * @param $node |
---|
159 | * The Webform node on which this submission was made. |
---|
160 | * @param $submission |
---|
161 | * The Webform submission that was just deleted from the database. |
---|
162 | */ |
---|
163 | function hook_webform_submission_delete($node, $submission) { |
---|
164 | // Delete a record from a 3rd-party module table when a submission is deleted. |
---|
165 | db_query("DELETE FROM {mymodule_table} WHERE nid = %d, sid = %d", $node->nid, $submission->sid); |
---|
166 | } |
---|
167 | |
---|
168 | /** |
---|
169 | * Provide a list of actions that can be executed on a submission. |
---|
170 | * |
---|
171 | * Some actions are displayed in the list of submissions such as edit, view, and |
---|
172 | * delete. All other actions are displayed only when viewing the submission. |
---|
173 | * These additional actions may be specified in this hook. Examples included |
---|
174 | * directly in the Webform module include PDF, print, and resend e-mails. Other |
---|
175 | * modules may extend this list by using this hook. |
---|
176 | * |
---|
177 | * @param $node |
---|
178 | * The Webform node on which this submission was made. |
---|
179 | * @param $submission |
---|
180 | * The Webform submission on which the actions may be performed. |
---|
181 | */ |
---|
182 | function hook_webform_submission_actions($node, $submission) { |
---|
183 | if (webform_results_access($node)) { |
---|
184 | $actions['myaction'] = array( |
---|
185 | 'title' => t('Do my action'), |
---|
186 | 'href' => 'node/' . $node->nid . '/submission/' . $submission->sid . '/myaction', |
---|
187 | 'query' => drupal_get_destination(), |
---|
188 | ); |
---|
189 | } |
---|
190 | |
---|
191 | return $actions; |
---|
192 | } |
---|
193 | |
---|
194 | /** |
---|
195 | * Alter the display of a Webform submission. |
---|
196 | * |
---|
197 | * This function applies to both e-mails sent by Webform and normal display of |
---|
198 | * submissions when viewing through the adminsitrative interface. |
---|
199 | * |
---|
200 | * @param $renderable |
---|
201 | * The Webform submission in a renderable array, similar to FormAPI's |
---|
202 | * structure. This variable must be passed in by-reference. Important |
---|
203 | * properties of this array include #node, #submission, #email, and #format, |
---|
204 | * which can be used to find the context of the submission that is being |
---|
205 | * rendered. |
---|
206 | */ |
---|
207 | function hook_webform_submission_render_alter(&$renderable) { |
---|
208 | // Remove page breaks from sent e-mails. |
---|
209 | if (isset($renderable['#email'])) { |
---|
210 | foreach (element_children($renderable) as $key) { |
---|
211 | if ($renderable[$key]['#component']['type'] == 'pagebreak') { |
---|
212 | unset($renderable[$key]); |
---|
213 | } |
---|
214 | } |
---|
215 | } |
---|
216 | } |
---|
217 | |
---|
218 | /** |
---|
219 | * Modify a loaded Webform component. |
---|
220 | * |
---|
221 | * IMPORTANT: This hook does not actually exist because components are loaded |
---|
222 | * in bulk as part of webform_node_load(). Use hook_nodeapi() to modify loaded |
---|
223 | * components when the node is loaded. This example is provided merely to point |
---|
224 | * to hook_nodeapi(). |
---|
225 | * |
---|
226 | * @see hook_nodeapi() |
---|
227 | * @see webform_node_load() |
---|
228 | */ |
---|
229 | function hook_webform_component_load() { |
---|
230 | // This hook does not exist. Instead use hook_nodeapi(). |
---|
231 | } |
---|
232 | |
---|
233 | /** |
---|
234 | * Modify a Webform component before it is saved to the database. |
---|
235 | * |
---|
236 | * Note that most of the time this hook is not necessary, because Webform will |
---|
237 | * automatically add data to the component based on the component form. Using |
---|
238 | * hook_form_alter() will be sufficient in most cases. |
---|
239 | * |
---|
240 | * @see hook_form_alter() |
---|
241 | * @see webform_component_edit_form() |
---|
242 | * |
---|
243 | * @param $component |
---|
244 | * The Webform component being saved. |
---|
245 | */ |
---|
246 | function hook_webform_component_presave(&$component) { |
---|
247 | $component['extra']['new_option'] = 'foo'; |
---|
248 | } |
---|
249 | |
---|
250 | /** |
---|
251 | * Respond to a Webform component being inserted into the database. |
---|
252 | */ |
---|
253 | function hook_webform_component_insert($component) { |
---|
254 | // Insert a record into a 3rd-party module table when a component is inserted. |
---|
255 | db_query("INSERT INTO {mymodule_table} (nid, cid) VALUES (%d, %d)", $component['nid'], $component['cid']); |
---|
256 | } |
---|
257 | |
---|
258 | /** |
---|
259 | * Respond to a Webform component being updated in the database. |
---|
260 | */ |
---|
261 | function hook_webform_component_update($component) { |
---|
262 | // Update a record in a 3rd-party module table when a component is updated. |
---|
263 | db_query('UPDATE {mymodule_table} SET value "%s" WHERE nid = %d AND cid = %d)', 'foo', $component['nid'], $component['cid']); |
---|
264 | } |
---|
265 | |
---|
266 | /** |
---|
267 | * Respond to a Webform component being deleted. |
---|
268 | */ |
---|
269 | function hook_webform_component_delete($component) { |
---|
270 | // Delete a record in a 3rd-party module table when a component is deleted. |
---|
271 | db_query('DELETE FROM {mymodule_table} WHERE nid = %d AND cid = %d)', $component['nid'], $component['cid']); |
---|
272 | } |
---|
273 | |
---|
274 | /** |
---|
275 | * Alter a Webform submission's header when exported. |
---|
276 | */ |
---|
277 | function hook_webform_csv_header_alter(&$header, $component) { |
---|
278 | // Use the machine name for component headers, but only for the webform |
---|
279 | // with node 5 and components that are text fields. |
---|
280 | if ($component['nid'] == 5 && $component['type'] == 'textfield') { |
---|
281 | $header[2] = $component['form_key']; |
---|
282 | } |
---|
283 | } |
---|
284 | |
---|
285 | /** |
---|
286 | * Alter a Webform submission's data when exported. |
---|
287 | */ |
---|
288 | function hook_webform_csv_data_alter(&$data, $component, $submission) { |
---|
289 | // If a value of a field was left blank, use the value from another |
---|
290 | // field. |
---|
291 | if ($component['cid'] == 1 && empty($data)) { |
---|
292 | $data = $submission->data[2]['value'][0]; |
---|
293 | } |
---|
294 | } |
---|
295 | |
---|
296 | /** |
---|
297 | * Define components to Webform. |
---|
298 | * |
---|
299 | * @return |
---|
300 | * An array of components, keyed by machine name. Required properties are |
---|
301 | * "label" and "description". The "features" array defines which capabilities |
---|
302 | * the component has, such as being displayed in e-mails or csv downloads. |
---|
303 | * A component like "markup" for example would not show in these locations. |
---|
304 | * The possible features of a component include: |
---|
305 | * |
---|
306 | * - csv |
---|
307 | * - email |
---|
308 | * - email_address |
---|
309 | * - email_name |
---|
310 | * - required |
---|
311 | * - conditional |
---|
312 | * - spam_analysis |
---|
313 | * - group |
---|
314 | * |
---|
315 | * Note that most of these features do not indicate the default state, but |
---|
316 | * determine if the component can have this property at all. Setting |
---|
317 | * "required" to TRUE does not mean that a component's fields will always be |
---|
318 | * required, but instead give the option to the administrator to choose the |
---|
319 | * requiredness. See the example implementation for details on how these |
---|
320 | * features may be set. |
---|
321 | * |
---|
322 | * An optional "file" may be specified to be loaded when the component is |
---|
323 | * needed. A set of callbacks will be established based on the name of the |
---|
324 | * component. All components follow the pattern: |
---|
325 | * |
---|
326 | * _webform_[callback]_[component] |
---|
327 | * |
---|
328 | * Where [component] is the name of the key of the component and [callback] is |
---|
329 | * any of the following: |
---|
330 | * |
---|
331 | * - defaults |
---|
332 | * - edit |
---|
333 | * - render |
---|
334 | * - display |
---|
335 | * - submit |
---|
336 | * - delete |
---|
337 | * - help |
---|
338 | * - theme |
---|
339 | * - analysis |
---|
340 | * - table |
---|
341 | * - csv_headers |
---|
342 | * - csv_data |
---|
343 | * |
---|
344 | * See the sample component implementation for details on each one of these |
---|
345 | * callbacks. |
---|
346 | * |
---|
347 | * @see webform_components() |
---|
348 | */ |
---|
349 | function hook_webform_component_info() { |
---|
350 | $components = array(); |
---|
351 | |
---|
352 | $components['textfield'] = array( |
---|
353 | 'label' => t('Textfield'), |
---|
354 | 'description' => t('Basic textfield type.'), |
---|
355 | 'features' => array( |
---|
356 | // Add content to CSV downloads. Defaults to TRUE. |
---|
357 | 'csv' => TRUE, |
---|
358 | |
---|
359 | // This component supports default values. Defaults to TRUE. |
---|
360 | 'default_value' => FALSE, |
---|
361 | |
---|
362 | // This component supports a description field. Defaults to TRUE. |
---|
363 | 'description' => FALSE, |
---|
364 | |
---|
365 | // Show this component in e-mailed submissions. Defaults to TRUE. |
---|
366 | 'email' => TRUE, |
---|
367 | |
---|
368 | // Allow this component to be used as an e-mail FROM or TO address. |
---|
369 | // Defaults to FALSE. |
---|
370 | 'email_address' => FALSE, |
---|
371 | |
---|
372 | // Allow this component to be used as an e-mail SUBJECT or FROM name. |
---|
373 | // Defaults to FALSE. |
---|
374 | 'email_name' => TRUE, |
---|
375 | |
---|
376 | // This component may be toggled as required or not. Defaults to TRUE. |
---|
377 | 'required' => TRUE, |
---|
378 | |
---|
379 | // This component supports a title attribute. Defaults to TRUE. |
---|
380 | 'title' => FALSE, |
---|
381 | |
---|
382 | // This component has a title that can be toggled as displayed or not. |
---|
383 | 'title_display' => TRUE, |
---|
384 | |
---|
385 | // This component has a title that can be displayed inline. |
---|
386 | 'title_inline' => TRUE, |
---|
387 | |
---|
388 | // If this component can be used as a conditional SOURCE. All components |
---|
389 | // may always be displayed conditionally, regardless of this setting. |
---|
390 | // Defaults to TRUE. |
---|
391 | 'conditional' => TRUE, |
---|
392 | |
---|
393 | // If this component allows other components to be grouped within it |
---|
394 | // (like a fieldset or tabs). Defaults to FALSE. |
---|
395 | 'group' => FALSE, |
---|
396 | |
---|
397 | // If this component can be used for SPAM analysis, usually with Mollom. |
---|
398 | 'spam_analysis' => FALSE, |
---|
399 | |
---|
400 | // If this component saves a file that can be used as an e-mail |
---|
401 | // attachment. Defaults to FALSE. |
---|
402 | 'attachment' => FALSE, |
---|
403 | ), |
---|
404 | 'file' => 'components/textfield.inc', |
---|
405 | ); |
---|
406 | |
---|
407 | return $components; |
---|
408 | } |
---|
409 | |
---|
410 | /** |
---|
411 | * Alter the list of available Webform components. |
---|
412 | * |
---|
413 | * @param $components |
---|
414 | * A list of existing components as defined by hook_webform_component_info(). |
---|
415 | * |
---|
416 | * @see hook_webform_component_info() |
---|
417 | */ |
---|
418 | function hook_webform_component_info_alter(&$components) { |
---|
419 | // Completely remove a component. |
---|
420 | unset($components['grid']); |
---|
421 | |
---|
422 | // Change the name of a component. |
---|
423 | $components['textarea']['label'] = t('Text box'); |
---|
424 | } |
---|
425 | |
---|
426 | /** |
---|
427 | * Alter the list of Webform component default values. |
---|
428 | * |
---|
429 | * @param $defaults |
---|
430 | * A list of component defaults as defined by _webform_defaults_COMPONENT(). |
---|
431 | * @param $type |
---|
432 | * The component type whose defaults are being provided. |
---|
433 | * |
---|
434 | * @see _webform_defaults_component() |
---|
435 | */ |
---|
436 | function hook_webform_component_defaults_alter(&$defaults, $type) { |
---|
437 | // Alter a default for all component types. |
---|
438 | $defaults['mandatory'] = 1; |
---|
439 | |
---|
440 | // Add a default for a new field added via hook_form_alter() or |
---|
441 | // hook_form_FORM_ID_alter() for all component types. |
---|
442 | $defaults['extra']['added_field'] = t('Added default value'); |
---|
443 | |
---|
444 | // Add or alter defaults for specific component types: |
---|
445 | switch ($type) { |
---|
446 | case 'select': |
---|
447 | $defaults['extra']['optrand'] = 1; |
---|
448 | break; |
---|
449 | |
---|
450 | case 'textfield': |
---|
451 | case 'textarea': |
---|
452 | $defaults['extra']['another_added_field'] = t('Another added default value'); |
---|
453 | } |
---|
454 | } |
---|
455 | |
---|
456 | /** |
---|
457 | * Alter access to a Webform submission. |
---|
458 | * |
---|
459 | * @param $node |
---|
460 | * The Webform node on which this submission was made. |
---|
461 | * @param $submission |
---|
462 | * The Webform submission. |
---|
463 | * @param $op |
---|
464 | * The operation to be performed on the submission. Possible values are: |
---|
465 | * - "view" |
---|
466 | * - "edit" |
---|
467 | * - "delete" |
---|
468 | * - "list" |
---|
469 | * @param $account |
---|
470 | * A user account object. |
---|
471 | * @return |
---|
472 | * TRUE if the current user has access to submission, |
---|
473 | * or FALSE otherwise. |
---|
474 | */ |
---|
475 | function hook_webform_submission_access($node, $submission, $op = 'view', $account = NULL) { |
---|
476 | switch ($op) { |
---|
477 | case 'view': |
---|
478 | return TRUE; |
---|
479 | break; |
---|
480 | case 'edit': |
---|
481 | return FALSE; |
---|
482 | break; |
---|
483 | case 'delete': |
---|
484 | return TRUE; |
---|
485 | break; |
---|
486 | case 'list': |
---|
487 | return TRUE; |
---|
488 | break; |
---|
489 | } |
---|
490 | } |
---|
491 | |
---|
492 | /** |
---|
493 | * Determine if a user has access to see the results of a webform. |
---|
494 | * |
---|
495 | * Note in addition to the view access to the results granted here, the $account |
---|
496 | * must also have view access to the Webform node in order to see results. |
---|
497 | * |
---|
498 | * @see webform_results_access(). |
---|
499 | * |
---|
500 | * @param $node |
---|
501 | * The Webform node to check access on. |
---|
502 | * @param $account |
---|
503 | * The user account to check access on. |
---|
504 | * @return |
---|
505 | * TRUE or FALSE if the user can access the webform results. |
---|
506 | */ |
---|
507 | function hook_webform_results_access($node, $account) { |
---|
508 | // Let editors view results of unpublished webforms. |
---|
509 | if ($node->status == 0 && in_array('editor', $account->roles)) { |
---|
510 | return TRUE; |
---|
511 | } |
---|
512 | else { |
---|
513 | return FALSE; |
---|
514 | } |
---|
515 | } |
---|
516 | |
---|
517 | /** |
---|
518 | * Return an array of files associated with the component. |
---|
519 | * |
---|
520 | * The output of this function will be used to attach files to e-mail messages. |
---|
521 | * |
---|
522 | * @param $component |
---|
523 | * A Webform component array. |
---|
524 | * @param $value |
---|
525 | * An array of information containing the submission result, directly |
---|
526 | * correlating to the webform_submitted_data database schema. |
---|
527 | * @return |
---|
528 | * An array of files, each file is an array with following keys: |
---|
529 | * - filepath: The relative path to the file. |
---|
530 | * - filename: The name of the file including the extension. |
---|
531 | * - filemime: The mimetype of the file. |
---|
532 | * This will result in an array looking something like this: |
---|
533 | * @code |
---|
534 | * array[0] => array( |
---|
535 | * 'filepath' => '/sites/default/files/attachment.txt', |
---|
536 | * 'filename' => 'attachment.txt', |
---|
537 | * 'filemime' => 'text/plain', |
---|
538 | * ); |
---|
539 | * @endcode |
---|
540 | */ |
---|
541 | function _webform_attachments_component($component, $value) { |
---|
542 | $files = array(); |
---|
543 | $files[] = db_fetch_array(db_query("SELECT * FROM {files} WHERE fid = %d", $value[0])); |
---|
544 | return $files; |
---|
545 | } |
---|
546 | |
---|
547 | |
---|
548 | /** |
---|
549 | * @} |
---|
550 | */ |
---|
551 | |
---|
552 | /** |
---|
553 | * @defgroup webform_component Sample Webform Component |
---|
554 | * @{ |
---|
555 | * In each of these examples, the word "component" should be replaced with the, |
---|
556 | * name of the component type (such as textfield or select). These are not |
---|
557 | * actual hooks, but instead samples of how Webform integrates with its own |
---|
558 | * built-in components. |
---|
559 | */ |
---|
560 | |
---|
561 | /** |
---|
562 | * Specify the default properties of a component. |
---|
563 | * |
---|
564 | * @return |
---|
565 | * An array defining the default structure of a component. |
---|
566 | */ |
---|
567 | function _webform_defaults_component() { |
---|
568 | return array( |
---|
569 | 'name' => '', |
---|
570 | 'form_key' => NULL, |
---|
571 | 'mandatory' => 0, |
---|
572 | 'pid' => 0, |
---|
573 | 'weight' => 0, |
---|
574 | 'extra' => array( |
---|
575 | 'options' => '', |
---|
576 | 'questions' => '', |
---|
577 | 'optrand' => 0, |
---|
578 | 'qrand' => 0, |
---|
579 | 'description' => '', |
---|
580 | ), |
---|
581 | ); |
---|
582 | } |
---|
583 | |
---|
584 | /** |
---|
585 | * Generate the form for editing a component. |
---|
586 | * |
---|
587 | * Create a set of form elements to be displayed on the form for editing this |
---|
588 | * component. Use care naming the form items, as this correlates directly to the |
---|
589 | * database schema. The component "Name" and "Description" fields are added to |
---|
590 | * every component type and are not necessary to specify here (although they |
---|
591 | * may be overridden if desired). |
---|
592 | * |
---|
593 | * @param $component |
---|
594 | * A Webform component array. |
---|
595 | * @return |
---|
596 | * An array of form items to be displayed on the edit component page |
---|
597 | */ |
---|
598 | function _webform_edit_component($component) { |
---|
599 | $form = array(); |
---|
600 | |
---|
601 | // Disabling the description if not wanted. |
---|
602 | $form['description'] = array(); |
---|
603 | |
---|
604 | // Most options are stored in the "extra" array, which stores any settings |
---|
605 | // unique to a particular component type. |
---|
606 | $form['extra']['options'] = array( |
---|
607 | '#type' => 'textarea', |
---|
608 | '#title' => t('Options'), |
---|
609 | '#default_value' => $component['extra']['options'], |
---|
610 | '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'), |
---|
611 | '#cols' => 60, |
---|
612 | '#rows' => 5, |
---|
613 | '#weight' => -3, |
---|
614 | '#required' => TRUE, |
---|
615 | ); |
---|
616 | return $form; |
---|
617 | } |
---|
618 | |
---|
619 | /** |
---|
620 | * Render a Webform component to be part of a form. |
---|
621 | * |
---|
622 | * @param $component |
---|
623 | * A Webform component array. |
---|
624 | * @param $value |
---|
625 | * If editing an existing submission or resuming a draft, this will contain |
---|
626 | * an array of values to be shown instead of the default in the component |
---|
627 | * configuration. This value will always be an array, keyed numerically for |
---|
628 | * each value saved in this field. |
---|
629 | * @param $filter |
---|
630 | * Whether or not to filter the contents of descriptions and values when |
---|
631 | * rendering the component. Values need to be unfiltered to be editable by |
---|
632 | * Form Builder. |
---|
633 | * |
---|
634 | * @see _webform_client_form_add_component() |
---|
635 | */ |
---|
636 | function _webform_render_component($component, $value = NULL) { |
---|
637 | $form_item = array( |
---|
638 | '#type' => 'textfield', |
---|
639 | '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'], |
---|
640 | '#required' => $component['mandatory'], |
---|
641 | '#weight' => $component['weight'], |
---|
642 | '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'], |
---|
643 | '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'], |
---|
644 | '#prefix' => '<div class="webform-component-' . $component['type'] . '" id="webform-component-' . $component['form_key'] . '">', |
---|
645 | '#suffix' => '</div>', |
---|
646 | ); |
---|
647 | |
---|
648 | if (isset($value)) { |
---|
649 | $form_item['#default_value'] = $value[0]; |
---|
650 | } |
---|
651 | |
---|
652 | return $form_item; |
---|
653 | } |
---|
654 | |
---|
655 | /** |
---|
656 | * Display the result of a submission for a component. |
---|
657 | * |
---|
658 | * The output of this function will be displayed under the "Results" tab then |
---|
659 | * "Submissions". This should output the saved data in some reasonable manner. |
---|
660 | * |
---|
661 | * @param $component |
---|
662 | * A Webform component array. |
---|
663 | * @param $value |
---|
664 | * An array of information containing the submission result, directly |
---|
665 | * correlating to the webform_submitted_data database table schema. |
---|
666 | * @param $format |
---|
667 | * Either 'html' or 'text'. Defines the format that the content should be |
---|
668 | * returned as. Make sure that returned content is run through check_plain() |
---|
669 | * or other filtering functions when returning HTML. |
---|
670 | * @return |
---|
671 | * A renderable element containing at the very least these properties: |
---|
672 | * - #title |
---|
673 | * - #weight |
---|
674 | * - #component |
---|
675 | * - #format |
---|
676 | * - #value |
---|
677 | * Webform also uses #theme_wrappers to output the end result to the user, |
---|
678 | * which will properly format the label and content for use within an e-mail |
---|
679 | * (such as wrapping the text) or as HTML (ensuring consistent output). |
---|
680 | */ |
---|
681 | function _webform_display_component($component, $value, $format = 'html') { |
---|
682 | return array( |
---|
683 | '#title' => $component['name'], |
---|
684 | '#weight' => $component['weight'], |
---|
685 | '#theme' => 'webform_display_textfield', |
---|
686 | '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'), |
---|
687 | '#post_render' => array('webform_element_wrapper'), |
---|
688 | '#field_prefix' => $component['extra']['field_prefix'], |
---|
689 | '#field_suffix' => $component['extra']['field_suffix'], |
---|
690 | '#component' => $component, |
---|
691 | '#format' => $format, |
---|
692 | '#value' => isset($value[0]) ? $value[0] : '', |
---|
693 | ); |
---|
694 | } |
---|
695 | |
---|
696 | /** |
---|
697 | * A hook for changing the input values before saving to the database. |
---|
698 | * |
---|
699 | * Webform expects a component to consist of a single field, or a single array |
---|
700 | * of fields. If you have a component that requires a deeper form tree |
---|
701 | * you must flatten the data into a single array using this callback |
---|
702 | * or by setting #parents on each field to avoid data loss and/or unexpected |
---|
703 | * behavior. |
---|
704 | * |
---|
705 | * Note that Webform will save the result of this function directly into the |
---|
706 | * database. |
---|
707 | * |
---|
708 | * @param $component |
---|
709 | * A Webform component array. |
---|
710 | * @param $value |
---|
711 | * The POST data associated with the user input. |
---|
712 | * @return |
---|
713 | * An array of values to be saved into the database. Note that this should be |
---|
714 | * a numerically keyed array. |
---|
715 | */ |
---|
716 | function _webform_submit_component($component, $value) { |
---|
717 | // Clean up a phone number into 123-456-7890 format. |
---|
718 | if ($component['extra']['phone_number']) { |
---|
719 | $matches = array(); |
---|
720 | $number = preg_replace('[^0-9]', $value[0]); |
---|
721 | if (strlen($number) == 7) { |
---|
722 | $number = substr($number, 0, 3) . '-' . substr($number, 3, 4); |
---|
723 | } |
---|
724 | else { |
---|
725 | $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4); |
---|
726 | } |
---|
727 | } |
---|
728 | |
---|
729 | $value[0] = $number; |
---|
730 | return $value; |
---|
731 | } |
---|
732 | |
---|
733 | /** |
---|
734 | * Delete operation for a component or submission. |
---|
735 | * |
---|
736 | * @param $component |
---|
737 | * A Webform component array. |
---|
738 | * @param $value |
---|
739 | * An array of information containing the submission result, directly |
---|
740 | * correlating to the webform_submitted_data database schema. |
---|
741 | */ |
---|
742 | function _webform_delete_component($component, $value) { |
---|
743 | // Delete corresponding files when a submission is deleted. |
---|
744 | $filedata = unserialize($value['0']); |
---|
745 | if (isset($filedata['filepath']) && is_file($filedata['filepath'])) { |
---|
746 | unlink($filedata['filepath']); |
---|
747 | db_query("DELETE FROM {files} WHERE filepath = '%s'", $filedata['filepath']); |
---|
748 | } |
---|
749 | } |
---|
750 | |
---|
751 | /** |
---|
752 | * Module specific instance of hook_help(). |
---|
753 | * |
---|
754 | * This allows each Webform component to add information into hook_help(). |
---|
755 | */ |
---|
756 | function _webform_help_component($section) { |
---|
757 | switch ($section) { |
---|
758 | case 'admin/settings/webform#grid_description': |
---|
759 | return t('Allows creation of grid questions, denoted by radio buttons.'); |
---|
760 | } |
---|
761 | } |
---|
762 | |
---|
763 | /** |
---|
764 | * Module specific instance of hook_theme(). |
---|
765 | * |
---|
766 | * This allows each Webform component to add information into hook_theme(). If |
---|
767 | * you specify a file to include, you must define the path to the module that |
---|
768 | * this file belongs to. |
---|
769 | */ |
---|
770 | function _webform_theme_component() { |
---|
771 | return array( |
---|
772 | 'webform_grid' => array( |
---|
773 | 'arguments' => array('grid_element' => NULL), |
---|
774 | 'file' => 'components/grid.inc', |
---|
775 | 'path' => drupal_get_path('module', 'webform'), |
---|
776 | ), |
---|
777 | 'webform_display_grid' => array( |
---|
778 | 'arguments' => array('element' => NULL), |
---|
779 | 'file' => 'components/grid.inc', |
---|
780 | 'path' => drupal_get_path('module', 'webform'), |
---|
781 | ), |
---|
782 | ); |
---|
783 | } |
---|
784 | |
---|
785 | /** |
---|
786 | * Calculate and returns statistics about results for this component. |
---|
787 | * |
---|
788 | * This takes into account all submissions to this webform. The output of this |
---|
789 | * function will be displayed under the "Results" tab then "Analysis". |
---|
790 | * |
---|
791 | * @param $component |
---|
792 | * An array of information describing the component, directly correlating to |
---|
793 | * the webform_component database schema. |
---|
794 | * @param $sids |
---|
795 | * An optional array of submission IDs (sid). If supplied, the analysis will |
---|
796 | * be limited to these sids. |
---|
797 | * @param $single |
---|
798 | * Boolean flag determining if the details about a single component are being |
---|
799 | * shown. May be used to provided detailed information about a single |
---|
800 | * component's analysis, such as showing "Other" options within a select list. |
---|
801 | * @return |
---|
802 | * An array of data rows, each containing a statistic for this component's |
---|
803 | * submissions. |
---|
804 | */ |
---|
805 | function _webform_analysis_component($component, $sids = array(), $single = FALSE) { |
---|
806 | // Generate the list of options and questions. |
---|
807 | $options = _webform_component_options($component['extra']['options']); |
---|
808 | $questions = array_values(_webform_component_options($component['extra']['questions'])); |
---|
809 | |
---|
810 | // Generate a lookup table of results. |
---|
811 | $sidfilter = count($sids) ? " AND sid in (" . db_placeholders($sids, 'int') . ")" : ""; |
---|
812 | $query = 'SELECT no, data, count(data) as datacount '. |
---|
813 | ' FROM {webform_submitted_data} '. |
---|
814 | ' WHERE nid = %d '. |
---|
815 | ' AND cid = %d '. |
---|
816 | " AND data != '' ". $sidfilter . |
---|
817 | ' GROUP BY no, data'; |
---|
818 | $result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids)); |
---|
819 | $counts = array(); |
---|
820 | while ($data = db_fetch_object($result)) { |
---|
821 | $counts[$data->no][$data->data] = $data->datacount; |
---|
822 | } |
---|
823 | |
---|
824 | // Create an entire table to be put into the returned row. |
---|
825 | $rows = array(); |
---|
826 | $header = array(''); |
---|
827 | |
---|
828 | // Add options as a header row. |
---|
829 | foreach ($options as $option) { |
---|
830 | $header[] = $option; |
---|
831 | } |
---|
832 | |
---|
833 | // Add questions as each row. |
---|
834 | foreach ($questions as $qkey => $question) { |
---|
835 | $row = array($question); |
---|
836 | foreach ($options as $okey => $option) { |
---|
837 | $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0; |
---|
838 | } |
---|
839 | $rows[] = $row; |
---|
840 | } |
---|
841 | $output = theme('table', $header, $rows, array('class' => 'webform-grid')); |
---|
842 | |
---|
843 | return array(array(array('data' => $output, 'colspan' => 2))); |
---|
844 | } |
---|
845 | |
---|
846 | /** |
---|
847 | * Return the result of a component value for display in a table. |
---|
848 | * |
---|
849 | * The output of this function will be displayed under the "Results" tab then |
---|
850 | * "Table". |
---|
851 | * |
---|
852 | * @param $component |
---|
853 | * A Webform component array. |
---|
854 | * @param $value |
---|
855 | * An array of information containing the submission result, directly |
---|
856 | * correlating to the webform_submitted_data database schema. |
---|
857 | * @return |
---|
858 | * Textual output formatted for human reading. |
---|
859 | */ |
---|
860 | function _webform_table_component($component, $value) { |
---|
861 | $questions = array_values(_webform_component_options($component['extra']['questions'])); |
---|
862 | $output = ''; |
---|
863 | // Set the value as a single string. |
---|
864 | if (is_array($value)) { |
---|
865 | foreach ($value as $item => $value) { |
---|
866 | if ($value !== '') { |
---|
867 | $output .= $questions[$item] . ': ' . check_plain($value) . '<br />'; |
---|
868 | } |
---|
869 | } |
---|
870 | } |
---|
871 | else { |
---|
872 | $output = check_plain(!isset($value['0']) ? '' : $value['0']); |
---|
873 | } |
---|
874 | return $output; |
---|
875 | } |
---|
876 | |
---|
877 | /** |
---|
878 | * Return the header for this component to be displayed in a CSV file. |
---|
879 | * |
---|
880 | * The output of this function will be displayed under the "Results" tab then |
---|
881 | * "Download". |
---|
882 | * |
---|
883 | * @param $component |
---|
884 | * A Webform component array. |
---|
885 | * @param $export_options |
---|
886 | * An array of options that may configure export of this field. |
---|
887 | * @return |
---|
888 | * An array of data to be displayed in the first three rows of a CSV file, not |
---|
889 | * including either prefixed or trailing commas. |
---|
890 | */ |
---|
891 | function _webform_csv_headers_component($component, $export_options) { |
---|
892 | $header = array(); |
---|
893 | $header[0] = array(''); |
---|
894 | $header[1] = array($component['name']); |
---|
895 | $items = _webform_component_options($component['extra']['questions']); |
---|
896 | $count = 0; |
---|
897 | foreach ($items as $key => $item) { |
---|
898 | // Empty column per sub-field in main header. |
---|
899 | if ($count != 0) { |
---|
900 | $header[0][] = ''; |
---|
901 | $header[1][] = ''; |
---|
902 | } |
---|
903 | // The value for this option. |
---|
904 | $header[2][] = $item; |
---|
905 | $count++; |
---|
906 | } |
---|
907 | |
---|
908 | return $header; |
---|
909 | } |
---|
910 | |
---|
911 | /** |
---|
912 | * Format the submitted data of a component for CSV downloading. |
---|
913 | * |
---|
914 | * The output of this function will be displayed under the "Results" tab then |
---|
915 | * "Download". |
---|
916 | * |
---|
917 | * @param $component |
---|
918 | * A Webform component array. |
---|
919 | * @param $export_options |
---|
920 | * An array of options that may configure export of this field. |
---|
921 | * @param $value |
---|
922 | * An array of information containing the submission result, directly |
---|
923 | * correlating to the webform_submitted_data database schema. |
---|
924 | * @return |
---|
925 | * An array of items to be added to the CSV file. Each value within the array |
---|
926 | * will be another column within the file. This function is called once for |
---|
927 | * every row of data. |
---|
928 | */ |
---|
929 | function _webform_csv_data_component($component, $export_options, $value) { |
---|
930 | $questions = array_keys(_webform_select_options($component['extra']['questions'])); |
---|
931 | $return = array(); |
---|
932 | foreach ($questions as $key => $question) { |
---|
933 | $return[] = isset($value[$key]) ? $value[$key] : ''; |
---|
934 | } |
---|
935 | return $return; |
---|
936 | } |
---|
937 | |
---|
938 | /** |
---|
939 | * @} |
---|
940 | */ |
---|