Projet

Général

Profil

Paste
Télécharger (44,9 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / webform / webform.api.php @ 7547bb19

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 $arguments
75
 *   The "options arguments" specified in hook_webform_select_options_info().
76
 * @return
77
 *   An array of key => value pairs suitable for a select list's #options
78
 *   FormAPI property.
79
 */
80
function webform_options_example($component, $flat, $arguments) {
81
  $options = array(
82
    'one' => t('Pre-built option one'),
83
    'two' => t('Pre-built option two'),
84
    'three' => t('Pre-built option three'),
85
  );
86

    
87
  return $options;
88
}
89

    
90
/**
91
 * Respond to the loading of Webform submissions.
92
 *
93
 * @param $submissions
94
 *   An array of Webform submissions that are being loaded, keyed by the
95
 *   submission ID. Modifications to the submissions are done by reference.
96
 */
97
function hook_webform_submission_load(&$submissions) {
98
  foreach ($submissions as $sid => $submission) {
99
    $submissions[$sid]->new_property = 'foo';
100
  }
101
}
102

    
103
/**
104
 * Respond to the creation of a new submission from form values.
105
 *
106
 * This hook is called when a user has completed a submission to initialize the
107
 * submission object. After this object has its values populated, it will be
108
 * saved by webform_submission_insert(). Note that this hook is only called for
109
 * new submissions, not for submissions being edited. If responding to the
110
 * saving of all submissions, it's recommended to use
111
 * hook_webform_submission_presave().
112
 *
113
 * @param $submission
114
 *   The submission object that has been created.
115
 * @param $node
116
 *   The Webform node for which this submission is being saved.
117
 * @param $account
118
 *   The user account that is creating the submission.
119
 * @param $form_state
120
 *   The contents of form state that is the basis for this submission.
121
 *
122
 * @see webform_submission_create()
123
 */
124
function hook_webform_submission_create_alter(&$submission, &$node, &$account, &$form_state) {
125
  $submission->new_property = TRUE;
126
}
127

    
128
/**
129
 * Modify a Webform submission, prior to saving it in the database.
130
 *
131
 * @param $node
132
 *   The Webform node on which this submission was made.
133
 * @param $submission
134
 *   The Webform submission that is about to be saved to the database.
135
 */
136
function hook_webform_submission_presave($node, &$submission) {
137
  // Update some component's value before it is saved.
138
  $component_id = 4;
139
  $submission->data[$component_id][0] = 'foo';
140
}
141

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

    
165
/**
166
 * Respond to a Webform submission being updated.
167
 *
168
 * Note that this hook is called after a submission has already been saved to
169
 * the database. If needing to modify the submission prior to updating, use
170
 * hook_webform_submission_presave().
171
 *
172
 * @param $node
173
 *   The Webform node on which this submission was made.
174
 * @param $submission
175
 *   The Webform submission that was just updated in the database.
176
 */
177
function hook_webform_submission_update($node, $submission) {
178
  // Update a record in a 3rd-party module table when a submission is updated.
179
  db_update('mymodule_table')
180
    ->fields(array(
181
      'foo' => 'foo_data',
182
    ))
183
    ->condition('nid', $node->nid)
184
    ->condition('sid', $submission->sid)
185
    ->execute();
186
}
187

    
188
/**
189
 * Respond to a Webform submission being deleted.
190
 *
191
 * @param $node
192
 *   The Webform node on which this submission was made.
193
 * @param $submission
194
 *   The Webform submission that was just deleted from the database.
195
 */
196
function hook_webform_submission_delete($node, $submission) {
197
  // Delete a record from a 3rd-party module table when a submission is deleted.
198
  db_delete('mymodule_table')
199
    ->condition('nid', $node->nid)
200
    ->condition('sid', $submission->sid)
201
    ->execute();
202
}
203

    
204
/**
205
 * Provide a list of actions that can be executed on a submission.
206
 *
207
 * Some actions are displayed in the list of submissions such as edit, view, and
208
 * delete. All other actions are displayed only when viewing the submission.
209
 * These additional actions may be specified in this hook. Examples included
210
 * directly in the Webform module include PDF, print, and resend e-mails. Other
211
 * modules may extend this list by using this hook.
212
 *
213
 * @param $node
214
 *   The Webform node on which this submission was made.
215
 * @param $submission
216
 *   The Webform submission on which the actions may be performed.
217
 */
218
function hook_webform_submission_actions($node, $submission) {
219
  $actions= array();
220

    
221
  if (webform_results_access($node)) {
222
    $actions['myaction'] = array(
223
      'title' => t('Do my action'),
224
      'href' => 'node/' . $node->nid . '/submission/' . $submission->sid . '/myaction',
225
      'query' => drupal_get_destination(),
226
    );
227
  }
228

    
229
  return $actions;
230
}
231

    
232
/**
233
 * Modify the draft to be presented for editing.
234
 *
235
 * When drafts are enabled for the webform, by default, a pre-existig draft is
236
 * presented when the webform is displayed to that user. To allow multiple
237
 * drafts, implement this alter function to set the $sid to NULL, or use your
238
 * application's business logic to determine whether a new draft or which of
239
 * he pre-existing drafts should be presented.
240
 *
241
 * @param integer $sid
242
 *    The id of the most recent submission to be presented for editing. Change
243
 *    to a different draft's sid or set to NULL for a new draft.
244
 * @param array $context
245
 *    Array of context with indices 'nid' and 'uid'.
246
 */
247
function hook_webform_draft_alter(&$sid, $context) {
248
  if ($_GET['newdraft']) {
249
    $sid = NULL;
250
  }
251
}
252

    
253
/**
254
 * Alter the display of a Webform submission.
255
 *
256
 * This function applies to both e-mails sent by Webform and normal display of
257
 * submissions when viewing through the adminsitrative interface.
258
 *
259
 * @param $renderable
260
 *   The Webform submission in a renderable array, similar to FormAPI's
261
 *   structure. This variable must be passed in by-reference. Important
262
 *   properties of this array include #node, #submission, #email, and #format,
263
 *   which can be used to find the context of the submission that is being
264
 *   rendered.
265
 */
266
function hook_webform_submission_render_alter(&$renderable) {
267
  // Remove page breaks from sent e-mails.
268
  if (isset($renderable['#email'])) {
269
    foreach (element_children($renderable) as $key) {
270
      if ($renderable[$key]['#component']['type'] == 'pagebreak') {
271
        unset($renderable[$key]);
272
      }
273
    }
274
  }
275
}
276

    
277
/**
278
 * Modify a loaded Webform component.
279
 *
280
 * IMPORTANT: This hook does not actually exist because components are loaded
281
 * in bulk as part of webform_node_load(). Use hook_node_load() to modify loaded
282
 * components when the node is loaded. This example is provided merely to point
283
 * to hook_node_load().
284
 *
285
 * @see hook_nodeapi()
286
 * @see webform_node_load()
287
 */
288
function hook_webform_component_load() {
289
  // This hook does not exist. Instead use hook_node_load().
290
}
291

    
292
/**
293
 * Modify a Webform component before it is saved to the database.
294
 *
295
 * Note that most of the time this hook is not necessary, because Webform will
296
 * automatically add data to the component based on the component form. Using
297
 * hook_form_alter() will be sufficient in most cases.
298
 *
299
 * @see hook_form_alter()
300
 * @see webform_component_edit_form()
301
 *
302
 * @param $component
303
 *   The Webform component being saved.
304
 */
305
function hook_webform_component_presave(&$component) {
306
  $component['extra']['new_option'] = 'foo';
307
}
308

    
309
/**
310
 * Respond to a Webform component being inserted into the database.
311
 */
312
function hook_webform_component_insert($component) {
313
  // Insert a record into a 3rd-party module table when a component is inserted.
314
  db_insert('mymodule_table')
315
    ->fields(array(
316
      'nid' => $component['nid'],
317
      'cid' => $component['cid'],
318
      'foo' => 'foo_data',
319
    ))
320
    ->execute();
321
}
322

    
323
/**
324
 * Respond to a Webform component being updated in the database.
325
 */
326
function hook_webform_component_update($component) {
327
  // Update a record in a 3rd-party module table when a component is updated.
328
  db_update('mymodule_table')
329
    ->fields(array(
330
      'foo' => 'foo_data',
331
    ))
332
    ->condition('nid', $component['nid'])
333
    ->condition('cid', $component['cid'])
334
    ->execute();
335
}
336

    
337
/**
338
 * Respond to a Webform component being deleted.
339
 */
340
function hook_webform_component_delete($component) {
341
  // Delete a record in a 3rd-party module table when a component is deleted.
342
  db_delete('mymodule_table')
343
    ->condition('nid', $component['nid'])
344
    ->condition('cid', $component['cid'])
345
    ->execute();
346
}
347

    
348
/**
349
 * Alter the entire analysis before rendering to the page on the Analysis tab.
350
 *
351
 * This alter hook allows modification of the entire analysis of a node's
352
 * Webform results. The resulting analysis is displayed on the Results ->
353
 * Analysis tab on the Webform.
354
 *
355
 * @param array $analysis
356
 *   A Drupal renderable array, passed by reference, containing the entire
357
 *   contents of the analysis page. This typically will contain the following
358
 *   two major keys:
359
 *   - form: The form for configuring the shown analysis.
360
 *   - components: The list of analyses for each analysis-enabled component
361
 *     for the node. Each keyed by its component ID.
362
 */
363
function hook_webform_analysis_alter(&$analysis) {
364
  $node = $analysis['#node'];
365

    
366
  // Add an additional piece of information to every component's analysis:
367
  foreach (element_children($analysis['components']) as $cid) {
368
    $component = $node->components[$cid];
369
    $analysis['components'][$cid]['chart'] = array(
370
      '#markup' => t('Chart for the @name component', array('@name' => $component['name'])),
371
    );
372
  }
373
}
374
/**
375
 * Alter data when displaying an analysis on that component.
376
 *
377
 * This hook modifies the data from an individual component's analysis results.
378
 * It can be used to add additional analysis, or to modify the existing results.
379
 * If needing to alter the entire set of analyses rather than an individual
380
 * component, hook_webform_analysis_alter() may be used instead.
381
 *
382
 * @param array $data
383
 *   An array containing the result of a components analysis hook, passed by
384
 *   reference. This is passed directly from a component's
385
 *   _webform_analysis_component() function. See that hook for more information
386
 *   on this value.
387
 * @param object $node
388
 *   The node object that contains the component being analyzed.
389
 * @param array $component
390
 *   The Webform component array whose analysis results are being displayed.
391
 *
392
 * @see _webform_analysis_component()
393
 * @see hook_webform_analysis_alter()
394
 */
395
function hook_webform_analysis_component_data_alter(&$data, $node, $component) {
396
  if ($component['type'] === 'textfield') {
397
    // Do not display rows that contain a zero value.
398
    foreach ($data as $row_number => $row_data) {
399
      if ($row_data[1] === 0) {
400
        unset($data[$row_number]);
401
      }
402
    }
403
  }
404
}
405

    
406
/**
407
 * Alter a Webform submission's header when exported.
408
 */
409
function hook_webform_csv_header_alter(&$header, $component) {
410
  // Use the machine name for component headers, but only for the webform
411
  // with node 5 and components that are text fields.
412
  if ($component['nid'] == 5 && $component['type'] == 'textfield') {
413
    $header[2] = $component['form_key'];
414
  }
415
}
416

    
417
/**
418
 * Alter a Webform submission's data when exported.
419
 */
420
function hook_webform_csv_data_alter(&$data, $component, $submission) {
421
  // If a value of a field was left blank, use the value from another
422
  // field.
423
  if ($component['cid'] == 1 && empty($data)) {
424
    $data = $submission->data[2]['value'][0];
425
  }
426
}
427

    
428
/**
429
 * Define components to Webform.
430
 *
431
 * @return
432
 *   An array of components, keyed by machine name. Required properties are
433
 *   "label" and "description". The "features" array defines which capabilities
434
 *   the component has, such as being displayed in e-mails or csv downloads.
435
 *   A component like "markup" for example would not show in these locations.
436
 *   The possible features of a component include:
437
 *
438
 *     - csv
439
 *     - email
440
 *     - email_address
441
 *     - email_name
442
 *     - required
443
 *     - conditional
444
 *     - spam_analysis
445
 *     - group
446
 *
447
 *   Note that most of these features do not indicate the default state, but
448
 *   determine if the component can have this property at all. Setting
449
 *   "required" to TRUE does not mean that a component's fields will always be
450
 *   required, but instead give the option to the administrator to choose the
451
 *   requiredness. See the example implementation for details on how these
452
 *   features may be set.
453
 *
454
 *   An optional "file" may be specified to be loaded when the component is
455
 *   needed. A set of callbacks will be established based on the name of the
456
 *   component. All components follow the pattern:
457
 *
458
 *   _webform_[callback]_[component]
459
 *
460
 *   Where [component] is the name of the key of the component and [callback] is
461
 *   any of the following:
462
 *
463
 *     - defaults
464
 *     - edit
465
 *     - render
466
 *     - display
467
 *     - submit
468
 *     - delete
469
 *     - help
470
 *     - theme
471
 *     - analysis
472
 *     - table
473
 *     - csv_headers
474
 *     - csv_data
475
 *
476
 * See the sample component implementation for details on each one of these
477
 * callbacks.
478
 *
479
 * @see webform_components()
480
 */
481
function hook_webform_component_info() {
482
  $components = array();
483

    
484
  $components['textfield'] = array(
485
    'label' => t('Textfield'),
486
    'description' => t('Basic textfield type.'),
487
    'features' => array(
488
      // This component includes an analysis callback. Defaults to TRUE.
489
      'analysis' => TRUE,
490

    
491
      // Add content to CSV downloads. Defaults to TRUE.
492
      'csv' => TRUE,
493

    
494
      // This component supports default values. Defaults to TRUE.
495
      'default_value' => FALSE,
496

    
497
      // This component supports a description field. Defaults to TRUE.
498
      'description' => FALSE,
499

    
500
      // Show this component in e-mailed submissions. Defaults to TRUE.
501
      'email' => TRUE,
502

    
503
      // Allow this component to be used as an e-mail FROM or TO address.
504
      // Defaults to FALSE.
505
      'email_address' => FALSE,
506

    
507
      // Allow this component to be used as an e-mail SUBJECT or FROM name.
508
      // Defaults to FALSE.
509
      'email_name' => TRUE,
510

    
511
      // This component may be toggled as required or not. Defaults to TRUE.
512
      'required' => TRUE,
513

    
514
      // This component supports a title attribute. Defaults to TRUE.
515
      'title' => FALSE,
516

    
517
      // This component has a title that can be toggled as displayed or not.
518
      'title_display' => TRUE,
519

    
520
      // This component has a title that can be displayed inline.
521
      'title_inline' => TRUE,
522

    
523
      // If this component can be used as a conditional SOURCE. All components
524
      // may always be displayed conditionally, regardless of this setting.
525
      // Defaults to TRUE.
526
      'conditional' => TRUE,
527

    
528
      // If this component allows other components to be grouped within it
529
      // (like a fieldset or tabs). Defaults to FALSE.
530
      'group' => FALSE,
531

    
532
      // If this component can be used for SPAM analysis, usually with Mollom.
533
      'spam_analysis' => FALSE,
534

    
535
      // If this component saves a file that can be used as an e-mail
536
      // attachment. Defaults to FALSE.
537
      'attachment' => FALSE,
538

    
539
      // If this component reflects a time range and should use labels such as
540
      // "Before" and "After" when exposed as filters in Views module.
541
      'views_range' => FALSE,
542
    ),
543

    
544
    // Specify the conditional behaviour of this component.
545
    // Examples are 'string', 'date', 'time', 'numeric', 'select'.
546
    // Defaults to 'string'.
547
    'conditional_type' => 'string',
548

    
549
    'file' => 'components/textfield.inc',
550
  );
551

    
552
  return $components;
553
}
554

    
555
/**
556
 * Alter the list of available Webform components.
557
 *
558
 * @param $components
559
 *   A list of existing components as defined by hook_webform_component_info().
560
 *
561
 * @see hook_webform_component_info()
562
 */
563
function hook_webform_component_info_alter(&$components) {
564
  // Completely remove a component.
565
  unset($components['grid']);
566

    
567
  // Change the name of a component.
568
  $components['textarea']['label'] = t('Text box');
569
}
570

    
571
/**
572
 * Alter the list of Webform component default values.
573
 *
574
 * @param $defaults
575
 *   A list of component defaults as defined by _webform_defaults_COMPONENT().
576
 * @param $type
577
 *   The component type whose defaults are being provided.
578
 *
579
 * @see _webform_defaults_component()
580
 */
581
function hook_webform_component_defaults_alter(&$defaults, $type) {
582
  // Alter a default for all component types.
583
  $defaults['required'] = 1;
584

    
585
  // Add a default for a new field added via hook_form_alter() or
586
  // hook_form_FORM_ID_alter() for all component types.
587
  $defaults['extra']['added_field'] = t('Added default value');
588

    
589
  // Add or alter defaults for specific component types:
590
  switch ($type) {
591
    case 'select':
592
      $defaults['extra']['optrand'] = 1;
593
      break;
594

    
595
    case 'textfield':
596
    case 'textarea':
597
      $defaults['extra']['another_added_field'] = t('Another added default value');
598
  }
599
}
600

    
601
/**
602
 * Alter access to a Webform submission.
603
 *
604
 * @param $node
605
 *   The Webform node on which this submission was made.
606
 * @param $submission
607
 *   The Webform submission.
608
 * @param $op
609
 *   The operation to be performed on the submission. Possible values are:
610
 *   - "view"
611
 *   - "edit"
612
 *   - "delete"
613
 *   - "list"
614
 * @param $account
615
 *   A user account object.
616
 * @return
617
 *   TRUE if the current user has access to submission,
618
 *   or FALSE otherwise.
619
 */
620
function hook_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
621
  switch ($op) {
622
    case 'view':
623
      return TRUE;
624
      break;
625
    case 'edit':
626
      return FALSE;
627
      break;
628
    case 'delete':
629
      return TRUE;
630
      break;
631
    case 'list':
632
      return TRUE;
633
      break;
634
  }
635
}
636

    
637
/**
638
 * Determine if a user has access to see the results of a webform.
639
 *
640
 * Note in addition to the view access to the results granted here, the $account
641
 * must also have view access to the Webform node in order to see results.
642
 * Access via this hook is in addition (adds permission) to the standard
643
 * webform access.
644
 *
645
 * @see webform_results_access().
646
 *
647
 * @param $node
648
 *   The Webform node to check access on.
649
 * @param $account
650
 *   The user account to check access on.
651
 * @return
652
 *   TRUE or FALSE if the user can access the webform results.
653
 */
