You are here

webform_view.module in Webform view 7.4

Same filename and directory in other branches
  1. 7 webform_view.module

Allows views to be embedded in webforms and used as submission data.

This does NOT save all that data in a fully webform-compatible way for reports, it just allows elements that were added on the fly to be processed as data for emails. Data is not available for later reporting.

USAGE.

Add a field 'can order' as a boolean flag on nodes that can be ordered.

Set its 'display' to be 'webform placeholder'

Make a view for the nodes you want to show on a webform. This view should display the 'webform placeholder' field.

Edit the webform and add this view as a webform field.

The placeholder on each node in the view will be replaced with a webform submission field.

File

webform_view.module
View source
<?php

/**
 * @file
 * Allows views to be embedded in webforms and used as submission data.
 *
 *
 * This does NOT save all that data in a fully webform-compatible way for
 * reports, it just allows elements that were added on the fly to be processed
 * as data for emails. Data is not available for later reporting.
 *
 * USAGE.
 *
 * Add a field 'can order' as a boolean flag on nodes that can be ordered.
 *
 * Set its 'display' to be 'webform placeholder'
 *
 * Make a view for the nodes you want to show on a webform.
 * This view should display the 'webform placeholder' field.
 *
 * Edit the webform and add this view as a webform field.
 *
 * The placeholder on each node in the view will be replaced with a webform
 * submission field.
 */

/**
 * Declare our new component type for webform - an embedded view.
 *
 * Implements hook_webform_component_info().
 */
function webform_view_webform_component_info() {
  $component_info = array(
    'view' => array(
      'label' => t('Embedded view'),
      'description' => t('Allows a view to be embedded and each row in the view to be a selectable option.'),
      'file' => 'webform_view.inc',
      'features' => array(
        'default_value' => FALSE,
        'required' => TRUE,
        'description' => FALSE,
        'conditional' => FALSE,
        'group' => TRUE,
        'title_inline' => FALSE,
        'css_classes' => FALSE,
        'wrapper_classes' => FALSE,
      ),
    ),
  );
  return $component_info;
}

/**
 * Declare our custom theme.
 *
 * Catch the rendering of an embedded view at the end.
 *
 * Implements hook_theme().
 */
function webform_view_theme() {
  return array(
    'webform_view_embedded' => array(
      'render element' => 'element',
    ),
  );
}

/**
 * Implements hook_help().
 */
function webform_view_help($path, $arg) {
  $modulename = 'webform_view';
  switch ($path) {
    case 'admin/help#' . $modulename:
      $help_dir = drupal_get_path('module', $modulename) . '/help';
      $text = file_get_contents("{$help_dir}/index.html");
      $text = preg_replace('/(src|href)="([^\\/][^"]+)"/', '$1="' . url($help_dir) . '/$2"', $text);
      return $text;
  }
  return FALSE;
}

/**
 * Adjusts a webform_client_form.
 *
 * Calculates the unique key which is required later.
 *
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function webform_view_form_webform_client_form_alter(&$form, &$form_state, $form_id) {

  // Only process if there is submitted input.
  if (empty($form_state['input']) || empty($form_state['input']['submitted'])) {
    return;
  }
  $component_tree = $form_state['webform']['component_tree'];
  foreach ($component_tree['children'] as $cid => $component) {
    if ($component['type'] == 'view') {

      // Current component is a webform_view.
      $form_key = $component['form_key'];
      $val = array();
      $first_field = NULL;

      // Can clear out blank values here.
      // eg 'quantity';
      $required_key = $component['extra']['filter_field_id'];
      $inputs = $form_state['input']['submitted'];
      if (is_array($inputs[$form_key])) {
        foreach ($inputs[$form_key] as $nid => $values) {
          if (is_numeric($nid)) {

            // Iterate each node in the view.
            $node = node_load($nid);

            // Flatten the embedded view values.
            if (is_array($component['children'])) {
              foreach ($component['children'] as $key => $field) {

                // If value was submitted, use it, else use default.
                $v = isset($values[$field['form_key']]) ? $values[$field['form_key']] : $field['value'];
                $val[$nid][$field['form_key']] = token_replace($v, array(
                  'node' => $node,
                ));

                // Discover which was the first hidden field defined.
                if ($first_field === NULL && $field['type'] == 'hidden') {
                  $first_field = $field['form_key'];
                }
              }
            }
          }
        }
      }

      // This stores the submitted data in serialized format in the first
      // hidden field.
      if ($first_field !== NULL) {

        // If required key is set, then rows without it are skipped.
        foreach ($val as $nid => $v) {
          if ($required_key != '<none>' && empty($v[$required_key])) {
            unset($val[$nid]);
          }
        }
        $form['submitted'][$form_key][$first_field]['#value'] = serialize($val);
      }
    }
  }

  // Add custom validation
  $form['#validate'][] = 'webform_view_form_validate';
}

/**
 * Form API #validate handler for the webform_client_form() form.
 */
