Projet

Général

Profil

Paste
Télécharger (50,5 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / webform / webform.api.php @ 7b2d1845

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 array
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 a function implementing
33
 *       callback_webform_options() that will return the list.
34
 *     - options arguments: Any additional arguments to send to the callback.
35
 *     - file: Optional. The file containing the options callback, relative to
36
 *       the module root.
37
 */
38
function hook_webform_select_options_info() {
39
  $items = array();
40

    
41
  $items['days'] = array(
42
    'title' => t('Days of the week'),
43
    'options callback' => 'webform_options_days',
44
    'file' => 'includes/webform.options.inc',
45
  );
46

    
47
  return $items;
48
}
49

    
50
/**
51
 * Alter the list of select list options provided by Webform and other modules.
52
 *
53
 * @see hook_webform_select_options_info()
54
 */
55
function hook_webform_select_options_info_alter(&$items) {
56
  // Remove the days of the week options.
57
  unset($items['days']);
58
}
59

    
60
/**
61
 * Define a list of options that Webform may use in a select component.
62
 *
63
 * Callback for hook_webform_select_options_info().
64
 *
65
 * @param $component
66
 *   The Webform component array for the select component being displayed.
67
 * @param $flat
68
 *   Boolean value indicating whether the returned list needs to be a flat array
69
 *   of key => value pairs. Select components support up to one level of
70
 *   nesting, but when results are displayed, the list needs to be returned
71
 *   without the nesting.
72
 * @param $arguments
73
 *   The "options arguments" specified in hook_webform_select_options_info().
74
 *
75
 * @return array
76
 *   An array of key => value pairs suitable for a select list's #options
77
 *   FormAPI property.
78
 */
79
function callback_webform_options($component, $flat, $arguments) {
80
  $options = array(
81
    'one' => t('Pre-built option one'),
82
    'two' => t('Pre-built option two'),
83
    'three' => t('Pre-built option three'),
84
  );
85

    
86
  return $options;
87
}
88

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

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

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

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

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

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

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

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

    
231
  return $actions;
232
}
233

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

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

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

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

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

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

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

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

    
368
  // Add an additional piece of information to every component's analysis:
369
  foreach (element_children($analysis['components']) as $cid) {
370
    $component = $node->components[$cid];
371
    $analysis['components'][$cid]['chart'] = array(
372
      '#markup' => t('Chart for the @name component', array('@name' => $component['name'])),
373
    );
374
  }
375
}
376

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

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

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

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

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

    
495
      // Add content to CSV downloads. Defaults to TRUE.
496
      'csv' => TRUE,
497

    
498
      // This component supports default values. Defaults to TRUE.
499
      'default_value' => FALSE,
500

    
501
      // This component supports a description field. Defaults to TRUE.
502
      'description' => FALSE,
503

    
504
      // Show this component in e-mailed submissions. Defaults to TRUE.
505
      'email' => TRUE,
506

    
507
      // Allow this component to be used as an e-mail FROM or TO address.
508
      // Defaults to FALSE.
509
      'email_address' => FALSE,
510

    
511
      // Allow this component to be used as an e-mail SUBJECT or FROM name.
512
      // Defaults to FALSE.
513
      'email_name' => TRUE,
514

    
515
      // This component may be toggled as required or not. Defaults to TRUE.
516
      'required' => TRUE,
517

    
518
      // Store data in database. Defaults to TRUE. When FALSE, submission data
519
      // will never be saved. This is for components like fieldset, markup, and
520
      // pagebreak which do not collect data.
521
      'stores_data' => TRUE,
522

    
523
      // This component supports a title attribute. Defaults to TRUE.
524
      'title' => FALSE,
525

    
526
      // This component has a title that can be toggled as displayed or not.
527
      'title_display' => TRUE,
528

    
529
      // This component has a title that can be displayed inline.
530
      'title_inline' => TRUE,
531

    
532
      // If this component can be used as a conditional SOURCE. All components
533
      // may always be displayed conditionally, regardless of this setting.
534
      // Defaults to TRUE.
535
      'conditional' => TRUE,
536

    
537
      // If this component allows other components to be grouped within it
538
      // (like a fieldset or tabs). Defaults to FALSE.
539
      'group' => FALSE,
540

    
541
      // If this component can be used for SPAM analysis.
542
      'spam_analysis' => FALSE,
543

    
544
      // If this component saves a file that can be used as an e-mail
545
      // attachment. Defaults to FALSE.
546
      'attachment' => FALSE,
547

    
548
      // If this component reflects a time range and should use labels such as
549
      // "Before" and "After" when exposed as filters in Views module.
550
      'views_range' => FALSE,
551

    
552
      // Set this to FALSE if this component cannot be used as a private
553
      // component. If this is not FALSE, in your implementation of
554
      // _webform_defaults_COMPONENT(), set ['extra']['private'] property to
555
      // TRUE or FALSE.
556
      'private' => FALSE,
557
    ),
558

    
559
    // Specify the conditional behaviour of this component.