654
function hook_webform_results_access($node, $account) {
655
  // Let editors view results of unpublished webforms.
656
  if ($node->status == 0 && in_array('editor', $account->roles)) {
657
    return TRUE;
658
  }
659
  else {
660
    return FALSE;
661
  }
662
}
663

    
664
/**
665
 * Determine if a user has access to clear the results of a webform.
666
 *
667
 * Access via this hook is in addition (adds permission) to the standard
668
 * webform access (delete all webform submissions).
669
 *
670
 * @see webform_results_clear_access().
671
 *
672
 * @param object $node
673
 *   The Webform node to check access on.
674
 * @param object $account
675
 *   The user account to check access on.
676
 * @return boolean
677
 *   TRUE or FALSE if the user can access the webform results.
678
 */
679
function hook_webform_results_clear_access($node, $account) {
680
  return user_access('my additional access', $account);
681
}
682

    
683
/**
684
 * Overrides the node_access and user_access permission to access and edit
685
 * webform components, e-mails, conditions, and form settings.
686
 *
687
 * Return NULL to defer to other modules. If all implementations defer, then
688
 * access to the node's EDIT tab plus 'edit webform components' permission
689
 * determines access. To grant access, return TRUE; to deny access, return
690
 * FALSE. If more than one implementation return TRUE/FALSE, all must be TRUE
691
 * to grant access.
692
 *
693
 * In this way, access to the EDIT tab of the node may be decoupled from
694
 * access to the WEBFORM tab. When returning TRUE, consider all aspects of
695
 * access as this will be the only test. For example, 'return TRUE;' would grant
696
 * annonymous access to creating webform components, which seldom be desired.
697
 *
698
 * @see webform_node_update_access().
699
 *
700
 * @param object $node
701
 *   The Webform node to check access on.
702
 * @param object $account
703
 *   The user account to check access on.
704
 * @return boolean|NULL
705
 *   TRUE or FALSE if the user can access the webform results, or NULL if
706
 *   access should be deferred to other implementations of this hook or
707
 *   node_access('update') plus user_access('edit webform components').
708
 */
