You are here

function _webform_render_view in Webform view 7

Same name and namespace in other branches
  1. 7.4 webform_view.inc \_webform_render_view()

Show the embedded view on the webform.

The returned renderable array representing the element to be themed may include form elements & nesting.

Implements _webform_render_component().

File

./webform_view.inc, line 125
Additional component for webform that allows views to be used as embeddable elements.

Code

function _webform_render_view($component, $value_serialized = NULL, $filter = TRUE) {
  if (!empty($value_serialized) && is_array($value_serialized)) {
    $value = unserialize(reset($value_serialized));
  }
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
  $view_key = $component['extra']['view'];
  $args = explode('/', $component['extra']['contextual_filters']);
  $args = array_filter($args);
  $placeholder_fields = array();

  // Nicely stolen from views_block_view()
  // If the delta doesn't contain valid data return nothing.
  $explode = explode('-', $view_key);
  if (count($explode) != 2) {
    return NULL;
  }
  list($name, $display_id) = $explode;

  // Load the view.
  if (!($view = views_get_view($name))) {
    watchdog('webform_view', 'Invalid view - cannot embed %name %display_id', array(
      '%name' => $name,
      '%display_id' => $display_id,
    ));
    return NULL;
  }
  if (!$view
    ->access($display_id)) {
    watchdog('webform_view', 'View access denied - cannot embed %name %display_id', array(
      '%name' => $name,
      '%display_id' => $display_id,
    ));
  }

  // execute_display produces cooked text.
  // It can include a placeholder string for our form elements,
  // if a field chooses to use the 'webform_placeholder' as a renderer.
  $output = $view
    ->preview($display_id, $args);
  if (empty($output)) {
    return NULL;
  }

  // Go through the rows to prepare the webform-like fields.
  // Do this by CLONING the children elements already nested in this one.
  foreach ($view->result as $index => $row) {

    // Key on the real row ID if possible.
    $key = isset($row->{$view->base_field}) ? $row->{$view->base_field} : $index;

    // If reviewing or editing fields, the $value array may be available.
    // It's our job to put it back into the element.
    $component_value = isset($value[$key]) ? $value[$key] : array();

    // This is now an array representing the data last stored in this row.
    // One of these fields should probably be a textfield that can hold the
    // item identifier
    // Should use tokens to prefill it. Would be good.
    // For now, just steal values direct from the row result.
    // A token like [node_title] will pull the id from a view -
    // as long as the view row has that data.
    // I can't expose to the user what those machine names are however...
    // https://drupal.org/node/2099751
    // They just have to guess.
    $tokens = array();
    foreach ($row as $token_key => $token_val) {
      if (is_string($token_val)) {
        $tokens["[{$token_key}]"] = $token_val;
      }
      elseif (is_array($token_val) && ($sub_val = reset($token_val))) {
        if (isset($sub_val) && isset($sub_val['raw']) && isset($sub_val['raw']['value'])) {
          $tokens["[{$token_key}]"] = $sub_val['raw']['value'];
        }
      }
    }

    // Each component that is defined as a child of this view component
    // gets replicated.
    if (empty($component['children'])) {
      watchdog('webform_view', '
        The embedded webform component "!component" in "!webform" has no
        "child" elements defined.
        If you want the webform to submit data, please create a webform
        field element and nest it beneath the embedded view.
        ...And then configure the view to expose this field in its layout.
        ', array(
        '!component' => l($component['name'], '/node/' . $node->nid . '/webform/components/' . $component['cid']),
        '!webform' => l($node->title, '/node/' . $node->nid . '/webform/components/'),
      ), WATCHDOG_NOTICE);
      $component['children'] = array();
    }
    foreach ((array) $component['children'] as $webform_component) {

      // Some webform welements are not native. @see webform_element_info
      $type = $webform_component['type'];
      $webform_elements = array(
        'number' => 'webform_number',
      );
      if (isset($webform_elements[$type])) {
        $type = $webform_elements[$type];
      }

      // Use replacements to put the item identifier into a field value.
      $default_value = NULL;
      if (!empty($webform_component['value'])) {
        $default_value = str_replace(array_keys($tokens), array_values($tokens), $webform_component['value']);
      }

      // Copy any previously set value into our element default value.
      if (isset($component_value[$webform_component['form_key']])) {
        $default_value = $component_value[$webform_component['form_key']];
      }

      // Webform components are very unlike normal form elements.
      // that's a bore. Copy some parameters like size across.
      // Can I delegate this to each elements own webform_render_THING
      // callback - I feel like doing this by hand could be errorful.?
      $render_func = '_webform_render_' . $webform_component['type'];
      if (function_exists($render_func)) {

        // The value arg is apparently expected to be an array? Whatever.
        if (!is_array($default_value)) {
          $default_value = array(
            $default_value,
          );
        }
        $placeholder_fields[$key][$webform_component['form_key']] = $render_func($webform_component, $default_value);
        $placeholder_fields[$key][$webform_component['form_key']]['#webform_component'] = $webform_component;
      }
      else {

        /*
        //////SNIP THIS
        // This was me doing it by hand - probably redundant if ^ is working.
        $placeholder_fields[$key][$webform_component['form_key']] = array(
          '#type' => $type,
          '#title' => $webform_component['name'],
          '#size' => isset($webform_component['extra']['width'])
            ? $webform_component['extra']['width'] : NULL,
          '#default_value' => isset($default_value) ? $default_value : NULL,
          '#webform_component' => $webform_component,
          // Need to call in the theme wrapper to get field markup
          // and title to show.
          '#theme_wrappers' => ($type == 'hidden')
            ? array() : array('webform_element'),
        );
        /////
        */
      }
    }
  }

  // $display = $view->display[$view->current_display];
  $element = array(
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
    '#required' => $component['mandatory'],
    '#weight' => $component['weight'],
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
    '#theme_wrappers' => array(
      'webform_element',
    ),
    '#theme' => 'webform_view_embedded',
    // Needed to disable double-wrapping of radios and checkboxes.
    '#pre_render' => array(),
    '#translatable' => array(
      'title',
      'description',
      'options',
    ),
    // When webform renders elements, the content is expected to be inside
    // element #children. #markup is not respected.
    '#type' => 'markup',
  );

  // Add the made-up placeholder fields as children.
  $element += $placeholder_fields;

  // Add our embedded view as a renderable.
  // Using #markup so that even if rendering starts falling apart later,
  // it will still show up. Normally however, this value gets caught and
  // preprocessed in theme_webform_view_embedded()
  $element['view']['#markup'] = $output;

  // Don't do this until we are finished with the data.
  // $view->destroy();
  return $element;
}