560
    // Examples are 'string', 'date', 'time', 'numeric', 'select'.
561
    // Defaults to 'string'.
562
    'conditional_type' => 'string',
563

    
564
    'file' => 'components/textfield.inc',
565
  );
566

    
567
  return $components;
568
}
569

    
570
/**
571
 * Alter the list of available Webform components.
572
 *
573
 * @param $components
574
 *   A list of existing components as defined by hook_webform_component_info().
575
 *
576
 * @see hook_webform_component_info()
577
 */
578
function hook_webform_component_info_alter(&$components) {
579
  // Completely remove a component.
580
  unset($components['grid']);
581

    
582
  // Change the name of a component.
583
  $components['textarea']['label'] = t('Text box');
584
}
585

    
586
/**
587
 * Alter the list of Webform component default values.
588
 *
589
 * @param $defaults
590
 *   A list of component defaults as defined by _webform_defaults_COMPONENT().
591
 * @param $type
592
 *   The component type whose defaults are being provided.
593
 *
594
 * @see _webform_defaults_component()
595
 */
596
function hook_webform_component_defaults_alter(&$defaults, $type) {
597
  // Alter a default for all component types.
598
  $defaults['required'] = 1;
599

    
600
  // Add a default for a new field added via hook_form_alter() or
601
  // hook_form_FORM_ID_alter() for all component types.
602
  $defaults['extra']['added_field'] = t('Added default value');
603

    
604
  // Add or alter defaults for specific component types:
605
  switch ($type) {
606
    case 'select':
607
      $defaults['extra']['optrand'] = 1;
608
      break;
609

    
610
    case 'textfield':
611
    case 'textarea':
612
      $defaults['extra']['another_added_field'] = t('Another added default value');
613
  }
614
}
615

    
616
/**
617
 * Alter access to a Webform submission.
618
 *
619
 * @param $node
620
 *   The Webform node on which this submission was made.
621
 * @param $submission
622
 *   The Webform submission.
623
 * @param $op
624
 *   The operation to be performed on the submission. Possible values are:
625
 *   - "view"
626
 *   - "edit"
627
 *   - "delete"
628
 *   - "list"
629
 * @param $account
630
 *   A user account object.
631
 *
632
 * @return bool
633
 *   TRUE if the current user has access to submission,
634
 *   or FALSE otherwise.
635
 */
636
function hook_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
637
  switch ($op) {
638
    case 'view':
639
      return TRUE;
640

    
641
    case 'edit':
642
      return FALSE;
643

    
644
    case 'delete':
645
      return TRUE;
646

    
647
    case 'list':
648
      return TRUE;
649
  }
650
}
651

    
652
/**
653
 * Determine if a user has access to see the results of a webform.
654
 *
655
 * Note in addition to the view access to the results granted here, the $account
656
 * must also have view access to the Webform node in order to see results.
657
 * Access via this hook is in addition (adds permission) to the standard
658
 * webform access.
659
 *
660
 * @param $node
661
 *   The Webform node to check access on.
662
 * @param $account
663
 *   The user account to check access on.
664
 *
665
 * @return bool
666
 *   TRUE or FALSE if the user can access the webform results.
667
 *
668
 * @see webform_results_access()
669
 */
670
function hook_webform_results_access($node, $account) {
671
  // Let editors view results of unpublished webforms.
672
  if ($node->status == 0 && in_array('editor', $account->roles)) {
673
    return TRUE;
674
  }
675
  else {
676
    return FALSE;
677
  }
678
}
679

    
680
/**
681
 * Determine if a user has access to clear the results of a webform.
682
 *
683
 * Access via this hook is in addition (adds permission) to the standard
684
 * webform access (delete all webform submissions).
685
 *
686
 * @param object $node
687
 *   The Webform node to check access on.
688
 * @param object $account
689
 *   The user account to check access on.
690
 *
691
 * @return bool
692
 *   TRUE or FALSE if the user can access the webform results.
693
 *
694
 * @see webform_results_clear_access()
695
 */
696
function hook_webform_results_clear_access($node, $account) {
697
  return user_access('my additional access', $account);
698
}
699

    
700
/**
701
 * Overrides the node_access and user_access permissions.
702
 *
703
 * Overrides the node_access and user_access permission to access and edit
704
 * webform components, e-mails, conditions, and form settings.
705
 *
706
 * Return NULL to defer to other modules. If all implementations defer, then
707
 * access to the node's EDIT tab plus 'edit webform components' permission
708
 * determines access. To grant access, return TRUE; to deny access, return
709
 * FALSE. If more than one implementation return TRUE/FALSE, all must be TRUE
710
 * to grant access.
711
 *
712
 * In this way, access to the EDIT tab of the node may be decoupled from
713
 * access to the WEBFORM tab. When returning TRUE, consider all aspects of
714
 * access as this will be the only test. For example, 'return TRUE;' would grant
715
 * annonymous access to creating webform components, which seldom be desired.
716
 *
717
 * @param object $node
718
 *   The Webform node to check access on.
719
 * @param object $account
720
 *   The user account to check access on.
721
 *
722
 * @return bool|null
723
 *   TRUE or FALSE if the user can access the webform results, or NULL if
724
 *   access should be deferred to other implementations of this hook or
725
 *   node_access('update') plus user_access('edit webform components').
726
 *
727
 * @see webform_node_update_access()
728
 */