709
function hook_webform_update_access($node, $account) {
710
  // Allow anyone who can see webform_editable_by_user nodes and who has
711
  // 'my webform component edit access' permission to see, edit, and delete the
712
  // webform components, e-mails, conditionals, and form settings.
713
  if ($node->type == 'webform_editable_by_user') {
714
    return node_access('view', $node, $account) && user_access('my webform component edit access', $account);
715
  }
716
}
717

    
718

    
719
/**
720
 * Return an array of files associated with the component.
721
 *
722
 * The output of this function will be used to attach files to e-mail messages.
723
 *
724
 * @param $component
725
 *   A Webform component array.
726
 * @param $value
727
 *   An array of information containing the submission result, directly
728
 *   correlating to the webform_submitted_data database schema.
729
 * @return
730
 *   An array of files, each file is an array with following keys:
731
 *     - filepath: The relative path to the file.
732
 *     - filename: The name of the file including the extension.
733
 *     - filemime: The mimetype of the file.
734
 *   This will result in an array looking something like this:
735
 *   @code
736
 *   array[0] => array(
737
 *     'filepath' => '/sites/default/files/attachment.txt',
738
 *     'filename' => 'attachment.txt',
739
 *     'filemime' => 'text/plain',
740
 *   );
741
 *   @endcode
742
 */
