Project

General

Profile

Paste
Download (30.4 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / webform / webform.api.php @ 4cfd8be6

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_insert('mymodule_table')
136
    ->fields(array(
137
      'nid' => $node->nid,
138
      'sid' => $submission->sid,
139
      'foo' => 'foo_data',
140
    ))
141
    ->execute();
142
}
143

    
144
/**
145
 * Respond to a Webform submission being updated.
146
 *
147
 * Note that this hook is called after a submission has already been saved to
148
 * the database. If needing to modify the submission prior to updating, use
149
 * hook_webform_submission_presave().
150
 *
151
 * @param $node
152
 *   The Webform node on which this submission was made.
153
 * @param $submission
154
 *   The Webform submission that was just updated in the database.
155
 */
156
function hook_webform_submission_update($node, $submission) {
157
  // Update a record in a 3rd-party module table when a submission is updated.
158
  db_update('mymodule_table')
159
    ->fields(array(
160
      'foo' => 'foo_data',
161
    ))
162
    ->condition('nid', $node->nid)
163
    ->condition('sid', $submission->sid)
164
    ->execute();
165
}
166

    
167
/**
168
 * Respond to a Webform submission being deleted.
169
 *
170
 * @param $node
171
 *   The Webform node on which this submission was made.
172
 * @param $submission
173
 *   The Webform submission that was just deleted from the database.
174
 */
175
function hook_webform_submission_delete($node, $submission) {
176
  // Delete a record from a 3rd-party module table when a submission is deleted.
177
  db_delete('mymodule_table')
178
    ->condition('nid', $node->nid)
179
    ->condition('sid', $submission->sid)
180
    ->execute();
181
}
182

    
183
/**
184
 * Provide a list of actions that can be executed on a submission.
185
 *
186
 * Some actions are displayed in the list of submissions such as edit, view, and
187
 * delete. All other actions are displayed only when viewing the submission.
188
 * These additional actions may be specified in this hook. Examples included
189
 * directly in the Webform module include PDF, print, and resend e-mails. Other
190
 * modules may extend this list by using this hook.
191
 *
192
 * @param $node
193
 *   The Webform node on which this submission was made.
194
 * @param $submission
195
 *   The Webform submission on which the actions may be performed.
196
 */
197
function hook_webform_submission_actions($node, $submission) {
198
  if (webform_results_access($node)) {
199
    $actions['myaction'] = array(
200
      'title' => t('Do my action'),
201
      'href' => 'node/' . $node->nid . '/submission/' . $submission->sid . '/myaction',
202
      'query' => drupal_get_destination(),
203
    );
204
  }
205

    
206
  return $actions;
207
}
208

    
209
/**
210
 * Alter the display of a Webform submission.
211
 *
212
 * This function applies to both e-mails sent by Webform and normal display of
213
 * submissions when viewing through the adminsitrative interface.
214
 *
215
 * @param $renderable
216
 *   The Webform submission in a renderable array, similar to FormAPI's
217
 *   structure. This variable must be passed in by-reference. Important
218
 *   properties of this array include #node, #submission, #email, and #format,
219
 *   which can be used to find the context of the submission that is being
220
 *   rendered.
221
 */
222
function hook_webform_submission_render_alter(&$renderable) {
223
  // Remove page breaks from sent e-mails.
224
  if (isset($renderable['#email'])) {
225
    foreach (element_children($renderable) as $key) {
226
      if ($renderable[$key]['#component']['type'] == 'pagebreak') {
227
        unset($renderable[$key]);
228
      }
229
    }
230
  }
231
}
232

    
233
/**
234
 * Modify a loaded Webform component.
235
 *
236
 * IMPORTANT: This hook does not actually exist because components are loaded
237
 * in bulk as part of webform_node_load(). Use hook_node_load() to modify loaded
238
 * components when the node is loaded. This example is provided merely to point
239
 * to hook_node_load().
240
 *
241
 * @see hook_nodeapi()
242
 * @see webform_node_load()
243
 */