729
function hook_webform_update_access($node, $account) {
730
  // Allow anyone who can see webform_editable_by_user nodes and who has
731
  // 'my webform component edit access' permission to see, edit, and delete the
732
  // webform components, e-mails, conditionals, and form settings.
733
  if ($node->type == 'webform_editable_by_user') {
734
    return node_access('view', $node, $account) && user_access('my webform component edit access', $account);
735
  }
736
}
737

    
738
/**
739
 * Return an array of files associated with the component.
740
 *
741
 * The output of this function will be used to attach files to e-mail messages.
742
 *
743
 * @param $component
744
 *   A Webform component array.
745
 * @param $value
746
 *   An array of information containing the submission result, directly
747
 *   correlating to the webform_submitted_data database schema.
748
 *
749
 * @return array
750
 *   An array of files, each file is an array with following keys:
751
 *     - filepath: The relative path to the file.
752
 *     - filename: The name of the file including the extension.
753
 *     - filemime: The mimetype of the file.
754
 *   This will result in an array looking something like this:
755
 *
756
 * @code
757
 *   array[0] => array(
758
 *     'filepath' => '/sites/default/files/attachment.txt',
759
 *     'filename' => 'attachment.txt',
760
 *     'filemime' => 'text/plain',
761
 *   );
762
 * @endcode
763
 */
764
function _webform_attachments_component($component, $value) {
765
  $files = array();
766
  $files[] = (array) file_load($value[0]);
767
  return $files;
768
}
769

    
770
/**
771
 * Alter default settings for a newly created webform node.
772
 *
773
 * @param array $defaults
774
 *   Default settings for a newly created webform node as defined by
775
 *   webform_node_defaults().
776
 *
777
 * @see webform_node_defaults()
778
 */
779
function hook_webform_node_defaults_alter(array &$defaults) {
780
  $defaults['allow_draft'] = '1';
781
}
782

    
783
/**
784
 * Add additional fields to submission data downloads.
785
 *
786
 * @return array
787
 *   Keys and titles for default submission information.
788
 *
789
 * @see hook_webform_results_download_submission_information_data()
790
 * @see hook_webform_results_download_submission_information_info_alter()
791
 */
792
function hook_webform_results_download_submission_information_info() {
793
  return array(
794
    'field_key_1' => t('Field Title 1'),
795
    'field_key_2' => t('Field Title 2'),
796
  );
797
}
798

    
799
/**
800
 * Alter fields in submission data downloads.
801
 *
802
 * @param array $submission_information
803
 *   Keys and titles for default submission information.
804
 *
805
 * @see hook_webform_results_download_submission_information_info()
806
 */
807
function hook_webform_results_download_submission_information_info_alter(array &$submission_information) {
808
  // Unset a property to remove it from submission data downloads.
809
  if (isset($submission_information['webform_ip_address'])) {
810
    unset($submission_information['webform_ip_address']);
811
  }
812
}
813

    
814
/**
815
 * Return values for submission data download fields.
816
 *
817
 * @param $token
818
 *   The name of the token being replaced.
819
 * @param $submission
820
 *   The data for an individual submission from webform_get_submissions().
821
 * @param array $options
822
 *   A list of options that define the output format. These are generally passed
823
 *   through from the GUI interface.
824
 * @param $serial_start
825
 *   The starting position for the Serial column in the output.
826
 * @param $row_count
827
 *   The number of the row being generated.
828
 *
829
 * @return string
830
 *   Value for requested submission information field.
831
 *
832
 * @see hook_webform_results_download_submission_information_info()
833
 */
834
function hook_webform_results_download_submission_information_data($token, $submission, array $options, $serial_start, $row_count) {
835
  switch ($token) {
836
    case 'field_key_1':
837
      return 'Field Value 1';
838

    
839
    case 'field_key_2':
840
      return 'Field Value 2';
841
  }
842
}
843

    
844
/**
845
 * Alter the query that will produce the list of submission IDs to be
846
 * downloaded.
847
 *
848
 * @param object $query
849
 *   The query object that is being built up to provide the list of submission
850
 *   IDs.
851
 *
852
 * @see webform_download_sids_query()
853
 */
854
function hook_webform_download_sids_query_alter(&$query) {
855
  global $user;
856

    
857
  // Check if component value matches a node ID and author of that node.
858
  $query->join('webform_submitted_data', 'wsd', 'ws.sid = wsd.sid');
859
  $query->condition('wsd.cid', 2);
860
  $query->join('node', 'n', 'wsd.data = n.nid');
861
  $query->condition('n.uid', $user->uid);
862
}
863

    
864
/**
865
 * @}
866
 */