743
function _webform_attachments_component($component, $value) {
744
  $files = array();
745
  $files[] = (array) file_load($value[0]);
746
  return $files;
747
}
748

    
749

    
750
/**
751
 * Alter default settings for a newly created webform node.
752
 *
753
 * @param array $defaults
754
 *   Default settings for a newly created webform node as defined by webform_node_defaults().
755
 *
756
 * @see webform_node_defaults()
757
 */
758
function hook_webform_node_defaults_alter(&$defaults) {
759
  $defaults['allow_draft'] = '1';
760
}
761

    
762
/**
763
 * Add additional fields to submission data downloads.
764
 *
765
 * @return
766
 *   Keys and titles for default submission information.
767
 *
768
 * @see hook_webform_results_download_submission_information_data()
769
 */
770
function hook_webform_results_download_submission_information_info() {
771
  return array(
772
    'field_key_1' => t('Field Title 1'),
773
    'field_key_2' => t('Field Title 2'),
774
  );
775
}
776

    
777
/**
778
 * Return values for submission data download fields.
779
 *
780
 * @param $token
781
 *   The name of the token being replaced.
782
 * @param $submission
783
 *   The data for an individual submission from webform_get_submissions().
784
 * @param $options
785
 *   A list of options that define the output format. These are generally passed
786
 *   through from the GUI interface.
787
 * @param $serial_start
788
 *   The starting position for the Serial column in the output.
789
 * @param $row_count
790
 *   The number of the row being generated.
791
 *
792
 * @return
793
 *   Value for requested submission information field.
794
 *
795
 * @see hook_webform_results_download_submission_information_info()
796
 */