244
function hook_webform_component_load() {
245
  // This hook does not exist. Instead use hook_node_load().
246
}
247

    
248
/**
249
 * Modify a Webform component before it is saved to the database.
250
 *
251
 * Note that most of the time this hook is not necessary, because Webform will
252
 * automatically add data to the component based on the component form. Using
253
 * hook_form_alter() will be sufficient in most cases.
254
 *
255
 * @see hook_form_alter()
256
 * @see webform_component_edit_form()
257
 *
258
 * @param $component
259
 *   The Webform component being saved.
260
 */
261
function hook_webform_component_presave(&$component) {
262
  $component['extra']['new_option'] = 'foo';
263
}
264

    
265
/**
266
 * Respond to a Webform component being inserted into the database.
267
 */
268
function hook_webform_component_insert($component) {
269
  // Insert a record into a 3rd-party module table when a component is inserted.
270
  db_insert('mymodule_table')
271
    ->fields(array(
272
      'nid' => $component['nid'],
273
      'cid' => $component['cid'],
274
      'foo' => 'foo_data',
275
    ))
276
    ->execute();
277
}
278

    
279
/**
280
 * Respond to a Webform component being updated in the database.
281
 */
282
function hook_webform_component_update($component) {
283
  // Update a record in a 3rd-party module table when a component is updated.
284
  db_update('mymodule_table')
285
    ->fields(array(
286
      'foo' => 'foo_data',
287
    ))
288
    ->condition('nid', $component['nid'])
289
    ->condition('cid', $component['cid'])
290
    ->execute();
291
}
292

    
293
/**
294
 * Respond to a Webform component being deleted.
295
 */
296
function hook_webform_component_delete($component) {
297
  // Delete a record in a 3rd-party module table when a component is deleted.
298
  db_delete('mymodule_table')
299
    ->condition('nid', $component['nid'])
300
    ->condition('cid', $component['cid'])
301
    ->execute();
302
}
303

    
304
/**
305
 * Alter a Webform submission's header when exported.
306
 */
307
function hook_webform_csv_header_alter(&$header, $component) {
308
  // Use the machine name for component headers, but only for the webform 
309
  // with node 5 and components that are text fields.
310
  if ($component['nid'] == 5 && $component['type'] == 'textfield') {
311
    $header[2] = $component['form_key'];
312
  }
313
}
314

    
315
/**
316
 * Alter a Webform submission's data when exported.
317
 */
318
function hook_webform_csv_data_alter(&$data, $component, $submission) {
319
  // If a value of a field was left blank, use the value from another
320
  // field.
321
  if ($component['cid'] == 1 && empty($data)) {
322
    $data = $submission->data[2]['value'][0];
323
  }
324
}
325

    
326
/**
327
 * Define components to Webform.
328
 *
329
 * @return
330
 *   An array of components, keyed by machine name. Required properties are
331
 *   "label" and "description". The "features" array defines which capabilities
332
 *   the component has, such as being displayed in e-mails or csv downloads.
333
 *   A component like "markup" for example would not show in these locations.
334
 *   The possible features of a component include:
335
 *
336
 *     - csv
337
 *     - email
338
 *     - email_address
339
 *     - email_name
340
 *     - required
341
 *     - conditional
342
 *     - spam_analysis
343
 *     - group
344
 *
345
 *   Note that most of these features do not indicate the default state, but
346
 *   determine if the component can have this property at all. Setting
347
 *   "required" to TRUE does not mean that a component's fields will always be
348
 *   required, but instead give the option to the administrator to choose the
349
 *   requiredness. See the example implementation for details on how these
350
 *   features may be set.
351
 *
352
 *   An optional "file" may be specified to be loaded when the component is
353
 *   needed. A set of callbacks will be established based on the name of the
354
 *   component. All components follow the pattern:
355
 *
356
 *   _webform_[callback]_[component]
357
 *
358
 *   Where [component] is the name of the key of the component and [callback] is
359
 *   any of the following:
360
 *
361
 *     - defaults
362
 *     - edit
363
 *     - render
364
 *     - display
365
 *     - submit
366
 *     - delete
367
 *     - help
368
 *     - theme
369
 *     - analysis
370
 *     - table
371
 *     - csv_headers
372
 *     - csv_data
373
 *
374
 * See the sample component implementation for details on each one of these
375
 * callbacks.
376
 *
377
 * @see webform_components()
378
 */