867

    
868
/**
869
 * @defgroup webform_component Sample Webform Component
870
 * @{
871
 * In each of these examples, the word "component" should be replaced with the,
872
 * name of the component type (such as textfield or select). These are not
873
 * actual hooks, but instead samples of how Webform integrates with its own
874
 * built-in components.
875
 */
876

    
877
/**
878
 * Specify the default properties of a component.
879
 *
880
 * @return array
881
 *   An array defining the default structure of a component.
882
 */
883
function _webform_defaults_component() {
884
  return array(
885
    'name' => '',
886
    'form_key' => NULL,
887
    'required' => 0,
888
    'pid' => 0,
889
    'weight' => 0,
890
    'extra' => array(
891
      'options' => '',
892
      'questions' => '',
893
      'optrand' => 0,
894
      'qrand' => 0,
895
      'description' => '',
896
      'description_above' => FALSE,
897
      'private' => FALSE,
898
      'analysis' => TRUE,
899
    ),
900
  );
901
}
902

    
903
/**
904
 * Generate the form for editing a component.
905
 *
906
 * Create a set of form elements to be displayed on the form for editing this
907
 * component. Use care naming the form items, as this correlates directly to the
908
 * database schema. The component "Name" and "Description" fields are added to
909
 * every component type and are not necessary to specify here (although they
910
 * may be overridden if desired).
911
 *
912
 * @param array $component
913
 *   A Webform component array.
914
 * @param array $form
915
 *   The form array.
916
 * @param array $form_state
917
 *   The form state array.
918
 *
919
 * @return array
920
 *   Return $form with whatever changes are desired.
921
 */
922
function _webform_edit_component(array $component, array $form, array $form_state) {
923
  // Disabling the description if not wanted.
924
  $form['description']['#access'] = FALSE;
925

    
926
  // Most options are stored in the "extra" array, which stores any settings
927
  // unique to a particular component type.
928
  $form['extra']['options'] = array(
929
    '#type' => 'textarea',
930
    '#title' => t('Options'),
931
    '#default_value' => $component['extra']['options'],
932
    '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . ' ' . theme('webform_token_help'),
933
    '#cols' => 60,
934
    '#rows' => 5,
935
    '#weight' => -3,
936
    '#required' => TRUE,
937
  );
938
  return $form;
939
}
940

    
941
/**
942
 * Render a Webform component to be part of a form.
943
 *
944
 * @param $component
945
 *   A Webform component array.
946
 * @param $value
947
 *   If editing an existing submission or resuming a draft, this will contain
948
 *   an array of values to be shown instead of the default in the component
949
 *   configuration. This value will always be an array, keyed numerically for
950
 *   each value saved in this field.
951
 * @param $filter
952
 *   Whether or not to filter the contents of descriptions and values when
953
 *   rendering the component. Values need to be unfiltered to be editable by
954
 *   Form Builder.
955
 * @param $submission
956
 *   The submission from which this component is being rendered. Usually not
957
 *   needed. Used by _webform_render_date() to validate using the submission's
958
 *   completion date.
959
 *
960
 * @return array
961
 *   $form_item
962
 *
963
 * @see _webform_client_form_add_component()
964
 */
965
function _webform_render_component($component, $value = NULL, $filter = TRUE, $submission = NULL) {
966
  $form_item = array(
967
    '#type' => 'textfield',
968
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
969
    '#required' => $component['required'],
970
    '#weight' => $component['weight'],
971
    '#description'   => $filter ? webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
972
    '#default_value' => $filter ? webform_replace_tokens($component['value']) : $component['value'],
973
    '#theme_wrappers' => array('webform_element'),
974
  );
975

    
976
  if (isset($value)) {
977
    $form_item['#default_value'] = $value[0];
978
  }
979

    
980
  return $form_item;
981
}
982

    
983
/**
984
 * Allow modules to modify a webform component that will be rendered in a form.
985
 *
986
 * @param array $element
987
 *   The display element as returned by _webform_render_component().
988
 * @param array $component
989
 *   A Webform component array.
990
 *
991
 * @see _webform_render_component()
992
 */
993
function hook_webform_component_render_alter(array &$element, array &$component) {
994
  if ($component['cid'] == 10) {
995
    $element['#title'] = 'My custom title';
996
    $element['#default_value'] = 42;
997
  }
998
}
999

    
1000
/**
1001
 * Display the result of a submission for a component.
1002
 *
1003
 * The output of this function will be displayed under the "Results" tab then
1004
 * "Submissions". This should output the saved data in some reasonable manner.
1005
 *
1006
 * @param $component
1007
 *   A Webform component array.
1008
 * @param $value
1009
 *   An array of information containing the submission result, directly
1010
 *   correlating to the webform_submitted_data database table schema.
1011
 * @param $format
1012
 *   Either 'html' or 'text'. Defines the format that the content should be
1013
 *   returned as. Make sure that returned content is run through check_plain()
1014
 *   or other filtering functions when returning HTML.
1015
 * @param $submission
1016
 *   The submission. Used to generate tokens.
1017
 *
1018
 * @return array
1019
 *   A renderable element containing at the very least these properties:
1020
 *    - #title
1021
 *    - #weight
1022
 *    - #component
1023
 *    - #format
1024
 *    - #value
1025
 *   Webform also uses #theme_wrappers to output the end result to the user,
1026
 *   which will properly format the label and content for use within an e-mail
1027
 *   (such as wrapping the text) or as HTML (ensuring consistent output).
1028
 */
