function _wfm_process_elements in Webform Multiple (WFM) 7
Process an element in the Webform to allow multiple values.
This is called recursively, throughout the form element tree.
Parameters
array &$element: The Form API element.
array &$form_state: The Form API form state.
stdClass $submission: The Webform submission object (when displaying or editing an existing submission), or an empty array.
bool $display: Whether the element should be themed for display (e.g. when viewing results), or as a form input. This is eventually passed on to _wfm_component_generate().
string $format: The display format, usually 'html' or 'text' ('html' by default). This is also passed on to _wfm_component_generate().
2 calls to _wfm_process_elements()
- wfm_form_webform_client_form_alter in ./
wfm.module - Implements hook_form_FORM_ID_alter().
- wfm_webform_submission_render_alter in ./
wfm.module - Implements hook_webform_submission_render_alter().
File
- ./
wfm.module, line 128 - Main module file for Webform Multiple (WFM).
Code
function _wfm_process_elements(&$element, &$form_state, $submission, $display = FALSE, $format = 'html') {
if (!$element || !isset($element['#webform_component'])) {
return;
}
$component = $element['#webform_component'];
$form_key = $component['form_key'];
$cid = $component['cid'];
$element_name = isset($element['#name']) ? $element['#name'] : "submitted[{$form_key}]";
$element_parents = isset($element['#parents']) ? $element['#parents'] : array(
'submitted',
$form_key,
);
$element_wfm_parents = isset($element['#wfm_parents']) ? $element['#wfm_parents'] : array(
$cid,
);
$initial_weight = isset($element['#weight']) ? $element['#weight'] : 1;
$form_state['wfm_ancestors'][$cid][implode('.', $element_parents)] = $element_parents;
// Stop processing if this component does not accept multiple values.
if (empty($component) || !_wfm_is_multiple($component)) {
// Recurse through the element's children.
foreach (element_children($element) as $key) {
if (!$element[$key] || !isset($element[$key]['#webform_component'])) {
continue;
}
$sub_element =& $element[$key];
$sub_component = $sub_element['#webform_component'];
$scid = $sub_element['#webform_component']['cid'];
$sub_element['#name'] = $element_name . "[{$key}]";
$sub_element['#parents'] = $element_parents;
$sub_element['#parents'][] = $key;
$sub_element['#wfm_parents'] = $element_wfm_parents;
$sub_element['#wfm_parents'][] = $scid;
if (empty($sub_component['children'])) {
array_unshift($sub_element['#wfm_parents'], $scid);
}
_wfm_process_elements($sub_element, $form_state, $submission, $display, $format);
}
return;
}
// Get the current item count for this component.
$max_items = _wfm_get_max_items($component);
$min_items = _wfm_get_min_items($component);
// The $delta keys for each component are saved in $form_state so they can be
// modified by the add/remove callbacks.
$new = FALSE;
if (!isset($form_state['wfm_deltas'][$element_name])) {
$new = TRUE;
$form_state['wfm_deltas'][$element_name] = array();
}
$element_deltas =& $form_state['wfm_deltas'][$element_name];
// Get the value and the item count from the submission, if there is one, and
// if $form_state was not already populated.
if ($submission && $new) {
if (isset($submission->wfm_data[$cid]) && !empty($component['children'])) {
$element_value = array_keys($submission->wfm_data[$cid]);
}
else {
$element_value = drupal_array_get_nested_value($submission->wfm_data, $element_wfm_parents);
}
if (is_array($element_value)) {
$deltas = array_keys($element_value);
foreach ($deltas as $delta) {
if (is_numeric($delta)) {
$element_deltas[$delta] = $delta;
}
}
}
}
// Pad the $delta keys if there aren't enough.
$missing = $min_items - count($element_deltas);
if ($missing > 0) {
$last_delta = empty($element_deltas) ? -1 : max(array_keys($element_deltas));
for ($i = 1; $i <= $missing; $i++) {
$next_delta = $last_delta + $i;
$element_deltas[$next_delta] = $next_delta;
}
}
$item_count = count($element_deltas);
// Replace the element with a parent container.
if (!isset($element['#wfm_wrapper'])) {
// Generate the ID that Webform would have given this element if it were a
// single instance.
//
// This ID must remain unique so that the 'Add another item' buttons can
// address the right AJAX wrapper (on multiple-instance descendants of
// multiple-instance ancestors), but it must also be in the format:
// "webform-component-$form_key"
// so that conditionals will work on the first instance. At the moment
// there's no way to get conditionals to work on multiple instances without
// breaking the HTML specification of unique ID attributes.
//
// Note that drupal_html_id() will always produce a unique ID, although
// unfortunately it isn't fast.
$wrapper_id = drupal_html_id('webform-component-' . str_replace('_', '-', $form_key));
$element = array(
'#type' => 'container',
'#wfm_wrapper' => TRUE,
'#webform_component' => $component,
'#attributes' => array(
'id' => $wrapper_id,
'class' => array(
'wfm-container',
),
),
'#wrapper_id' => $wrapper_id,
'#weight' => $initial_weight,
'#name' => $element_name,
'#parents' => $element_parents,
'#wfm_parents' => $element_wfm_parents,
);
// Add the 'Add another item' button.
if (!$display) {
$element['add_more'] = array(
'#type' => 'submit',
'#value' => _wfm_get_add_text($component),
'#weight' => $initial_weight + 0.5,
'#limit_validation_errors' => array(
array(
'submitted',
$form_key,
),
),
'#submit' => array(
'wfm_add_more_submit',
),
'#attributes' => array(
'class' => array(
'wfm-add',
),
),
'#ajax' => array(
'callback' => 'wfm_js',
'wrapper' => $wrapper_id,
),
);
}
}
$item_number = 1;
foreach ($element_deltas as $delta) {
// Remove the 'Add another item' button where appropriate.
$final = $item_count == $max_items;
if ($final) {
unset($element['add_more']);
}
elseif (!$display) {
$element['add_more']['#name'] = $element_name . '_ADD_' . $delta;
}
// Define the parents of the item.
$wfm_parents = $element['#wfm_parents'];
$wfm_parents[] = $delta;
// Get the default value of the item.
$default_value = NULL;
if (!empty($element_value) && empty($component['children'])) {
$default_value = drupal_array_get_nested_value($submission->wfm_data, $wfm_parents);
$default_value = (array) $default_value;
}
// Generate any new form items needed. They are all added as children of the
// parent $element, keyed by $delta.
if (!isset($element[$delta])) {
$new_element = _wfm_component_generate($component, $display, $default_value, $format);
$new_element['#weight'] = $initial_weight + $item_number / 100;
$element[$delta] = $new_element;
}
// Process new and existing form items.
$item =& $element[$delta];
$item['#name'] = $element_name . "[{$delta}]";
$item['#parents'] = $element['#parents'];
$item['#parents'][] = $delta;
$item['#wfm_parents'] = $wfm_parents;
// Add the item's children (e.g. if it's a fieldset).
if (!empty($component['children'])) {
foreach ($component['children'] as $scid => $sub_component) {
$sub_component_key = $sub_component['form_key'];
$sub_item_wfm_parents = $item['#wfm_parents'];
$sub_item_wfm_parents[] = $scid;
if (empty($sub_component['children'])) {
array_unshift($sub_item_wfm_parents, $scid);
}
if (!isset($item[$sub_component_key])) {
$sub_item_value = NULL;
if ($submission && !_wfm_is_multiple($sub_component)) {
$sub_item_value = drupal_array_get_nested_value($submission->wfm_data, $sub_item_wfm_parents, $exists);
if ($exists) {
$sub_item_value = (array) $sub_item_value;
}
}
$item[$sub_component_key] = _wfm_component_generate($sub_component, $display, $sub_item_value, $format);
}
$sub_item =& $item[$sub_component_key];
$sub_item['#name'] = $item['#name'] . "[{$sub_component_key}]";
$sub_item['#parents'] = $item['#parents'];
$sub_item['#parents'][] = $sub_component_key;
$sub_item['#wfm_parents'] = $sub_item_wfm_parents;
// Recursively process any multiple-value children.
_wfm_process_elements($sub_item, $form_state, $submission, $display);
}
}
// Append numbering to the form input's title.
if ($item_count > 1) {
$item['#title'] = t('@title (@num/@count)', array(
'@title' => $item['#title'],
'@num' => $item_number,
'@count' => $item_count,
));
}
$item['#prefix'] = '<div class="wfm-item">';
$item['#suffix'] = '</div>';
// Add a 'Remove' button, to appear just after the form input.
if ($min_items > 0 && $item_count > $min_items && !$display) {
$element['remove_' . $delta] = array(
'#type' => 'submit',
'#value' => t('Remove'),
'#limit_validation_errors' => array(),
'#submit' => array(
'wfm_remove_submit',
),
'#attributes' => array(
'class' => array(
'wfm-remove',
),
'title' => t('Remove "@title"', array(
'@title' => $item['#title'],
)),
),
'#ajax' => array(
'callback' => 'wfm_js',
'wrapper' => $element['#wrapper_id'],
),
'#weight' => $item['#weight'] + 0.001,
'#name' => $element_name . '_REMOVE_' . $delta,
);
// Include the remove button within the 'wfm-item' div container.
$element['remove_' . $delta]['#suffix'] = '</div>';
unset($item['#suffix']);
}
$item_number++;
}
}