protected function D7Webform::buildFormElements in Webform: Migrate 8
Same name and namespace in other branches
- 8.2 src/Plugin/migrate/source/d7/D7Webform.php \Drupal\webform_migrate\Plugin\migrate\source\d7\D7Webform::buildFormElements()
Build form elements from webform component table.
1 call to D7Webform::buildFormElements()
- D7Webform::prepareRow in src/
Plugin/ migrate/ source/ d7/ D7Webform.php - Adds additional data to the row.
File
- src/
Plugin/ migrate/ source/ d7/ D7Webform.php, line 184
Class
- D7Webform
- Drupal 7 webform source from database.
Namespace
Drupal\webform_migrate\Plugin\migrate\source\d7Code
protected function buildFormElements($nid) {
// TODO : Use yaml_emit http://php.net/manual/en/function.yaml-emit.php
$output = '';
$query = $this
->select('webform_component', 'wc');
$query
->fields('wc', [
'nid',
'cid',
'pid',
'form_key',
'name',
'type',
'value',
'extra',
'required',
'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;
// We might get element with same form_key
// d8 doesn't like that so rename it.
if ($depth > 0) {
$element['form_key'] = $element['form_key'] . '_' . $element['pid'];
}
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': webform_wizard_page\n '#title': {" . $current_page . "_title}\n";
$current_page_title = 'Start';
}
foreach ($elements_tree as $element) {
// Rename fieldsets to it's own unique key.
if ($element['type'] == 'fieldset' && strpos($element['form_key'], 'fieldset') === FALSE) {
$element['form_key'] = 'fieldset_' . $element['form_key'];
}
// 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']);
// The description key can be missing (since description is optional and
// it isn't saved by Drupal 7 webform when it is left empty).
$description = !empty($extra['description']) ? $this
->cleanString($extra['description']) : NULL;
// 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] . ": '" . str_replace('\'', '"', $option[1]) . "'\n";
}
else {
$options .= "{$indent}{$ingroup} " . $option[0] . ": '" . str_replace('\'', '"', $option[0]) . "'\n";
}
}
}
}
}
// Replace any tokens in the value.
if (!empty($element['value'])) {
$element['value'] = $this
->replaceTokens($element['value']);
}
$markup = $indent . strtolower($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']) && count($valid_options) > 1) {
$select_type = 'checkboxes';
}
elseif (!empty($extra['multiple']) && count($valid_options) == 1) {
$select_type = 'checkbox';
list($key, $desc) = explode('|', $extra['items']);
$markup .= "{$indent} '#description': \"" . $this
->cleanString($desc) . "\"\n";
}
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 (!empty($extra['min'])) {
$markup .= "{$indent} '#min': " . $extra['min'] . "\n";
}
if (!empty($extra['max'])) {
$markup .= "{$indent} '#max': " . $extra['max'] . "\n";
}
if (!empty($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':
case 'multiple_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);
}
$file_size = '';
if (!empty($extra['filtering']['size'])) {
// Get the string for the size. Will be something like "2 MB".
$size = $extra['filtering']['size'];
// Convert the string into an integer in bytes.
$file_size_bytes = Bytes::toInt($size);
// Convert that to MB.
$file_size = floor($file_size_bytes / 1024 / 1024);
// Failsafe as Webform doesn't let you go less than 1MB.
$file_size = $file_size < 1 ? 1 : $file_size;
}
$markup .= "{$indent} '#type': managed_file\n";
$markup .= "{$indent} '#max_filesize': '{$file_size}'\n";
$markup .= "{$indent} '#file_extensions': '{$exts}'\n";
if (!empty($extra['width'])) {
$markup .= "{$indent} '#size': " . $extra['width'] . "\n";
}
if ($element['type'] == 'multiple_file') {
$markup .= "{$indent} '#multiple': true\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': webform_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($extra['minuteincrements'])) {
// Setting expects seconds not minutes.
$step = (int) $extra['minuteincrements'] * 60;
$markup .= "{$indent} '#step': {$step}\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': webform_wizard_page\n '#title': {" . $current_page . "_title}\n";
$current_page_title = $element['name'];
$pageCnt++;
break;
case 'addressfield':
$markup .= "{$indent} '#type': webform_address\n";
$markup .= "{$indent} '#state_province__type': textfield\n";
break;
case 'grid':
$questionsArray = $this
->getItemsArray($extra['questions']);
$questions = $this
->buildItemsString($questionsArray, $indent . ' ');
$answersArray = $this
->getItemsArray($extra['options']);
$answers = $this
->buildItemsString($answersArray, $indent . ' ');
$markup .= "{$indent} '#type': webform_likert\n";
$markup .= "{$indent} '#questions':\n" . $questions . "\n";
$markup .= "{$indent} '#answers':\n" . $answers . "\n";
break;
default:
echo '';
}
if (!empty($element['type']) && is_string($element['type'])) {
$this
->getModuleHandler()
->alter('webform_migrate_d7_webform_element_' . $element['type'], $markup, $indent, $element);
}
// Add common fields.
if (!empty(trim($element['value'])) && (empty($valid_options) || in_array($element['value'], $valid_options))) {
$markup .= "{$indent} '#default_value': '" . str_replace(array(
'\'',
"\n",
"\r",
), array(
'"',
'\\n',
'',
), trim($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': '" . str_replace('\'', '"', $element['name']) . "'\n";
$markup .= "{$indent} '#description': \"" . $description . "\"\n";
}
if (!empty($element['required'])) {
$markup .= "{$indent} '#required': true\n";
}
// Build contionals.
if ($states = $this
->buildConditionals($element, $elements)) {
$markup .= "{$indent} '#states':\n";
foreach ($states as $key => $values) {
$markup .= "{$indent} {$key}:\n";
foreach ($values as $value) {
foreach ($value as $name => $item) {
$markup .= "{$indent} " . Yaml::dump($name, 2, 2) . ":\n";
foreach (explode("\n", Yaml::dump($item, 2, 2)) as $line) {
if (!empty($line)) {
$markup .= "{$indent} " . $line . "\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,
];
}