1029
function _webform_display_component($component, $value, $format = 'html', $submission = array()) {
1030
  return array(
1031
    '#title' => $component['name'],
1032
    '#weight' => $component['weight'],
1033
    '#theme' => 'webform_display_textfield',
1034
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
1035
    '#post_render' => array('webform_element_wrapper'),
1036
    '#field_prefix' => $component['extra']['field_prefix'],
1037
    '#field_suffix' => $component['extra']['field_suffix'],
1038
    '#component' => $component,
1039
    '#format' => $format,
1040
    '#value' => isset($value[0]) ? $value[0] : '',
1041
  );
1042
}
1043

    
1044
/**
1045
 * Allow modules to modify a "display only" webform component.
1046
 *
1047
 * @param array $element
1048
 *   The display element as returned by _webform_display_component().
1049
 * @param array $component
1050
 *   A Webform component array.
1051
 *
1052
 * @see _webform_display_component()
1053
 */
1054
function hook_webform_component_display_alter(array &$element, array &$component) {
1055
  if ($component['cid'] == 10) {
1056
    $element['#title'] = 'My custom title';
1057
    $element['#default_value'] = 42;
1058
  }
1059
}
1060

    
1061
/**
1062
 * Performs the conditional action set on an implemented component.
1063
 *
1064
 * Setting the form element allows form validation functions to see the value
1065
 * that webform has set for the given component.
1066
 *
1067
 * @param array $component
1068
 *   The webform component array whose value is being set for the currently-
1069
 *   edited submission.
1070
 * @param array $element
1071
 *   The form element currently being set.
1072
 * @param array $form_state
1073
 *   The form's state.
1074
 * @param string $value
1075
 *   The value to be set, as defined in the conditional action.
1076
 */
1077
function _webform_action_set_component(array $component, array &$element, array &$form_state, $value) {
1078
  $element['#value'] = $value;
1079
  form_set_value($element, $value, $form_state);
1080
}
1081

    
1082
/**
1083
 * A hook for changing the input values before saving to the database.
1084
 *
1085
 * Webform expects a component to consist of a single field, or a single array
1086
 * of fields. If you have a component that requires a deeper form tree
1087
 * you must flatten the data into a single array using this callback
1088
 * or by setting #parents on each field to avoid data loss and/or unexpected
1089
 * behavior.
1090
 *
1091
 * Note that Webform will save the result of this function directly into the
1092
 * database.
1093
 *
1094
 * @param $component
1095
 *   A Webform component array.
1096
 * @param $value
1097
 *   The POST data associated with the user input.
1098
 *
1099
 * @return array
1100
 *   An array of values to be saved into the database. Note that this should be
1101
 *   a numerically keyed array.
1102
 */
1103
function _webform_submit_component($component, $value) {
1104
  // Clean up a phone number into 123-456-7890 format.
1105
  if ($component['extra']['phone_number']) {
1106
    $number = preg_replace('/[^0-9]/', '', $value[0]);
1107
    if (strlen($number) == 7) {
1108
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
1109
    }
1110
    else {
1111
      $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
1112
    }
1113
  }
1114

    
1115
  $value[0] = $number;
1116
  return $value;
1117
}
1118

    
1119
/**
1120
 * Delete operation for a component or submission.
1121
 *
1122
 * @param $component
1123
 *   A Webform component array.
1124
 * @param $value
1125
 *   An array of information containing the submission result, directly
1126
 *   correlating to the webform_submitted_data database schema.
1127
 */
1128
function _webform_delete_component($component, $value) {
1129
  // Delete corresponding files when a submission is deleted.
1130
  if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
1131
    file_usage_delete($file, 'webform');
1132
    file_delete($file);
1133
  }
1134
}
1135

    
1136
/**
1137
 * Module specific instance of hook_help().
1138
 *
1139
 * This allows each Webform component to add information into hook_help().
1140
 */
1141
function _webform_help_component($section) {
1142
  switch ($section) {
1143
    case 'admin/config/content/webform#grid_description':
1144
      return t('Allows creation of grid questions, denoted by radio buttons.');
1145
  }
1146
}
1147

    
1148
/**
1149
 * Module specific instance of hook_theme().
1150
 *
1151
 * This allows each Webform component to add information into hook_theme(). If
1152
 * you specify a file to include, you must define the path to the module that
1153
 * this file belongs to.
1154
 */