797
function hook_webform_results_download_submission_information_data($token, $submission, array $options, $serial_start, $row_count) {
798
  switch ($token) {
799
    case 'field_key_1':
800
      return 'Field Value 1';
801
    case 'field_key_2':
802
      return 'Field Value 2';
803
  }
804
}
805

    
806
/**
807
 * @}
808
 */
809

    
810
/**
811
 * @defgroup webform_component Sample Webform Component
812
 * @{
813
 * In each of these examples, the word "component" should be replaced with the,
814
 * name of the component type (such as textfield or select). These are not
815
 * actual hooks, but instead samples of how Webform integrates with its own
816
 * built-in components.
817
 */
818

    
819
/**
820
 * Specify the default properties of a component.
821
 *
822
 * @return
823
 *   An array defining the default structure of a component.
824
 */
825
function _webform_defaults_component() {
826
  return array(
827
    'name' => '',
828
    'form_key' => NULL,
829
    'required' => 0,
830
    'pid' => 0,
831
    'weight' => 0,
832
    'extra' => array(
833
      'options' => '',
834
      'questions' => '',
835
      'optrand' => 0,
836
      'qrand' => 0,
837
      'description' => '',
838
      'description_above' => FALSE,
839
      'private' => FALSE,
840
      'analysis' => TRUE,
841
    ),
842
  );
843
}
844

    
845
/**
846
 * Generate the form for editing a component.
847
 *
848
 * Create a set of form elements to be displayed on the form for editing this
849
 * component. Use care naming the form items, as this correlates directly to the
850
 * database schema. The component "Name" and "Description" fields are added to
851
 * every component type and are not necessary to specify here (although they
852
 * may be overridden if desired).
853
 *
854
 * @param $component
855
 *   A Webform component array.
856
 * @return
857
 *   An array of form items to be displayed on the edit component page
858
 */
859
function _webform_edit_component($component) {
860
  $form = array();
861

    
862
  // Disabling the description if not wanted.
863
  $form['description'] = array();
864

    
865
  // Most options are stored in the "extra" array, which stores any settings
866
  // unique to a particular component type.
867
  $form['extra']['options'] = array(
868
    '#type' => 'textarea',
869
    '#title' => t('Options'),
870
    '#default_value' => $component['extra']['options'],
871
    '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . ' ' . theme('webform_token_help'),
872
    '#cols' => 60,
873
    '#rows' => 5,
874
    '#weight' => -3,
875
    '#required' => TRUE,
876
  );
877
  return $form;
878
}
879

    
880
/**
881
 * Render a Webform component to be part of a form.
882
 *
883
 * @param $component
884
 *   A Webform component array.
885
 * @param $value
886
 *   If editing an existing submission or resuming a draft, this will contain
887
 *   an array of values to be shown instead of the default in the component
888
 *   configuration. This value will always be an array, keyed numerically for
889
 *   each value saved in this field.
890
 * @param $filter
891
 *   Whether or not to filter the contents of descriptions and values when
892
 *   rendering the component. Values need to be unfiltered to be editable by
893
 *   Form Builder.
894
 * @param $submission
895
 *   The submission from which this component is being rendered. Usually not
896
 *   needed. Used by _webform_render_date() to validate using the submission's
897
 *   completion date.
898
 *
899
 * @see _webform_client_form_add_component()
900
 */
901
function _webform_render_component($component, $value = NULL, $filter = TRUE, $submission = NULL) {
902
  $form_item = array(
903
    '#type' => 'textfield',
904
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
905
    '#required' => $component['required'],
906
    '#weight' => $component['weight'],
907
    '#description'   => $filter ? webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
908
    '#default_value' => $filter ? webform_replace_tokens($component['value']) : $component['value'],
909
    '#theme_wrappers' => array('webform_element'),
910
  );
911

    
912
  if (isset($value)) {
913
    $form_item['#default_value'] = $value[0];
914
  }
915

    
916
  return $form_item;
917
}
918

    
919
/**
920
 * Allow modules to modify a webform component that is going to be rendered in a form.
921
 *
922
 * @param array $element
923
 *   The display element as returned by _webform_render_component().
924
 * @param array $component
925
 *   A Webform component array.
926
 *
927
 * @see _webform_render_component()
928
 */