379
function hook_webform_component_info() {
380
  $components = array();
381

    
382
  $components['textfield'] = array(
383
    'label' => t('Textfield'),
384
    'description' => t('Basic textfield type.'),
385
    'features' => array(
386
      // Add content to CSV downloads. Defaults to TRUE.
387
      'csv' => TRUE,
388

    
389
      // This component supports default values. Defaults to TRUE.
390
      'default_value' => FALSE,
391

    
392
      // This component supports a description field. Defaults to TRUE.
393
      'description' => FALSE,
394

    
395
      // Show this component in e-mailed submissions. Defaults to TRUE.
396
      'email' => TRUE,
397

    
398
      // Allow this component to be used as an e-mail FROM or TO address.
399
      // Defaults to FALSE.
400
      'email_address' => FALSE,
401

    
402
      // Allow this component to be used as an e-mail SUBJECT or FROM name.
403
      // Defaults to FALSE.
404
      'email_name' => TRUE,
405

    
406
      // This component may be toggled as required or not. Defaults to TRUE.
407
      'required' => TRUE,
408

    
409
      // This component supports a title attribute. Defaults to TRUE.
410
      'title' => FALSE,
411

    
412
      // This component has a title that can be toggled as displayed or not.
413
      'title_display' => TRUE,
414

    
415
      // This component has a title that can be displayed inline.
416
      'title_inline' => TRUE,
417

    
418
      // If this component can be used as a conditional SOURCE. All components
419
      // may always be displayed conditionally, regardless of this setting.
420
      // Defaults to TRUE.
421
      'conditional' => TRUE,
422

    
423
      // If this component allows other components to be grouped within it
424
      // (like a fieldset or tabs). Defaults to FALSE.
425
      'group' => FALSE,
426

    
427
      // If this component can be used for SPAM analysis, usually with Mollom.
428
      'spam_analysis' => FALSE,
429

    
430
      // If this component saves a file that can be used as an e-mail
431
      // attachment. Defaults to FALSE.
432
      'attachment' => FALSE,
433
    ),
434
    'file' => 'components/textfield.inc',
435
  );
436

    
437
  return $components;
438
}
439

    
440
/**
441
 * Alter the list of available Webform components.
442
 *
443
 * @param $components
444
 *   A list of existing components as defined by hook_webform_component_info().
445
 *
446
 * @see hook_webform_component_info()
447
 */
448
function hook_webform_component_info_alter(&$components) {
449
  // Completely remove a component.
450
  unset($components['grid']);
451

    
452
  // Change the name of a component.
453
  $components['textarea']['label'] = t('Text box');
454
}
455

    
456
/**
457
 * Alter the list of Webform component default values.
458
 *
459
 * @param $defaults
460
 *   A list of component defaults as defined by _webform_defaults_COMPONENT().
461
 * @param $type
462
 *   The component type whose defaults are being provided.
463
 *
464
 * @see _webform_defaults_component()
465
 */
