[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/webform/ -> webform_hooks.php (source)

   1  <?php
   2  // $Id: webform_hooks.php,v 1.9.2.8 2010/09/10 17:42:23 quicksketch Exp $
   3  
   4  /**
   5   * @file
   6   * Sample hooks demonstrating usage in Webform.
   7   */
   8  
   9  /**
  10   * @defgroup webform_hooks Webform Module Hooks
  11   * @{
  12   * Webform's hooks enable other modules to intercept events within Webform, such
  13   * as the completion of a submission or adding validation. Webform's hooks also
  14   * allow other modules to provide additional components for use within forms.
  15   */
  16  
  17  /**
  18   * Define callbacks that can be used as select list options.
  19   *
  20   * @return
  21   *   An array of callbacks that can be used for select list options. This array
  22   *   should be keyed by the "name" of the pre-defined list. The values should
  23   *   be an array with the following additional keys:
  24   *     - title: The translated title for this list.
  25   *     - options callback: The name of the function that will return the list.
  26   *     - options arguments: Any additional arguments to send to the callback.
  27   *     - file: Optional. The file containing the options callback, relative to
  28   *       the module root.
  29   */
  30  function hook_webform_select_options_info() {
  31    $items = array();
  32  
  33    $items['days'] = array(
  34      'title' => t('Days of the week'),
  35      'options callback' => 'webform_options_days',
  36      'file' => 'includes/webform.options.inc',
  37    );
  38  
  39    return $items;
  40  }
  41  
  42  /**
  43   * Respond to the loading of Webform submissions.
  44   *
  45   * @param $submissions
  46   *   An array of Webform submissions that are being loaded, keyed by the
  47   *   submission ID. Modifications to the submissions are done by reference.
  48   */
  49  function hook_webform_submission_load(&$submissions) {
  50    foreach ($submissions as $sid => $submission) {
  51      $submissions[$sid]->new_property = 'foo';
  52    }
  53  }
  54  
  55  /**
  56   * Modify a Webform submission, prior to saving it in the database.
  57   *
  58   * @param $node
  59   *   The Webform node on which this submission was made.
  60   * @param $submission
  61   *   The Webform submission that is about to be saved to the database.
  62   */
  63  function hook_webform_submission_presave($node, &$submission) {
  64    // Update some component's value before it is saved.
  65    $component_id = 4;
  66    $submission->data[$component_id]['value'][0] = 'foo';
  67  }
  68  
  69  /**
  70   * Respond to a Webform submission being inserted.
  71   *
  72   * Note that this hook is called after a submission has already been saved to
  73   * the database. If needing to modify the submission prior to insertion, use
  74   * hook_webform_submission_presave().
  75   *
  76   * @param $node
  77   *   The Webform node on which this submission was made.
  78   * @param $submission
  79   *   The Webform submission that was just inserted into the database.
  80   */
  81  function hook_webform_submission_insert($node, $submission) {
  82    // Insert a record into a 3rd-party module table when a submission is added.
  83    db_query("INSERT INTO {mymodule_table} nid = %d, sid = %d, foo = '%s'", $node->nid, $submission->sid, 'foo_data');
  84  }
  85  
  86  /**
  87   * Respond to a Webform submission being updated.
  88   *
  89   * Note that this hook is called after a submission has already been saved to
  90   * the database. If needing to modify the submission prior to updating, use
  91   * hook_webform_submission_presave().
  92   *
  93   * @param $node
  94   *   The Webform node on which this submission was made.
  95   * @param $submission
  96   *   The Webform submission that was just updated in the database.
  97   */
  98  function hook_webform_submission_update($node, $submission) {
  99    // Update a record in a 3rd-party module table when a submission is updated.
 100    db_query("UPDATE {mymodule_table} SET (foo) VALUES ('%s') WHERE nid = %d, sid = %d", 'foo_data', $node->nid, $submission->sid);
 101  }
 102  
 103  /**
 104   * Respond to a Webform submission being deleted.
 105   *
 106   * @param $node
 107   *   The Webform node on which this submission was made.
 108   * @param $submission
 109   *   The Webform submission that was just deleted from the database.
 110   */
 111  function hook_webform_submission_delete($node, $submission) {
 112    // Delete a record from a 3rd-party module table when a submission is deleted.
 113    db_query("DELETE FROM {mymodule_table} WHERE nid = %d, sid = %d", $node->nid, $submission->sid);
 114  }
 115  
 116  /**
 117   * Alter the display of a Webform submission.
 118   *
 119   * This function applies to both e-mails sent by Webform and normal display of
 120   * submissions when viewing through the adminsitrative interface.
 121   *
 122   * @param $renderable
 123   *   The Webform submission in a renderable array, similar to FormAPI's
 124   *   structure. This variable must be passed in by-reference. Important
 125   *   properties of this array include #node, #submission, #email, and #format,
 126   *   which can be used to find the context of the submission that is being
 127   *   rendered.
 128   */
 129  function hook_webform_submission_render_alter(&$renderable) {
 130    // Remove page breaks from sent e-mails.
 131    if (isset($renderable['#email'])) {
 132      foreach (element_children($renderable) as $key) {
 133        if ($renderable[$key]['#component']['type'] == 'pagebreak') {
 134          unset($renderable[$key]);
 135        }
 136      }
 137    }
 138  }
 139  
 140  /**
 141   * Modify a loaded Webform component.
 142   *
 143   * IMPORTANT: This hook does not actually exist because components are loaded
 144   * in bulk as part of webform_node_load(). Use hook_nodeapi() to modify loaded
 145   * components when the node is loaded. This example is provided merely to point
 146   * to hook_nodeapi().
 147   *
 148   * @see hook_nodeapi()
 149   * @see webform_node_load()
 150   */
 151  function hook_webform_component_load() {
 152    // This hook does not exist. Instead use hook_nodeapi().
 153  }
 154  
 155  /**
 156   * Modify a Webform component before it is saved to the database.
 157   *
 158   * Note that most of the time this hook is not necessary, because Webform will
 159   * automatically add data to the component based on the component form. Using
 160   * hook_form_alter() will be sufficient in most cases.
 161   *
 162   * @see hook_form_alter()
 163   * @see webform_component_edit_form()
 164   *
 165   * @param $component
 166   *   The Webform component being saved.
 167   */
 168  function hook_webform_component_presave(&$component) {
 169    $component['extra']['new_option'] = 'foo';
 170  }
 171  
 172  /**
 173   * Respond to a Webform component being inserted into the database.
 174   */
 175  function hook_webform_component_insert($component) {
 176    // Insert a record into a 3rd-party module table when a component is inserted.
 177    db_query("INSERT INTO {mymodule_table} (nid, cid) VALUES (%d, %d)", $component['nid'], $component['cid']);
 178  }
 179  
 180  /**
 181   * Respond to a Webform component being updated in the database.
 182   */
 183  function hook_webform_component_update($component) {
 184    // Update a record in a 3rd-party module table when a component is updated.
 185    db_query('UPDATE {mymodule_table} SET value "%s" WHERE nid = %d AND cid = %d)', 'foo', $component['nid'], $component['cid']);
 186  }
 187  
 188  /**
 189   * Respond to a Webform component being deleted.
 190   */
 191  function hook_webform_component_delete($component) {
 192    // Delete a record in a 3rd-party module table when a component is deleted.
 193    db_query('DELETE FROM {mymodule_table} WHERE nid = %d AND cid = %d)', $component['nid'], $component['cid']);
 194  }
 195  
 196  /**
 197   * Define components to Webform.
 198   *
 199   * @return
 200   *   An array of components, keyed by machine name. Required properties are
 201   *   "label" and "description". The "features" array defines which capabilities
 202   *   the component has, such as being displayed in e-mails or csv downloads.
 203   *   A component like "markup" for example would not show in these locations.
 204   *   The possible features of a component include:
 205   *
 206   *     - csv
 207   *     - email
 208   *     - email_address
 209   *     - email_name
 210   *     - required
 211   *     - conditional
 212   *     - spam_analysis
 213   *     - group
 214   *
 215   *   Note that these features do not indicate the default state, but determine
 216   *   if the component can have this property at all. Setting "required" to TRUE
 217   *   does not mean that a field will always be required, but instead give the
 218   *   option to the administrator to choose the requiredness. See the example
 219   *   implementation for details on how these features may be set.
 220   *
 221   *   An optional "file" may be specified to be loaded when the component is
 222   *   needed. A set of callbacks will be established based on the name of the
 223   *   component. All components follow the pattern:
 224   *
 225   *   _webform_[callback]_[component]
 226   *
 227   *   Where [component] is the name of the key of the component and [callback] is
 228   *   any of the following:
 229   *
 230   *     - defaults
 231   *     - theme
 232   *     - edit
 233   *     - delete
 234   *     - render
 235   *     - display
 236   *     - analysis
 237   *     - table
 238   *     - csv_headers
 239   *     - csv_data
 240   *
 241   * See the sample component implementation for details on each one of these
 242   * callbacks.
 243   *
 244   * @see webform_component
 245   */
 246  function hook_webform_component_info() {
 247    $components = array();
 248  
 249    $components['textfield'] = array(
 250      'label' => t('Textfield'),
 251      'description' => t('Basic textfield type.'),
 252      'features' => array(
 253        // Add content to CSV downloads. Defaults to TRUE.
 254        'csv' => TRUE,
 255        // Show this field in e-mailed submissions. Defaults to TRUE.
 256        'email' => TRUE,
 257        // Allow this field to be used as an e-mail FROM or TO address. Defaults
 258        // to FALSE.
 259        'email_address' => FALSE,
 260        // Allow this field to be used as an e-mail SUBJECT or FROM name. Defaults
 261        // to FALSE.
 262        'email_name' => TRUE,
 263        // This field may be toggled as required or not. Defaults to TRUE.
 264        'required' => TRUE,
 265        // If this field can be used as a conditional SOURCE. All fields may
 266        // always be displayed conditionally, regardless of this setting.
 267        // Defaults to TRUE.
 268        'conditonal' => TRUE,
 269        // If this field allows other fields to be grouped within it (like a 
 270        // fieldset or tabs). Defaults to FALSE.
 271        'group' => FALSE,
 272        // If this field saves a file that can be used as an e-mail attachment.
 273        // Defaults to FALSE.
 274        'attachment' => FALSE,
 275      ),
 276      'file' => 'components/textfield.inc',
 277    );
 278  
 279    return $components;
 280  }
 281  
 282  /**
 283   * Alter the list of available Webform components.
 284   *
 285   * @param $components
 286   *   A list of existing components as defined by hook_webform_component_info().
 287   *
 288   * @see hook_webform_component_info()
 289   */
 290  function hook_webform_component_info_alter(&$components) {
 291    // Completely remove a component.
 292    unset($components['grid']);
 293  
 294    // Change the name of a component.
 295    $components['textarea']['label'] = t('Text box');
 296  }
 297  
 298  /**
 299   * @}
 300   */
 301  
 302  /**
 303   * @defgroup webform_component Sample Webform Component
 304   * @{
 305   * In each of these examples, the word "component" should be replaced with the,
 306   * name of the component type (such as textfield or select). These are not
 307   * actual hooks, but instead samples of how Webform integrates with its own
 308   * built-in components.
 309   */
 310  
 311  /**
 312   * Specify the default properties of a component.
 313   *
 314   * @return
 315   *   An array defining the default structure of a component.
 316   */
 317  function _webform_defaults_component() {
 318    return array(
 319      'name' => '',
 320      'form_key' => NULL,
 321      'email' => 1,
 322      'mandatory' => 0,
 323      'pid' => 0,
 324      'weight' => 0,
 325      'extra' => array(
 326        'options' => '',
 327        'questions' => '',
 328        'optrand' => 0,
 329        'qrand' => 0,
 330        'description' => '',
 331      ),
 332    );
 333  }
 334  
 335  /**
 336   * Generate the form for editing a component.
 337   *
 338   * Create a set of form elements to be displayed on the form for editing this
 339   * component. Use care naming the form items, as this correlates directly to the
 340   * database schema. The component "Name" and "Description" fields are added to
 341   * every component type and are not necessary to specify here (although they
 342   * may be overridden if desired).
 343   *
 344   * @param $component
 345   *   A Webform component array.
 346   * @return
 347   *   An array of form items to be displayed on the edit component page
 348   */
 349  function _webform_edit_component($component) {
 350    $form = array();
 351  
 352    // Disabling the description if not wanted.
 353    $form['description'] = array();
 354  
 355    // Most options are stored in the "extra" array, which stores any settings
 356    // unique to a particular component type.
 357    $form['extra']['options'] = array(
 358      '#type' => 'textarea',
 359      '#title' => t('Options'),
 360      '#default_value' => $component['extra']['options'],
 361      '#description' => t('Key-value pairs may be entered separated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'),
 362      '#cols' => 60,
 363      '#rows' => 5,
 364      '#weight' => -3,
 365      '#required' => TRUE,
 366    );
 367    return $form;
 368  }
 369  
 370  /**
 371   * Render a Webform component to be part of a form.
 372   *
 373   * @param $component
 374   *   A Webform component array.
 375   * @param $value
 376   *   If editing an existing submission or resuming a draft, this will contain
 377   *   an array of values to be shown instead of the default in the component
 378   *   configuration. This value will always be an array, keyed numerically for
 379   *   each value saved in this field.
 380   */
 381  function _webform_render_component($component, $value = NULL) {
 382    $form_item = array(
 383      '#type' => 'textfield',
 384      '#title' => $component['name'],
 385      '#required' => $component['mandatory'],
 386      '#weight' => $component['weight'],
 387      '#description'   => _webform_filter_descriptions($component['extra']['description']),
 388      '#default_value' => $component['value'],
 389      '#prefix' => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
 390      '#suffix' => '</div>',
 391    );
 392  
 393    if (isset($value)) {
 394      $form_item['#default_value'] = $value[0];
 395    }
 396  
 397    return $form_item;
 398  }
 399  
 400  /**
 401   * Display the result of a submission for a component.
 402   * 
 403   * The output of this function will be displayed under the "Results" tab then
 404   * "Submissions". This should output the saved data in some reasonable manner.
 405   *
 406   * @param $component
 407   *   A Webform component array.
 408   * @param $value
 409   *   An array of information containing the submission result, directly
 410   *   correlating to the webform_submitted_data database table schema.
 411   * @param $format
 412   *   Either 'html' or 'text'. Defines the format that the content should be
 413   *   returned as. Make sure that returned content is run through check_plain()
 414   *   or other filtering functions when returning HTML.
 415   * @return
 416   *   A renderable element containing at the very least these properties:
 417   *    - #title
 418   *    - #weight
 419   *    - #component
 420   *    - #format
 421   *    - #value
 422   *   Webform also uses #theme_wrappers to output the end result to the user,
 423   *   which will properly format the label and content for use within an e-mail
 424   *   (such as wrapping the text) or as HTML (ensuring consistent output).
 425   */
 426  function _webform_display_component($component, $value, $format = 'html') {
 427    return array(
 428      '#title' => $component['name'],
 429      '#weight' => $component['weight'],
 430      '#theme' => 'webform_display_textfield',
 431      '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
 432      '#post_render' => array('webform_element_wrapper'),
 433      '#field_prefix' => $component['extra']['field_prefix'],
 434      '#field_suffix' => $component['extra']['field_suffix'],
 435      '#component' => $component,
 436      '#format' => $format,
 437      '#value' => isset($value[0]) ? $value[0] : '',
 438    );
 439  }
 440  
 441  /**
 442   * A hook for changing the input values before saving to the database.
 443   *
 444   * Note that Webform will save the result of this function directly into the
 445   * database.
 446   *
 447   * @param $component
 448   *   A Webform component array.
 449   * @param $value
 450   *   The POST data associated with the user input.
 451   * @return
 452   *   An array of values to be saved into the database. Note that this should be
 453   *   a numerically keyed array.
 454   */
 455  function _webform_submit_component($component, $value) {
 456    // Clean up a phone number into 123-456-7890 format.
 457    if ($component['extra']['phone_number']) {
 458      $matches = array();
 459      $number = preg_replace('[^0-9]', $value[0]);
 460      if (strlen($number) == 7) {
 461        $number = substr($number, 0, 3) . '-' . substr($number, 3, 4);
 462      }
 463      else {
 464        $number = substr($number, 0, 3) . '-' . substr($number, 3, 3) . '-' . substr($number, 6, 4);
 465      }
 466    }
 467  
 468    $value[0] = $number;
 469    return $value;
 470  }
 471  
 472  /**
 473   * Delete operation for a component or submission.
 474   *
 475   * @param $component
 476   *   A Webform component array.
 477   * @param $value
 478   *   An array of information containing the submission result, directly
 479   *   correlating to the webform_submitted_data database schema.
 480   */
 481  function _webform_delete_component($component, $value) {
 482    // Delete corresponding files when a submission is deleted.
 483    $filedata = unserialize($value['0']);
 484    if (isset($filedata['filepath']) && is_file($filedata['filepath'])) {
 485      unlink($filedata['filepath']);
 486      db_query("DELETE FROM {files} WHERE filepath = '%s'", $filedata['filepath']);
 487    }
 488  }
 489  
 490  /**
 491   * Module specific instance of hook_help().
 492   *
 493   * This allows each Webform component to add information into hook_help().
 494   */
 495  function _webform_help_component($section) {
 496    switch ($section) {
 497      case 'admin/settings/webform#grid_description':
 498        return t('Allows creation of grid questions, denoted by radio buttons.');
 499    }
 500  }
 501  
 502  /**
 503   * Module specific instance of hook_theme().
 504   *
 505   * This allows each Webform component to add information into hook_theme().
 506   */
 507  function _webform_theme_component() {
 508    return array(
 509      'webform_grid' => array(
 510        'arguments' => array('grid_element' => NULL),
 511      ),
 512      'webform_mail_grid' => array(
 513        'arguments' => array('component' => NULL, 'value' => NULL),
 514      ),
 515    );
 516  }
 517  
 518  /**
 519   * Calculate and returns statistics about results for this component.
 520   * 
 521   * This takes into account all submissions to this webform. The output of this
 522   * function will be displayed under the "Results" tab then "Analysis".
 523   *
 524   * @param $component
 525   *   An array of information describing the component, directly correlating to
 526   *   the webform_component database schema.
 527   * @param $sids
 528   *   An optional array of submission IDs (sid). If supplied, the analysis will
 529   *   be limited to these sids.
 530   * @param $single
 531   *   Boolean flag determining if the details about a single component are being
 532   *   shown. May be used to provided detailed information about a single
 533   *   component's analysis, such as showing "Other" options within a select list.
 534   * @return
 535   *   An array of data rows, each containing a statistic for this component's
 536   *   submissions.
 537   */
 538  function _webform_analysis_component($component, $sids = array(), $single = FALSE) {
 539    // Generate the list of options and questions.
 540    $options = _webform_component_options($component['extra']['options']);
 541    $questions = array_values(_webform_component_options($component['extra']['questions']));
 542  
 543    // Generate a lookup table of results.
 544    $placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
 545    $sidfilter = count($sids) ? " AND sid in (".implode(",", $placeholders).")" : "";
 546    $query = 'SELECT no, data, count(data) as datacount '.
 547      ' FROM {webform_submitted_data} '.
 548      ' WHERE nid = %d '.
 549      ' AND cid = %d '.
 550      " AND data != '' ". $sidfilter .
 551      ' GROUP BY no, data';
 552    $result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids));
 553    $counts = array();
 554    while ($data = db_fetch_object($result)) {
 555      $counts[$data->no][$data->data] = $data->datacount;
 556    }
 557  
 558    // Create an entire table to be put into the returned row.
 559    $rows = array();
 560    $header = array('');
 561  
 562    // Add options as a header row.
 563    foreach ($options as $option) {
 564      $header[] = $option;
 565    }
 566  
 567    // Add questions as each row.
 568    foreach ($questions as $qkey => $question) {
 569      $row = array($question);
 570      foreach ($options as $okey => $option) {
 571        $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
 572      }
 573      $rows[] = $row;
 574    }
 575    $output = theme('table', $header, $rows, array('class' => 'webform-grid'));
 576  
 577    return array(array(array('data' => $output, 'colspan' => 2)));
 578  }
 579  
 580  /**
 581   * Return the result of a component value for display in a table.
 582   *
 583   * The output of this function will be displayed under the "Results" tab then
 584   * "Table".
 585   *
 586   * @param $component
 587   *   A Webform component array.
 588   * @param $value
 589   *   An array of information containing the submission result, directly
 590   *   correlating to the webform_submitted_data database schema.
 591   * @return
 592   *   Textual output formatted for human reading.
 593   */
 594  function _webform_table_component($component, $value) {
 595    $questions = array_values(_webform_component_options($component['extra']['questions']));
 596    $output = '';
 597    // Set the value as a single string.
 598    if (is_array($value)) {
 599      foreach ($value as $item => $value) {
 600        if ($value !== '') {
 601          $output .= $questions[$item] .': '. check_plain($value) .'<br />';
 602        }
 603      }
 604    }
 605    else {
 606      $output = check_plain(!isset($value['0']) ? '' : $value['0']);
 607    }
 608    return $output;
 609  }
 610  
 611  /**
 612   * Return the header for this component to be displayed in a CSV file.
 613   *
 614   * The output of this function will be displayed under the "Results" tab then
 615   * "Download".
 616   *
 617   * @param $component
 618   *   A Webform component array.
 619   * @param $export_options
 620   *   An array of options that may configure export of this field.
 621   * @return
 622   *   An array of data to be displayed in the first three rows of a CSV file, not
 623   *   including either prefixed or trailing commas.
 624   */
 625  function _webform_csv_headers_component($component, $export_options) {
 626    $header = array();
 627    $header[0] = array('');
 628    $header[1] = array($component['name']);
 629    $items = _webform_component_options($component['extra']['questions']);
 630    $count = 0;
 631    foreach ($items as $key => $item) {
 632      // Empty column per sub-field in main header.
 633      if ($count != 0) {
 634        $header[0][] = '';
 635        $header[1][] = '';
 636      }
 637      // The value for this option.
 638      $header[2][] = $item;
 639      $count++;
 640    }
 641  
 642    return $header;
 643  }
 644  
 645  /**
 646   * Format the submitted data of a component for CSV downloading.
 647   *
 648   * The output of this function will be displayed under the "Results" tab then
 649   * "Download".
 650   *
 651   * @param $component
 652   *   A Webform component array.
 653   * @param $export_options
 654   *   An array of options that may configure export of this field.
 655   * @param $value
 656   *   An array of information containing the submission result, directly
 657   *   correlating to the webform_submitted_data database schema.
 658   * @return
 659   *   An array of items to be added to the CSV file. Each value within the array
 660   *   will be another column within the file. This function is called once for
 661   *   every row of data.
 662   */
 663  function _webform_csv_data_component($component, $export_options, $value) {
 664    $questions = array_keys(_webform_select_options($component['extra']['questions']));
 665    $return = array();
 666    foreach ($questions as $key => $question) {
 667      $return[] = isset($value[$key]) ? $value[$key] : '';
 668    }
 669    return $return;
 670  }
 671  
 672  /**
 673   * @}
 674   */


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7