929
function hook_webform_component_render_alter(&$element, &$component) {
930
  if ($component['cid'] == 10) {
931
    $element['#title'] = 'My custom title';
932
    $element['#default_value'] = 42;
933
  }
934
}
935

    
936
/**
937
 * Display the result of a submission for a component.
938
 *
939
 * The output of this function will be displayed under the "Results" tab then
940
 * "Submissions". This should output the saved data in some reasonable manner.
941
 *
942
 * @param $component
943
 *   A Webform component array.
944
 * @param $value
945
 *   An array of information containing the submission result, directly
946
 *   correlating to the webform_submitted_data database table schema.
947
 * @param $format
948
 *   Either 'html' or 'text'. Defines the format that the content should be
949
 *   returned as. Make sure that returned content is run through check_plain()
950
 *   or other filtering functions when returning HTML.
951
 * @param $submission
952
 *   The submission. Used to generate tokens.
953
 * @return
954
 *   A renderable element containing at the very least these properties:
955
 *    - #title
956
 *    - #weight
957
 *    - #component
958
 *    - #format
959
 *    - #value
960
 *   Webform also uses #theme_wrappers to output the end result to the user,
961
 *   which will properly format the label and content for use within an e-mail
962
 *   (such as wrapping the text) or as HTML (ensuring consistent output).
963
 */
964
function _webform_display_component($component, $value, $format = 'html', $submission = array()) {
965
  return array(
966
    '#title' => $component['name'],
967
    '#weight' => $component['weight'],
968
    '#theme' => 'webform_display_textfield',
969
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
970
    '#post_render' => array('webform_element_wrapper'),
971
    '#field_prefix' => $component['extra']['field_prefix'],
972
    '#field_suffix' => $component['extra']['field_suffix'],
973
    '#component' => $component,
974
    '#format' => $format,
975
    '#value' => isset($value[0]) ? $value[0] : '',
976
  );
977
}
978

    
979
/**
980
 * Allow modules to modify a "display only" webform component.
981
 *
982
 * @param array $element
983
 *   The display element as returned by _webform_display_component().
984
 * @param array $component
985
 *   A Webform component array.
986
 *
987
 * @see _webform_display_component()
988
 */
989
function hook_webform_component_display_alter(&$element, &$component) {
990
  if ($component['cid'] == 10) {
991
    $element['#title'] = 'My custom title';
992
    $element['#default_value'] = 42;
993
  }
994
}
995

    
996
/**
997
 * Performs the conditional action set on an implemented component.
998
 *
999
 * Setting the form element allows form validation functions to see the value
1000
 * that webform has set for the given component.
1001
 *
1002
 * @param array $component
1003
 *   The webform component array whose value is being set for the currently-
1004
 *   edited submission.
1005
 * @param array $element
1006
 *   The form element currently being set.
1007
 * @param array $form_state
1008
 *   The form's state.
1009
 * @param string $value
1010
 *   The value to be set, as defined in the conditional action.
1011
 */
1012
function _webform_action_set_component($component, &$element, &$form_state, $value) {
1013
  $element['#value'] = $value;
1014
  form_set_value($element, $value, $form_state);
1015
}
1016

    
1017
/**
1018
 * A hook for changing the input values before saving to the database.
1019
 *
1020
 * Webform expects a component to consist of a single field, or a single array
1021
 * of fields. If you have a component that requires a deeper form tree
1022
 * you must flatten the data into a single array using this callback
1023
 * or by setting #parents on each field to avoid data loss and/or unexpected
1024
 * behavior.
1025
 *
1026
 * Note that Webform will save the result of this function directly into the
1027
 * database.
1028
 *
1029
 * @param $component
1030
 *   A Webform component array.
1031
 * @param $value
1032
 *   The POST data associated with the user input.
1033
 * @return
1034
 *   An array of values to be saved into the database. Note that this should be
1035
 *   a numerically keyed array.
1036
 */
1037
function _webform_submit_component($component, $value) {
1038
  // Clean up a phone number into 123-456-7890 format.
1039
  if ($component['extra']['phone_number']) {
1040
    $number = preg_replace('/[^0-9]/', '', $value[0]);
1041
    if (strlen($number) == 7) {
1042
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
1043
    }
1044
    else {
1045
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
1046
    }
1047
  }
1048

    
1049
  $value[0] = $number;
1050
  return $value;
1051
}
1052

    
1053
/**
1054
 * Delete operation for a component or submission.
1055
 *
1056
 * @param $component
1057
 *   A Webform component array.
1058
 * @param $value
1059
 *   An array of information containing the submission result, directly
1060
 *   correlating to the webform_submitted_data database schema.
1061
 */
1062
function _webform_delete_component($component, $value) {
1063
  // Delete corresponding files when a submission is deleted.
1064
  if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
1065
    file_usage_delete($file, 'webform');
1066
    file_delete($file);
1067
  }
1068
}
1069

    
1070
/**
1071
 * Module specific instance of hook_help().
1072
 *
1073
 * This allows each Webform component to add information into hook_help().
1074
 */
1075
function _webform_help_component($section) {
1076
  switch ($section) {
1077
    case 'admin/config/content/webform#grid_description':
1078
      return t('Allows creation of grid questions, denoted by radio buttons.');
1079
  }
1080
}
1081

    
1082
/**
1083
 * Module specific instance of hook_theme().
1084
 *
1085
 * This allows each Webform component to add information into hook_theme(). If
1086
 * you specify a file to include, you must define the path to the module that
1087
 * this file belongs to.
1088
 */