466
function hook_webform_component_defaults_alter(&$defaults, $type) {
467
  // Alter a default for all component types.
468
  $defaults['required'] = 1;
469

    
470
  // Add a default for a new field added via hook_form_alter() or
471
  // hook_form_FORM_ID_alter() for all component types.
472
  $defaults['extra']['added_field'] = t('Added default value');
473

    
474
  // Add or alter defaults for specific component types:
475
  switch ($type) {
476
    case 'select':
477
      $defaults['extra']['optrand'] = 1;
478
      break;
479

    
480
    case 'textfield':
481
    case 'textarea':
482
      $defaults['extra']['another_added_field'] = t('Another added default value');
483
  }
484
}
485

    
486
/**
487
 * Alter access to a Webform submission.
488
 *
489
 * @param $node
490
 *   The Webform node on which this submission was made.
491
 * @param $submission
492
 *   The Webform submission.
493
 * @param $op
494
 *   The operation to be performed on the submission. Possible values are:
495
 *   - "view"
496
 *   - "edit"
497
 *   - "delete"
498
 *   - "list"
499
 * @param $account
500
 *   A user account object.
501
 * @return
502
 *   TRUE if the current user has access to submission,
503
 *   or FALSE otherwise.
504
 */
505
function hook_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
506
  switch ($op) {
507
    case 'view':
508
      return TRUE;
509
      break;
510
    case 'edit':
511
      return FALSE;
512
      break;
513
    case 'delete':
514
      return TRUE;
515
      break;
516
    case 'list':
517
      return TRUE;
518
      break;
519
  }
520
}
521

    
522
/**
523
 * Determine if a user has access to see the results of a webform.
524
 *
525
 * Note in addition to the view access to the results granted here, the $account
526
 * must also have view access to the Webform node in order to see results.
527
 *
528
 * @see webform_results_access().
529
 *
530
 * @param $node
531
 *   The Webform node to check access on.
532
 * @param $account
533
 *   The user account to check access on.
534
 * @return
535
 *   TRUE or FALSE if the user can access the webform results.
536
 */
537
function hook_webform_results_access($node, $account) {
538
  // Let editors view results of unpublished webforms.
539
  if ($node->status == 0 && in_array('editor', $account->roles)) {
540
    return TRUE;
541
  }
542
  else {
543
    return FALSE;
544
  }
545
}
546

    
547
/**
548
 * Return an array of files associated with the component.
549
 *
550
 * The output of this function will be used to attach files to e-mail messages.
551
 *
552
 * @param $component
553
 *   A Webform component array.
554
 * @param $value
555
 *   An array of information containing the submission result, directly
556
 *   correlating to the webform_submitted_data database schema.
557
 * @return
558
 *   An array of files, each file is an array with following keys:
559
 *     - filepath: The relative path to the file.
560
 *     - filename: The name of the file including the extension.
561
 *     - filemime: The mimetype of the file.
562
 *   This will result in an array looking something like this:
563
 *   @code
564
 *   array[0] => array(
565
 *     'filepath' => '/sites/default/files/attachment.txt',
566
 *     'filename' => 'attachment.txt',
567
 *     'filemime' => 'text/plain',
568
 *   );
569
 *   @endcode
570
 */
571
function _webform_attachments_component($component, $value) {
572
  $files = array();
573
  $files[] = (array) file_load($value[0]);
574
  return $files;
575
}
576

    
577
/**
578
 * @}
579
 */
580

    
581
/**
582
 * @defgroup webform_component Sample Webform Component
583
 * @{
584
 * In each of these examples, the word "component" should be replaced with the,
585
 * name of the component type (such as textfield or select). These are not
586
 * actual hooks, but instead samples of how Webform integrates with its own
587
 * built-in components.
588
 */
589

    
590
/**
591
 * Specify the default properties of a component.
592
 *
593
 * @return
594
 *   An array defining the default structure of a component.
595
 */