1155
function _webform_theme_component() {
1156
  return array(
1157
    'webform_grid' => array(
1158
      'render element' => 'element',
1159
      'file' => 'components/grid.inc',
1160
      'path' => drupal_get_path('module', 'webform'),
1161
    ),
1162
    'webform_display_grid' => array(
1163
      'render element' => 'element',
1164
      'file' => 'components/grid.inc',
1165
      'path' => drupal_get_path('module', 'webform'),
1166
    ),
1167
  );
1168
}
1169

    
1170
/**
1171
 * Calculate and returns statistics about results for this component.
1172
 *
1173
 * This takes into account all submissions to this webform. The output of this
1174
 * function will be displayed under the "Results" tab then "Analysis".
1175
 *
1176
 * @param $component
1177
 *   An array of information describing the component, directly correlating to
1178
 *   the webform_component database schema.
1179
 * @param $sids
1180
 *   An optional array of submission IDs (sid). If supplied, the analysis will
1181
 *   be limited to these sids.
1182
 * @param $single
1183
 *   Boolean flag determining if the details about a single component are being
1184
 *   shown. May be used to provided detailed information about a single
1185
 *   component's analysis, such as showing "Other" options within a select list.
1186
 * @param $join
1187
 *   An optional SelectQuery object to be used to join with the submissions
1188
 *   table to restrict the submissions being analyzed.
1189
 *
1190
 * @return array
1191
 *   An array containing one or more of the following keys:
1192
 *   - table_rows: If this component has numeric data that can be represented in
1193
 *     a grid, return the values here. This array assumes a 2-dimensional
1194
 *     structure, with the first value being a label and subsequent values
1195
 *     containing a decimal or integer.
1196
 *   - table_header: If this component has more than a single set of values,
1197
 *     include a table header so each column can be labeled.
1198
 *   - other_data: If your component has non-numeric data to include, such as
1199
 *     a description or link, include that in the other_data array. Each item
1200
 *     may be a string or an array of values that matches the number of columns
1201
 *     in the table_header property.
1202
 *   At the very least, either table_rows or other_data should be provided.
1203
 *   Note that if you want your component's analysis to be available by default
1204
 *   without the user specifically enabling it, you must set
1205
 *   $component['extra']['analysis'] = TRUE in your
1206
 *   _webform_defaults_component() callback.
1207
 *
1208
 * @see _webform_defaults_component()
1209
 */
1210
function _webform_analysis_component($component, $sids = array(), $single = FALSE, $join = NULL) {
1211
  // Generate the list of options and questions.
1212
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
1213
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
1214

    
1215
  // Generate a lookup table of results.
1216
  $query = db_select('webform_submitted_data', 'wsd')
1217
    ->fields('wsd', array('no', 'data'))
1218
    ->condition('nid', $component['nid'])
1219
    ->condition('cid', $component['cid'])
1220
    ->condition('data', '', '<>')
1221
    ->groupBy('no')
1222
    ->groupBy('data');
1223
  $query->addExpression('COUNT(sid)', 'datacount');
1224

    
1225
  if (count($sids)) {
1226
    $query->condition('sid', $sids, 'IN');
1227
  }
1228

    
1229
  if ($join) {
1230
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
1231
  }
1232

    
1233
  $result = $query->execute();
1234
  $counts = array();
1235
  foreach ($result as $data) {
1236
    $counts[$data->no][$data->data] = $data->datacount;
1237
  }
1238

    
1239
  // Create an entire table to be put into the returned row.
1240
  $rows = array();
1241
  $header = array('');
1242

    
1243
  // Add options as a header row.
1244
  foreach ($options as $option) {
1245
    $header[] = $option;
1246
  }
1247

    
1248
  // Add questions as each row.
1249
  foreach ($questions as $qkey => $question) {
1250
    $row = array($question);
1251
    foreach ($options as $okey => $option) {
1252
      $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
1253
    }
1254
    $rows[] = $row;
1255
  }
1256

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

    
1260
  return array(
1261
    'table_header' => $header,
1262
    'table_rows' => $rows,
1263
    'other_data' => $other,
1264
  );
1265
}
1266

    
1267
/**
1268
 * Return the result of a component value for display in a table.
1269
 *
1270
 * The output of this function will be displayed under the "Results" tab then
1271
 * "Table".
1272
 *
1273
 * @param $component
1274
 *   A Webform component array.
1275
 * @param $value
1276
 *   An array of information containing the submission result, directly
1277
 *   correlating to the webform_submitted_data database schema.
1278
 *
1279
 * @return string
1280
 *   Textual output formatted for human reading.
1281
 */
1282
function _webform_table_component($component, $value) {
1283
  $questions = array_values(_webform_component_options($component['extra']['questions']));
1284
  $output = '';
1285
  // Set the value as a single string.
1286
  if (is_array($value)) {
1287
    foreach ($value as $item => $value) {
1288
      if ($value !== '') {
1289
        $output .= $questions[$item] . ': ' . check_plain($value) . '<br />';
1290
      }
1291
    }
1292
  }
1293
  else {
1294
    $output = check_plain(!isset($value['0']) ? '' : $value['0']);
1295
  }
1296
  return $output;
1297
}
1298

    
1299
/**
1300
 * Return the header for this component to be displayed in a CSV file.
1301
 *
1302
 * The output of this function will be displayed under the "Results" tab then
1303
 * "Download".
1304
 *
1305
 * @param $component
1306
 *   A Webform component array.
1307
 * @param $export_options
1308
 *   An array of options that may configure export of this field.
1309
 *
1310
 * @return array
1311
 *   An array of data to be displayed in the first three rows of a CSV file, not
1312
 *   including either prefixed or trailing commas.
1313
 */
