You are here

protected function D6Webform::buildFormElements in Webform: Migrate 8

Same name and namespace in other branches
  1. 8.2 src/Plugin/migrate/source/d6/D6Webform.php \Drupal\webform_migrate\Plugin\migrate\source\d6\D6Webform::buildFormElements()

Build form elements from webform component table.

1 call to D6Webform::buildFormElements()
D6Webform::prepareRow in src/Plugin/migrate/source/d6/D6Webform.php
Adds additional data to the row.

File

src/Plugin/migrate/source/d6/D6Webform.php, line 154

Class

D6Webform
Drupal 6 webform source from database.

Namespace

Drupal\webform_migrate\Plugin\migrate\source\d6

Code

protected function buildFormElements($nid) {
  $output = '';
  $query = $this
    ->select('webform_component', 'wc');
  $query
    ->fields('wc', [
    'nid',
    'cid',
    'pid',
    'form_key',
    'name',
    'type',
    'value',
    'extra',
    'mandatory',
    'weight',
  ]);
  $components = $query
    ->condition('nid', $nid)
    ->orderBy('pid')
    ->orderBy('weight')
    ->execute();
  $children = [];
  $parents = [];
  $elements = [];
  $xref = [];

  // Build an array of elements in the correct order for rendering based on
  // pid and weight and a cross reference array to match cid with form_key
  // used by email handler.
  $multiPage = FALSE;
  foreach ($components as $component) {
    $xref[$component['cid']] = $component['form_key'];
    if ($component['type'] == 'pagebreak') {

      // Pagebreak found so we have a multi-page form.
      $multiPage = TRUE;
    }
    $children[$component['pid']][] = $component['cid'];
    $parents[$component['cid']][] = $component['pid'];
    $elements[$component['cid']] = $component;
  }

  // Keeps track of the parents we have to process, the last entry is used
  // for the next processing step.
  $process_parents = [];
  $process_parents[] = 0;
  $elements_tree = [];

  // Loops over the parent components and adds its children to the tree array.
  // Uses a loop instead of a recursion, because it's more efficient.
  while (count($process_parents)) {
    $parent = array_pop($process_parents);

    // The number of parents determines the current depth.
    $depth = count($process_parents);
    if (!empty($children[$parent])) {
      $has_children = FALSE;
      $child = current($children[$parent]);
      do {
        if (empty($child)) {
          break;
        }
        $element = $elements[$child];
        $element['depth'] = $depth;
        unset($element['pid']);
        $elements_tree[] = $element;
        if (!empty($children[$element['cid']])) {
          $has_children = TRUE;

          // We have to continue with this parent later.
          $process_parents[] = $parent;

          // Use the current component as parent for the next iteration.
          $process_parents[] = $element['cid'];

          // Reset pointers for child lists because we step in there more often
          // with multi parents.
          reset($children[$element['cid']]);

          // Move pointer so that we get the correct term the next time.
          next($children[$parent]);
          break;
        }
      } while ($child = next($children[$parent]));
      if (!$has_children) {

        // We processed all components in this hierarchy-level.
        reset($children[$parent]);
      }
    }
  }

  // If form has multiple pages then start first page automatically.
  if ($multiPage) {
    $pageCnt = 1;
    $current_page = 'wizard_page_1';
    $output .= "first_page:\n  '#type': wizard_page\n  '#title': {" . $current_page . "_title}\n  '#open': true\n";
    $current_page_title = t('Page') . ' ' . $pageCnt++;
  }
  foreach ($elements_tree as $element) {

    // If this is a multi-page form then indent all elements one level
    // to allow for page elements.
    if ($multiPage && $element['type'] != 'pagebreak') {
      $element['depth'] += 1;
    }
    $indent = str_repeat(' ', $element['depth'] * 2);
    $extra = unserialize($element['extra']);
    $description = $this
      ->cleanString($extra['description']);

    // Create an option list if there are items for this element.
    $options = '';
    $valid_options = [];
    if (!empty($extra['items'])) {
      $items = explode("\n", trim($extra['items']));
      $ingroup = '';
      foreach ($items as $item) {
        $item = trim($item);
        if (!empty($item)) {

          // Handle option groups.
          if (preg_match('/^<(.*)>$/', $item, $matches)) {
            if (empty(trim($matches[1]))) {
              $ingroup = '';
              continue;
            }
            $options .= "{$indent}    '" . $matches[1] . "':\n";
            $ingroup = str_repeat(' ', 2);
          }
          else {
            $option = explode('|', $item);
            $valid_options[] = $option[0];
            if (count($option) == 2) {
              $options .= "{$indent}{$ingroup}    " . $option[0] . ": " . $option[1] . "\n";
            }
            else {
              $options .= "{$indent}{$ingroup}    " . $option[0] . ": " . $option[0] . "\n";
            }
          }
        }
      }
    }

    // Replace any tokens in the value.
    if (!empty($element['value'])) {
      $element['value'] = $this
        ->replaceTokens($element['value']);
    }
    $markup = $indent . $element['form_key'] . ":\n";
    switch ($element['type']) {
      case 'fieldset':
        if ($multiPage && empty($current_page_title)) {
          $current_page_title = $element['name'];
        }
        $markup .= "{$indent}  '#type': fieldset\n{$indent}  '#open': true\n";
        break;
      case 'textfield':
        $markup .= "{$indent}  '#type': textfield\n";
        if (!empty($extra['width'])) {
          $markup .= "{$indent}  '#size': " . (int) $extra['width'] . "\n";
        }
        break;
      case 'textarea':
        $markup .= "{$indent}  '#type': textarea\n";
        break;
      case 'select':
        if (!empty($extra['aslist'])) {
          $select_type = 'select';
        }
        elseif (!empty($extra['multiple'])) {
          $select_type = 'checkboxes';
        }
        else {
          $select_type = 'radios';
        }
        $markup .= "{$indent}  '#type': {$select_type}\n";
        $markup .= "{$indent}  '#options':\n" . $options;
        if (!empty($extra['multiple'])) {
          $markup .= "{$indent}  '#multiple': true\n";
        }
        break;
      case 'email':
        $markup .= "{$indent}  '#type': email\n{$indent}  '#size': 20\n";
        break;
      case 'number':
        if ($extra['type'] == 'textfield') {
          $markup .= "{$indent}  '#type': textfield\n{$indent}  '#size': 20\n";
        }
        elseif ($extra['type'] == 'select') {
          $markup .= "{$indent}  '#type': select\n";
          $markup .= "{$indent}  '#options':\n" . $options;
          $min = $extra['min'];
          $max = $extra['max'];
          $step = !empty($extra['step']) ? $extra['step'] : 1;
          for ($value = $min; $value <= $max; $value += $step) {
            $markup .= "{$indent}    " . $value . ": " . $value . "\n";
          }
        }
        if (isset($extra['min'])) {
          $markup .= "{$indent}  '#min': " . $extra['min'] . "\n";
        }
        if (isset($extra['max'])) {
          $markup .= "{$indent}  '#max': " . $extra['max'] . "\n";
        }
        if (isset($extra['step'])) {
          $markup .= "{$indent}  '#step': " . $extra['step'] . "\n";
        }
        if (isset($extra['unique'])) {
          $unique = $extra['unique'] ? 'true' : 'false';
          $markup .= "{$indent}  '#unique': " . $unique . "\n";
        }
        break;
      case 'markup':
        $markup .= "{$indent}  '#type': processed_text\n{$indent}  '#format': full_html\n{$indent}  '#text': \"" . $this
          ->cleanString($element['value']) . "\"\n";
        $element['value'] = '';
        break;
      case 'file':
        $exts = '';
        if (!empty($extra['filtering']['types'])) {
          $types = $extra['filtering']['types'];
          if (!empty($extra['filtering']['addextensions'])) {
            $add_types = explode(',', $extra['filtering']['addextensions']);
            $types = array_unique(array_merge($types, array_map('trim', $add_types)));
          }
          $exts = implode(',', $types);
        }
        $filesize = '';
        if (!empty($extra['filtering']['size'])) {
          $filesize = $extra['filtering']['size'] / 1000;
        }
        $markup .= "{$indent}  '#type': managed_file\n";
        $markup .= "{$indent}  '#max_filesize': '{$filesize}'\n";
        $markup .= "{$indent}  '#file_extensions': '{$exts}'\n";
        if (!empty($extra['width'])) {
          $markup .= "{$indent}  '#size': " . $extra['width'] . "\n";
        }
        break;
      case 'date':
        $markup .= "{$indent}  '#type': date\n";

        /*if (!empty($element['value'])) {
          $element['value'] = date('Y-m-d', strtotime($element['value']));
          }*/
        break;
      case 'time':
        $markup .= "{$indent}  '#type': time\n";
        if (!empty($extra['hourformat'])) {
          if ($extra['hourformat'] == '12-hour') {
            $markup .= "{$indent}  '#time_format': 'g:i A'\n";
          }
          elseif ($extra['hourformat'] == '24-hour') {
            $markup .= "{$indent}  '#time_format': 'H:i'\n";
          }
        }

        /*if (!empty($element['value'])) {
          $element['value'] = date('c', strtotime($element['value']));
          }*/
        break;
      case 'hidden':
        $markup .= "{$indent}  '#type': hidden\n";
        break;
      case 'pagebreak':
        $output = str_replace('{' . $current_page . '_title}', $current_page_title, $output);
        $current_page = $element['form_key'];
        $markup .= "{$indent}  '#type': wizard_page\n  '#open': true\n  '#title': {" . $current_page . "_title}\n";
        $current_page_title = t('Page') . ' ' . $pageCnt++;
        break;
    }
    if (!empty($element['type']) && is_string($element['type'])) {
      $this
        ->getModuleHandler()
        ->alter('webform_migrate_d6_weform_element_' . $element['type'], $markup, $indent, $element);
    }

    // Add common fields.
    if (!empty($element['value']) && (empty($valid_options) || in_array($element['value'], $valid_options))) {
      $markup .= "{$indent}  '#default_value': " . $element['value'] . "\n";
    }
    if (!empty($extra['field_prefix'])) {
      $markup .= "{$indent}  '#field_prefix': " . $extra['field_prefix'] . "\n";
    }
    if (!empty($extra['field_suffix'])) {
      $markup .= "{$indent}  '#field_suffix': " . $extra['field_suffix'] . "\n";
    }
    if (!empty($extra['title_display']) && $extra['title_display'] != 'before') {
      $title_display = $extra['title_display'];
      if ($title_display == 'none') {
        $title_display = 'invisible';
      }
      $markup .= "{$indent}  '#title_display': " . $title_display . "\n";
    }
    if ($element['type'] != 'pagebreak') {
      $markup .= "{$indent}  '#title': " . $element['name'] . "\n";
      $markup .= "{$indent}  '#description': \"" . $description . "\"\n";
    }
    if (!empty($element['mandatory'])) {
      $markup .= "{$indent}  '#required': true\n";
    }
    $output .= $markup;
  }
  if ($multiPage) {

    // Replace the final page title.
    $output = str_replace('{' . $current_page . '_title}', $current_page_title, $output);
  }
  return [
    'elements' => $output,
    'xref' => $xref,
  ];
}