596
function _webform_defaults_component() {
597
  return array(
598
    'name' => '',
599
    'form_key' => NULL,
600
    'mandatory' => 0,
601
    'pid' => 0,
602
    'weight' => 0,
603
    'extra' => array(
604
      'options' => '',
605
      'questions' => '',
606
      'optrand' => 0,
607
      'qrand' => 0,
608
      'description' => '',
609
    ),
610
  );
611
}
612

    
613
/**
614
 * Generate the form for editing a component.
615
 *
616
 * Create a set of form elements to be displayed on the form for editing this
617
 * component. Use care naming the form items, as this correlates directly to the
618
 * database schema. The component "Name" and "Description" fields are added to
619
 * every component type and are not necessary to specify here (although they
620
 * may be overridden if desired).
621
 *
622
 * @param $component
623
 *   A Webform component array.
624
 * @return
625
 *   An array of form items to be displayed on the edit component page
626
 */
627
function _webform_edit_component($component) {
628
  $form = array();
629

    
630
  // Disabling the description if not wanted.
631
  $form['description'] = array();
632

    
633
  // Most options are stored in the "extra" array, which stores any settings
634
  // unique to a particular component type.
635
  $form['extra']['options'] = array(
636
    '#type' => 'textarea',
637
    '#title' => t('Options'),
638
    '#default_value' => $component['extra']['options'],
639
    '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'),
640
    '#cols' => 60,
641
    '#rows' => 5,
642
    '#weight' => -3,
643
    '#required' => TRUE,
644
  );
645
  return $form;
646
}
647

    
648
/**
649
 * Render a Webform component to be part of a form.
650
 *
651
 * @param $component
652
 *   A Webform component array.
653
 * @param $value
654
 *   If editing an existing submission or resuming a draft, this will contain
655
 *   an array of values to be shown instead of the default in the component
656
 *   configuration. This value will always be an array, keyed numerically for
657
 *   each value saved in this field.
658
 * @param $filter
659
 *   Whether or not to filter the contents of descriptions and values when
660
 *   rendering the component. Values need to be unfiltered to be editable by
661
 *   Form Builder.
662
 *
663
 * @see _webform_client_form_add_component()
664
 */
665
function _webform_render_component($component, $value = NULL, $filter = TRUE) {
666
  $form_item = array(
667
    '#type' => 'textfield',
668
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
669
    '#required' => $component['mandatory'],
670
    '#weight' => $component['weight'],
671
    '#description'   => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
672
    '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
673
    '#prefix' => '<div class="webform-component-textfield" id="webform-component-' . $component['form_key'] . '">',
674
    '#suffix' => '</div>',
675
  );
676

    
677
  if (isset($value)) {
678
    $form_item['#default_value'] = $value[0];
679
  }
680

    
681
  return $form_item;
682
}
683

    
684
/**
685
 * Display the result of a submission for a component.
686
 *
687
 * The output of this function will be displayed under the "Results" tab then
688
 * "Submissions". This should output the saved data in some reasonable manner.
689
 *
690
 * @param $component
691
 *   A Webform component array.
692
 * @param $value
693
 *   An array of information containing the submission result, directly
694
 *   correlating to the webform_submitted_data database table schema.
695
 * @param $format
696
 *   Either 'html' or 'text'. Defines the format that the content should be
697
 *   returned as. Make sure that returned content is run through check_plain()
698
 *   or other filtering functions when returning HTML.
699
 * @return
700
 *   A renderable element containing at the very least these properties:
701
 *    - #title
702
 *    - #weight
703
 *    - #component
704
 *    - #format
705
 *    - #value
706
 *   Webform also uses #theme_wrappers to output the end result to the user,
707
 *   which will properly format the label and content for use within an e-mail
708
 *   (such as wrapping the text) or as HTML (ensuring consistent output).
709
 */