1089
function _webform_theme_component() {
1090
  return array(
1091
    'webform_grid' => array(
1092
      'render element' => 'element',
1093
      'file' => 'components/grid.inc',
1094
      'path' => drupal_get_path('module', 'webform'),
1095
    ),
1096
    'webform_display_grid' => array(
1097
      'render element' => 'element',
1098
      'file' => 'components/grid.inc',
1099
      'path' => drupal_get_path('module', 'webform'),
1100
    ),
1101
  );
1102
}
1103

    
1104
/**
1105
 * Calculate and returns statistics about results for this component.
1106
 *
1107
 * This takes into account all submissions to this webform. The output of this
1108
 * function will be displayed under the "Results" tab then "Analysis".
1109
 *
1110
 * @param $component
1111
 *   An array of information describing the component, directly correlating to
1112
 *   the webform_component database schema.
1113
 * @param $sids
1114
 *   An optional array of submission IDs (sid). If supplied, the analysis will
1115
 *   be limited to these sids.
1116
 * @param $single
1117
 *   Boolean flag determining if the details about a single component are being
1118
 *   shown. May be used to provided detailed information about a single
1119
 *   component's analysis, such as showing "Other" options within a select list.
1120
 * @param $join
1121
 *   An optional SelectQuery object to be used to join with the submissions
1122
 *   table to restrict the submissions being analyzed.
1123
 * @return
1124
 *   An array containing one or more of the following keys:
1125
 *   - table_rows: If this component has numeric data that can be represented in
1126
 *     a grid, return the values here. This array assumes a 2-dimensional
1127
 *     structure, with the first value being a label and subsequent values
1128
 *     containing a decimal or integer.
1129
 *   - table_header: If this component has more than a single set of values,
1130
 *     include a table header so each column can be labeled.
1131
 *   - other_data: If your component has non-numeric data to include, such as
1132
 *     a description or link, include that in the other_data array. Each item
1133
 *     may be a string or an array of values that matches the number of columns
1134
 *     in the table_header property.
1135
 *   At the very least, either table_rows or other_data should be provided.
1136
 *   Note that if you want your component's analysis to be available by default
1137
 *   without the user specifically enabling it, you must set
1138
 *   $component['extra']['analysis'] = TRUE in your
1139
 *   _webform_defaults_component() callback.
1140
 *
1141
 * @see _webform_defaults_component()
1142
 */