1314
function _webform_csv_headers_component($component, $export_options) {
1315
  $header = array();
1316
  $header[0] = array('');
1317
  $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name']);
1318
  $items = _webform_component_options($component['extra']['questions']);
1319
  $count = 0;
1320
  foreach ($items as $key => $item) {
1321
    // Empty column per sub-field in main header.
1322
    if ($count != 0) {
1323
      $header[0][] = '';
1324
      $header[1][] = '';
1325
    }
1326
    // The value for this option.
1327
    $header[2][] = $item;
1328
    $count++;
1329
  }
1330

    
1331
  return $header;
1332
}
1333

    
1334
/**
1335
 * Format the submitted data of a component for CSV downloading.
1336
 *
1337
 * The output of this function will be displayed under the "Results" tab then
1338
 * "Download".
1339
 *
1340
 * @param $component
1341
 *   A Webform component array.
1342
 * @param $export_options
1343
 *   An array of options that may configure export of this field.
1344
 * @param $value
1345
 *   An array of information containing the submission result, directly
1346
 *   correlating to the webform_submitted_data database schema.
1347
 *
1348
 * @return array
1349
 *   An array of items to be added to the CSV file. Each value within the array
1350
 *   will be another column within the file. This function is called once for
1351
 *   every row of data.
1352
 */
1353
function _webform_csv_data_component($component, $export_options, $value) {
1354
  $questions = array_keys(_webform_select_options($component['extra']['questions']));
1355
  $return = array();
1356
  foreach ($questions as $key => $question) {
1357
    $return[] = isset($value[$key]) ? $value[$key] : '';
1358
  }
1359
  return $return;
1360
}
1361

    
1362
/**
1363
 * Fix the view field(s) that are automatically generated for number components.
1364
 *
1365
 * Provides each component the opportunity to adjust how this component is
1366
 * displayed in a view as a field in a view table. For example, a component may
1367
 * modify how it responds to click-sorting. Or it may add additional fields,
1368
 * such as a grid component having a column for each question.
1369
 *
1370
 * @param array $component
1371
 *   A Webform component array.
1372
 * @param array $fields
1373
 *   An array of field-definition arrays. Will be passed one field definition,
1374
 *   which may be modified. Additional fields may be added to the array.
1375
 *
1376
 * @return array
1377
 *   The modified $fields array.
1378
 */
1379
function _webform_view_field_component(array $component, array $fields) {
1380
  foreach ($fields as &$field) {
1381
    $field['webform_datatype'] = 'number';
1382
  }
1383
  return $fields;
1384
}
1385

    
1386
/**
1387
 * Modify the how a view was expanded to show all the components.
1388
 *
1389
 * This alter function is only called when the view is actually modified. It
1390
 * provides modules an opportunity to alter the changes that webform made to
1391
 * the view.
1392
 *
1393
 * This hook is called from webform_views_pre_view. If another module also
1394
 * changes views by implementing this same views hook, the relative order of
1395
 * execution of the two implementations will depend upon the module weights of
1396
 * the two modules. Using hook_webform_view_alter instead guarantees an
1397
 * opportunity to modify the view AFTER webform.
1398
 *
1399
 * @param object $view
1400
 *   The view object.
1401
 * @param string $display_id
1402
 *   The display_id that was expanded by webform.
1403
 * @param array $args
1404
 *   The arguments that were passed to the view.
1405
 */
1406
function hook_webform_view_alter($view, $display_id, array $args) {
1407
  // Don't show component with cid == 4.
1408
  $fields = $view->get_items('field', $display_id);
1409
  foreach ($fields as $id => $field) {
1410
    if (isset($field['webform_cid']) && $field['webform_cid'] == 4) {
1411
      unset($fields[$id]);
1412
    }
1413
  }
1414
  $view->display[$display_id]->handler->set_option('fields', $fields);
1415
}
1416

    
1417
/**
1418
 * Modify the list of mail systems that are capable of sending HTML email.
1419
 *
1420
 * @param array &$systems
1421
 *   An array of mail system class names.
1422
 */
1423
function hook_webform_html_capable_mail_systems_alter(array &$systems) {
1424
  if (module_exists('my_module')) {
1425
    $systems[] = 'MyModuleMailSystem';
1426
  }
1427
}
1428

    
1429
/**
1430
 * Define a list of webform exporters.
1431
 *
1432
 * @return array
1433
 *   A list of the available exporters provided by the module.
1434
 *
1435
 * @see webform_webform_exporters()
1436
 */