710
function _webform_display_component($component, $value, $format = 'html') {
711
  return array(
712
    '#title' => $component['name'],
713
    '#weight' => $component['weight'],
714
    '#theme' => 'webform_display_textfield',
715
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
716
    '#post_render' => array('webform_element_wrapper'),
717
    '#field_prefix' => $component['extra']['field_prefix'],
718
    '#field_suffix' => $component['extra']['field_suffix'],
719
    '#component' => $component,
720
    '#format' => $format,
721
    '#value' => isset($value[0]) ? $value[0] : '',
722
  );
723
}
724

    
725
/**
726
 * A hook for changing the input values before saving to the database.
727
 *
728
 * Webform expects a component to consist of a single field, or a single array
729
 * of fields. If you have a component that requires a deeper form tree
730
 * you must flatten the data into a single array using this callback
731
 * or by setting #parents on each field to avoid data loss and/or unexpected
732
 * behavior.
733
 *
734
 * Note that Webform will save the result of this function directly into the
735
 * database.
736
 *
737
 * @param $component
738
 *   A Webform component array.
739
 * @param $value
740
 *   The POST data associated with the user input.
741
 * @return
742
 *   An array of values to be saved into the database. Note that this should be
743
 *   a numerically keyed array.
744
 */
745
function _webform_submit_component($component, $value) {
746
  // Clean up a phone number into 123-456-7890 format.
747
  if ($component['extra']['phone_number']) {
748
    $matches = array();
749
    $number = preg_replace('[^0-9]', $value[0]);
750
    if (strlen($number) == 7) {
751
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
752
    }
753
    else {
754
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
755
    }
756
  }
757

    
758
  $value[0] = $number;
759
  return $value;
760
}
761

    
762
/**
763
 * Delete operation for a component or submission.
764
 *
765
 * @param $component
766
 *   A Webform component array.
767
 * @param $value
768
 *   An array of information containing the submission result, directly
769
 *   correlating to the webform_submitted_data database schema.
770
 */
771
function _webform_delete_component($component, $value) {
772
  // Delete corresponding files when a submission is deleted.
773
  if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
774
    file_usage_delete($file, 'webform');
775
    file_delete($file);
776
  }
777
}
778

    
779
/**
780
 * Module specific instance of hook_help().
781
 *
782
 * This allows each Webform component to add information into hook_help().
783
 */
784
function _webform_help_component($section) {
785
  switch ($section) {
786
    case 'admin/config/content/webform#grid_description':
787
      return t('Allows creation of grid questions, denoted by radio buttons.');
788
  }
789
}
790

    
791
/**
792
 * Module specific instance of hook_theme().
793
 *
794
 * This allows each Webform component to add information into hook_theme(). If
795
 * you specify a file to include, you must define the path to the module that
796
 * this file belongs to.
797
 */
798
function _webform_theme_component() {
799
  return array(
800
    'webform_grid' => array(
801
      'render element' => 'element',
802
      'file' => 'components/grid.inc',
803
      'path' => drupal_get_path('module', 'webform'),
804
    ),
805
    'webform_display_grid' => array(
806
      'render element' => 'element',
807
      'file' => 'components/grid.inc',
808
      'path' => drupal_get_path('module', 'webform'),
809
    ),
810
  );
811
}
812

    
813
/**
814
 * Calculate and returns statistics about results for this component.
815
 *
816
 * This takes into account all submissions to this webform. The output of this
817
 * function will be displayed under the "Results" tab then "Analysis".
818
 *
819
 * @param $component
820
 *   An array of information describing the component, directly correlating to
821
 *   the webform_component database schema.
822
 * @param $sids
823
 *   An optional array of submission IDs (sid). If supplied, the analysis will
824
 *   be limited to these sids.
825
 * @param $single
826
 *   Boolean flag determining if the details about a single component are being
827
 *   shown. May be used to provided detailed information about a single
828
 *   component's analysis, such as showing "Other" options within a select list.
829
 * @return
830
 *   An array of data rows, each containing a statistic for this component's
831
 *   submissions.
832
 */