function webform_view_form_validate($form, &$form_state) {
  if ($form_state['webform']['preview'] && $form_state['webform']['page_count'] === $form_state['webform']['page_num']) {

    // Form has already passed validation and is on the preview page.
    return;
  }
  $component_tree = $form_state['webform']['component_tree'];
  foreach ($component_tree['children'] as $cid => $component) {
    if ($component['type'] == 'view') {

      // Current component is a webform_view.
      $form_key = $component['form_key'];

      // If the required field is set, verify that at least one of the values
      // is defined, and display an error if not
      $required_key = $component['extra']['filter_field_id'];
      if ($required_key != '<none>' && $component['required']) {
        $ok = FALSE;
        $inputs = $form_state['input']['submitted'];
        if (is_array($inputs[$form_key])) {
          foreach ($inputs[$form_key] as $nid => $values) {
            if (is_array($values) && !empty($values[$required_key])) {
              $ok = TRUE;
              break;
            }
          }
        }
        if (!$ok) {

          // Search for the right field in order to provide a nice name to the
          // user in the validation failure message
          foreach ($component['children'] as $ch_cid => $ch_component) {
            if ($ch_component['form_key'] == $required_key) {
              form_set_error('submitted][' . $form_key, t('!name field is required.', array(
                '!name' => $ch_component['name'],
              )));
              break;
            }
          }
        }
      }
    }
  }
}

/**
 * A special formatter to use as a placeholder to insert our view into a form.
 *
 * By declaring an alternative field formatter - to be used in place of the
 * 'can order' flag, we can insert form elements into the view display
 * and therefore into the webform.
 *
 * Field used on the content type must be a Boolean.
 * If so, then we can replace that item with a custom display renderer.
 *
 * Implements hook_field_formatter_info().
 */
function webform_view_field_formatter_info() {
  return array(
    'webform_view_placeholder' => array(
      'label' => t('A webform placeholder'),
      'field types' => array(
        'list_boolean',
      ),
    ),
  );
}

/**
 * Insert a PLACEHOLDER value as the text rendering of an item.
 *
 * The webform postprocess should replace this placeholder with the form element
 *
 * Implements hook_field_formatter_view().
 *
 * @see theme_webform_view_embedded()
 */
function webform_view_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  switch ($display['type']) {
    case 'webform_view_placeholder':
      foreach ($items as $delta => $item) {

        // Don't even insert the placeholder if there is no value in the trigger
        // element.
        if (!empty($item['value'])) {
          $key = $entity_type == 'node' ? $entity->nid : $entity->id;
          $replace_pattern = "[webform_view_" . $key . "_placeholder]";
          $element[$delta] = array(
            '#type' => 'markup',
            '#markup' => $replace_pattern,
          );
        }
        else {

          // Cannot order, return empty string.
          $element[$delta] = array(
            '#type' => 'markup',
            '#markup' => '',
          );
        }
      }
      break;
  }
  return $element;
}

/**
 * Implements hook_webform_csv_header_alter().
 */
function webform_view_webform_csv_header_alter(&$header, $component) {
  $node = node_load($component['nid']);
  if ($component['type'] == 'view') {

    // This component is a webform_view, use name as header
    $header[2] = t($component['name']);
  }
  else {

    // Current component parent is a webform_view, hide headers
    if ($node->webform['components'][$component['pid']]['type'] == 'view') {
      $header[2] = NULL;
    }
  }
}

/**
 * Implements hook_webform_csv_data_alter().
 */
function webform_view_webform_csv_data_alter(&$data, $component, $submission) {
  $node = node_load($component['nid']);
  if ($component['type'] == 'view') {

    // This component is a webform_view
    foreach ($node->webform['components'] as $cid => $comp) {

      // Get the data from the first hidden field that is a child of this one
      // and display each field separated with colon, and each item with a bar
      if ($comp['pid'] == $component['cid'] && $comp['type'] == 'hidden') {
        $values = array();
        foreach (unserialize($submission->data[$cid][0]) as $val) {
          $values[] = implode(':', $val);
        }
        $data = implode('|', $values);
        break;
      }
    }
  }
  else {

    // Current component parent is a webform_view, hide any data
    if ($node->webform['components'][$component['pid']]['type'] == 'view') {
      $data = NULL;
    }
  }
}

Functions

Namesort descending Description
webform_view_field_formatter_info A special formatter to use as a placeholder to insert our view into a form.
webform_view_field_formatter_view Insert a PLACEHOLDER value as the text rendering of an item.
webform_view_form_validate Form API #validate handler for the webform_client_form() form.
webform_view_form_webform_client_form_alter Adjusts a webform_client_form.
webform_view_help Implements hook_help().
webform_view_theme Declare our custom theme.
webform_view_webform_component_info Declare our new component type for webform - an embedded view.
webform_view_webform_csv_data_alter Implements hook_webform_csv_data_alter().
webform_view_webform_csv_header_alter Implements hook_webform_csv_header_alter().