1143
function _webform_analysis_component($component, $sids = array(), $single = FALSE, $join = NULL) {
1144
  // Generate the list of options and questions.
1145
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
1146
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
1147

    
1148
  // Generate a lookup table of results.
1149
  $query = db_select('webform_submitted_data', 'wsd')
1150
    ->fields('wsd', array('no', 'data'))
1151
    ->condition('nid', $component['nid'])
1152
    ->condition('cid', $component['cid'])
1153
    ->condition('data', '', '<>')
1154
    ->groupBy('no')
1155
    ->groupBy('data');
1156
  $query->addExpression('COUNT(sid)', 'datacount');
1157

    
1158
  if (count($sids)) {
1159
    $query->condition('sid', $sids, 'IN');
1160
  }
1161

    
1162
  if ($join) {
1163
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
1164
  }
1165

    
1166
  $result = $query->execute();
1167
  $counts = array();
1168
  foreach ($result as $data) {
1169
    $counts[$data->no][$data->data] = $data->datacount;
1170
  }
1171

    
1172
  // Create an entire table to be put into the returned row.
1173
  $rows = array();
1174
  $header = array('');
1175

    
1176
  // Add options as a header row.
1177
  foreach ($options as $option) {
1178
    $header[] = $option;
1179
  }
1180

    
1181
  // Add questions as each row.
1182
  foreach ($questions as $qkey => $question) {
1183
    $row = array($question);
1184
    foreach ($options as $okey => $option) {
1185
      $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
1186
    }
1187
    $rows[] = $row;
1188
  }
1189

    
1190
  $other = array();
1191
  $other[] = l(t('More information'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']);
1192

    
1193
  return array(
1194
    'table_header' => $header,
1195
    'table_rows' => $rows,
1196
    'other_data' => $other,
1197
  );
1198
}
1199

    
1200
/**
1201
 * Return the result of a component value for display in a table.
1202
 *
1203
 * The output of this function will be displayed under the "Results" tab then
1204
 * "Table".
1205
 *
1206
 * @param $component
1207
 *   A Webform component array.
1208
 * @param $value
1209
 *   An array of information containing the submission result, directly
1210
 *   correlating to the webform_submitted_data database schema.
1211
 * @return
1212
 *   Textual output formatted for human reading.
1213
 */
1214
function _webform_table_component($component, $value) {
1215
  $questions = array_values(_webform_component_options($component['extra']['questions']));
1216
  $output = '';
1217
  // Set the value as a single string.
1218
  if (is_array($value)) {
1219
    foreach ($value as $item => $value) {
1220
      if ($value !== '') {
1221
        $output .= $questions[$item] . ': ' . check_plain($value) . '<br />';
1222
      }
1223
    }
1224
  }
1225
  else {
1226
    $output = check_plain(!isset($value['0']) ? '' : $value['0']);
1227
  }
1228
  return $output;
1229
}
1230

    
1231
/**
1232
 * Return the header for this component to be displayed in a CSV file.
1233
 *
1234
 * The output of this function will be displayed under the "Results" tab then
1235
 * "Download".
1236
 *
1237
 * @param $component
1238
 *   A Webform component array.
1239
 * @param $export_options
1240
 *   An array of options that may configure export of this field.
1241
 * @return
1242
 *   An array of data to be displayed in the first three rows of a CSV file, not
1243
 *   including either prefixed or trailing commas.
1244
 */
1245
function _webform_csv_headers_component($component, $export_options) {
1246
  $header = array();
1247
  $header[0] = array('');
1248
  $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name']);
1249
  $items = _webform_component_options($component['extra']['questions']);
1250
  $count = 0;
1251
  foreach ($items as $key => $item) {
1252
    // Empty column per sub-field in main header.
1253
    if ($count != 0) {
1254
      $header[0][] = '';
1255
      $header[1][] = '';
1256
    }
1257
    // The value for this option.
1258
    $header[2][] = $item;
1259
    $count++;
1260
  }
1261

    
1262
  return $header;
1263
}
1264

    
1265
/**
1266
 * Format the submitted data of a component for CSV downloading.
1267
 *
1268
 * The output of this function will be displayed under the "Results" tab then
1269
 * "Download".
1270
 *
1271
 * @param $component
1272
 *   A Webform component array.
1273
 * @param $export_options
1274
 *   An array of options that may configure export of this field.
1275
 * @param $value
1276
 *   An array of information containing the submission result, directly
1277
 *   correlating to the webform_submitted_data database schema.
1278
 * @return
1279
 *   An array of items to be added to the CSV file. Each value within the array
1280
 *   will be another column within the file. This function is called once for
1281
 *   every row of data.
1282
 */
1283
function _webform_csv_data_component($component, $export_options, $value) {
1284
  $questions = array_keys(_webform_select_options($component['extra']['questions']));
1285
  $return = array();
1286
  foreach ($questions as $key => $question) {
1287
    $return[] = isset($value[$key]) ? $value[$key] : '';
1288
  }
1289
  return $return;
1290
}
1291

    
1292
/**
1293
 * Adjusts the view field(s) that are automatically generated for number
1294
 * components.
1295
 *
1296
 * Provides each component the opportunity to adjust how this component is
1297
 * displayed in a view as a field in a view table. For example, a component may
1298
 * modify how it responds to click-sorting. Or it may add additional fields,
1299
 * such as a grid component having a column for each question.
1300
 *
1301
 * @param array $component
1302
 *   A Webform component array
1303
 * @param array $fields
1304
 *   An array of field-definition arrays. Will be passed one field definition,
1305
 *   which may be modified. Additional fields may be added to the array.
1306
 * @return array
1307
 *   The modified $fields array.
1308
 */
1309
function _webform_view_field_component($component, $fields) {
1310
  foreach ($fields as &$field) {
1311
    $field['webform_datatype'] = 'number';
1312
  }
1313
  return $fields;
1314
}
1315

    
1316
/**
1317
 * Modify the how a view was expanded to show all the components.
1318
 *
1319
 * This alter function is only called when the view is actually modified. It
1320
 * provides modules an opportunity to alter the changes that webform made to
1321
 * the view.
1322
 *
1323
 * This hook is called from webform_views_pre_view. If another module also
1324
 * changes views by implementing this same views hook, the relative order of
1325
 * execution of the two implementations will depend upon the module weights of
1326
 * the two modules. Using hook_webform_view_alter instead guarantees an
1327
 * opportuinty to modify the view AFTER webform.
1328
 *
1329
 * @param object $view
1330
 *   The view object.
1331
 * @param string $display_id
1332
 *   The display_id that was expanded by webform.
1333
 * @param array $args
1334
 *   The argumentst that were passed to the view.
1335
 */
1336
function hook_webform_view_alter($view, $display_id, $args) {
1337
  // Don't show component with cid == 4
1338
  $fields = $view->get_items('field', $display_id);
1339
  foreach ($fields as $id => $field) {
1340
    if (isset($field['webform_cid']) && $field['webform_cid'] == 4) {
1341
      unset($fields[$id]);
1342
    }
1343
  }
1344
  $view->display[$display_id]->handler->set_option('fields', $fields);
1345
}
1346

    
1347
/**
1348
 * Modify the list of mail systems that are capable of sending HTML email.
1349
 *
1350
 * @param array &$systems
1351
 *   An array of mail system class names.
1352
 */
1353
function hook_webform_html_capable_mail_systems_alter(&$systems) {
1354
  if (module_exists('my_module')) {
1355
    $systems[] = 'MyModuleMailSystem';
1356
  }
1357
}
1358

    
1359
/**
1360
 * Define a list of webform exporters.
1361
 *
1362
 * @return array
1363
 *   A list of the available exporters provided by the module.
1364
 *
1365
 * @see webform_webform_exporters()
1366
 */
1367
function hook_webform_exporters() {
1368
  $exporters = array(
1369
    'webform_exporter_custom' => array(
1370
      'title' => t('Webform exporter name'),
1371
      'description' => t('The description for this exporter.'),
1372
      'handler' => 'webform_exporter_custom',
1373
      'file' => drupal_get_path('module', 'yourmodule') . '/includes/webform_exporter_custom.inc',
1374
      'weight' => 10,
1375
    ),
1376
  );
1377

    
1378
  return $exporters;
1379
}
1380

    
1381
/**
1382
 * Modify the list of webform exporters definitions.
1383
 *
1384
 * @param  array &$exporters
1385
 *   A list of all available webform exporters.
1386
 */
1387
function hook_webform_exporters_alter(&$exporters) {
1388
  $exporters['excel']['handler'] = 'customized_excel_exporter';
1389
  $exporters['excel']['file'] = drupal_get_path('module', 'yourmodule') . '/includes/customized_excel_exporter.inc';
1390
}
1391

    
1392
/**
1393
 * @}
1394
 */