1437
function hook_webform_exporters() {
1438
  $exporters = array(
1439
    'webform_exporter_custom' => array(
1440
      'title' => t('Webform exporter name'),
1441
      'description' => t('The description for this exporter.'),
1442
      'handler' => 'webform_exporter_custom',
1443
      'file' => drupal_get_path('module', 'yourmodule') . '/includes/webform_exporter_custom.inc',
1444
      'weight' => 10,
1445
    ),
1446
  );
1447

    
1448
  return $exporters;
1449
}
1450

    
1451
/**
1452
 * Modify the list of webform exporters definitions.
1453
 *
1454
 * @param array &$exporters
1455
 *   A list of all available webform exporters.
1456
 */
1457
function hook_webform_exporters_alter(array &$exporters) {
1458
  $exporters['excel']['handler'] = 'customized_excel_exporter';
1459
  $exporters['excel']['file'] = drupal_get_path('module', 'yourmodule') . '/includes/customized_excel_exporter.inc';
1460
}
1461

    
1462
/**
1463
 * Declare conditional types and their operators.
1464
 *
1465
 * Each conditional type defined here may then be referenced in
1466
 * hook_webform_component_info(). For each type this hook also declares a set of
1467
 * operators that may be applied to a component of this conditional type in
1468
 * conditionals.
1469
 *
1470
 * @return array
1471
 *   A 2-dimensional array of operator configurations. The configurations are
1472
 *   keyed first by their conditional type then by operator key. Each operator
1473
 *   declaration is an array with the following keys:
1474
 *   - label: Translated label for this operator that is shown in the UI.
1475
 *   - comparison callback: A callback for server-side evaluation.
1476
 *   - js comparison callback: A JavaScript callback for client-side evaluation.
1477
 *     The callback will be looked for in the Drupal.webform object.
1478
 *   - form callback (optional): A form callback that allows configuring
1479
 *     additional parameters for this operator. Default:
1480
 *     'webform_conditional_operator_text'.
1481
 *
1482
 * @see hook_webform_component_info()
1483
 * @see callback_webform_conditional_comparision_operator()
1484
 * @see callback_webform_conditional_rule_value_form()
1485
 */
1486
function hook_webform_conditional_operator_info() {
1487
  $operators = array();
1488
  $operators['string']['not_equal'] = array(
1489
    'label' => t('is not'),
1490
    'comparison callback' => 'webform_conditional_operator_string_not_equal',
1491
    'js comparison callback' => 'conditionalOperatorStringNotEqual',
1492
  );
1493
  return $operators;
1494
}
1495

    
1496
/**
1497
 * Alter the list of operators and conditional types.
1498
 *
1499
 * @param array $operators
1500
 *   A data structure as described in hook_webform_conditional_operator_info().
1501
 *
1502
 * @see hook_webform_conditional_operator_info()
1503
 */
1504
function hook_webform_conditional_operators_alter(array &$operators) {
1505
  $operators['string']['not_equal']['label'] = t('not equal');
1506
}
1507

    
1508
/**
1509
 * Evaluate the operator for a given set of values.
1510
 *
1511
 * This function will be called two times with potentially different kinds of
1512
 * values: Once in _webform_client_form_validate() before any of the validate
1513
 * handlers or the _webform_submit_COMPONENT() callback is called, and once in
1514
 * webform_client_form_pages() after those handlers have been called.
1515
 *
1516
 * @param array $input_values
1517
 *   The values received from the browser.
1518
 * @param mixed $rule_value
1519
 *   The value as configured in the form callback.
1520
 * @param array $component
1521
 *   The component for which we are evaluating the operator.
1522
 *
1523
 * @return bool
1524
 *   The operation result.
1525
 */
1526
function callback_webfom_conditional_comparison_operator(array $input_values, $rule_value, array $component) {
1527
  foreach ($input_values as $value) {
1528
    if (strcasecmp($value, $rule_value)) {
1529
      return TRUE;
1530
    }
1531
  }
1532
  return FALSE;
1533
}
1534

    
1535
/**
1536
 * Define a form element that configures your operator.
1537
 *
1538
 * @param object $node
1539
 *   The node for which the conditionals are being configured.
1540
 *
1541
 * @return string|string[]
1542
 *   Either a single rendered form element or a rendered form element per
1543
 *   component (keyed by cid). Make sure that none of the rendered strings
1544
 *   contains any HTML IDs as the form element will be rendered multiple times.
1545
 *   The JavaScript will take care of adding the appropriate name attributes.
1546
 *
1547
 * @see _webform_conditional_expand_value_forms()
1548
 */
1549
function callback_webform_conditional_rule_value_form($node) {
1550
  $forms = [];
1551
  foreach ($node->webform['components'] as $cid => $component) {
1552
    if (webform_component_property($component['type'], 'conditional_type') == 'newsletter') {
1553
      $element = [
1554
        '#type' => 'select',
1555
        '#options' => [
1556
          'yes' => t('Opt-in'),
1557
          'no' => t('No opt-in'),
1558
        ],
1559
      ];
1560
      $forms[$cid] = drupal_render($element);
1561
    }
1562
  }
1563
  return $forms;
1564
}
1565

    
1566
/**
1567
 * @}
1568
 */