833
function _webform_analysis_component($component, $sids = array(), $single = FALSE) {
834
  // Generate the list of options and questions.
835
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
836
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
837

    
838
  // Generate a lookup table of results.
839
  $query = db_select('webform_submitted_data', 'wsd')
840
    ->fields('wsd', array('no', 'data'))
841
    ->condition('nid', $component['nid'])
842
    ->condition('cid', $component['cid'])
843
    ->condition('data', '', '<>')
844
    ->groupBy('no')
845
    ->groupBy('data');
846
  $query->addExpression('COUNT(sid)', 'datacount');
847

    
848
  if (count($sids)) {
849
    $query->condition('sid', $sids, 'IN');
850
  }
851

    
852
  $result = $query->execute();
853
  $counts = array();
854
  foreach ($result as $data) {
855
    $counts[$data->no][$data->data] = $data->datacount;
856
  }
857

    
858
  // Create an entire table to be put into the returned row.
859
  $rows = array();
860
  $header = array('');
861

    
862
  // Add options as a header row.
863
  foreach ($options as $option) {
864
    $header[] = $option;
865
  }
866

    
867
  // Add questions as each row.
868
  foreach ($questions as $qkey => $question) {
869
    $row = array($question);
870
    foreach ($options as $okey => $option) {
871
      $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
872
    }
873
    $rows[] = $row;
874
  }
875
  $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid'))));
876

    
877
  return array(array(array('data' => $output, 'colspan' => 2)));
878
}
879

    
880
/**
881
 * Return the result of a component value for display in a table.
882
 *
883
 * The output of this function will be displayed under the "Results" tab then
884
 * "Table".
885
 *
886
 * @param $component
887
 *   A Webform component array.
888
 * @param $value
889
 *   An array of information containing the submission result, directly
890
 *   correlating to the webform_submitted_data database schema.
891
 * @return
892
 *   Textual output formatted for human reading.
893
 */
894
function _webform_table_component($component, $value) {
895
  $questions = array_values(_webform_component_options($component['extra']['questions']));
896
  $output = '';
897
  // Set the value as a single string.
898
  if (is_array($value)) {
899
    foreach ($value as $item => $value) {
900
      if ($value !== '') {
901
        $output .= $questions[$item] . ': ' . check_plain($value) . '<br />';
902
      }
903
    }
904
  }
905
  else {
906
    $output = check_plain(!isset($value['0']) ? '' : $value['0']);
907
  }
908
  return $output;
909
}
910

    
911
/**
912
 * Return the header for this component to be displayed in a CSV file.
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
 * @return
922
 *   An array of data to be displayed in the first three rows of a CSV file, not
923
 *   including either prefixed or trailing commas.
924
 */
925
function _webform_csv_headers_component($component, $export_options) {
926
  $header = array();
927
  $header[0] = array('');
928
  $header[1] = array($component['name']);
929
  $items = _webform_component_options($component['extra']['questions']);
930
  $count = 0;
931
  foreach ($items as $key => $item) {
932
    // Empty column per sub-field in main header.
933
    if ($count != 0) {
934
      $header[0][] = '';
935
      $header[1][] = '';
936
    }
937
    // The value for this option.
938
    $header[2][] = $item;
939
    $count++;
940
  }
941

    
942
  return $header;
943
}
944

    
945
/**
946
 * Format the submitted data of a component for CSV downloading.
947
 *
948
 * The output of this function will be displayed under the "Results" tab then
949
 * "Download".
950
 *
951
 * @param $component
952
 *   A Webform component array.
953
 * @param $export_options
954
 *   An array of options that may configure export of this field.
955
 * @param $value
956
 *   An array of information containing the submission result, directly
957
 *   correlating to the webform_submitted_data database schema.
958
 * @return
959
 *   An array of items to be added to the CSV file. Each value within the array
960
 *   will be another column within the file. This function is called once for
961
 *   every row of data.
962
 */
963
function _webform_csv_data_component($component, $export_options, $value) {
964
  $questions = array_keys(_webform_select_options($component['extra']['questions']));
965
  $return = array();
966
  foreach ($questions as $key => $question) {
967
    $return[] = isset($value[$key]) ? $value[$key] : '';
968
  }
969
  return $return;
970
}
971

    
972
/**
973
 * @}
974
 */