diff --git a/src/Element/WebformMapping.php b/src/Element/WebformMapping.php index f8f027de..9e3b0686 100644 --- a/src/Element/WebformMapping.php +++ b/src/Element/WebformMapping.php @@ -14,6 +14,11 @@ use Drupal\Core\Render\Element\FormElement; class WebformMapping extends FormElement { /** + * Require all. + */ + const REQUIRED_ALL = 'all'; + + /** * {@inheritdoc} */ public function getInfo() { @@ -53,8 +58,9 @@ class WebformMapping extends FormElement { // Set base destination element. $destination_element_base = [ '#title_display' => 'invisible', - '#required' => $element['#required'], + '#required' => ($element['#required'] === self::REQUIRED_ALL) ? TRUE : FALSE, ]; + // Get base #destination__* properties. foreach ($element as $element_key => $element_value) { if (strpos($element_key, '#destination__') === 0 && !in_array($element_key, ['#destination__title'])) { @@ -104,6 +110,10 @@ class WebformMapping extends FormElement { ], ] + $rows; + + // Cast required to boolean since, it can be set to self::REQUIRED_ALL. + $element['#required'] = (bool) $element['#required']; + $element['#element_validate'] = [[get_called_class(), 'validateWebformMapping']]; return $element; @@ -114,8 +124,25 @@ class WebformMapping extends FormElement { * Validates a mapping element. */ public static function validateWebformMapping(&$element, FormStateInterface $form_state, &$complete_form) { - $values = NestedArray::getValue($form_state->getValues(), $element['#parents']); - $form_state->setValueForElement($element, array_filter($values)); + $value = NestedArray::getValue($form_state->getValues(), $element['#parents']); + $value = array_filter($value); + + $has_access = (!isset($element['#access']) || $element['#access'] === TRUE); + // Note: Not validating REQUIRED_ALL because each destination element is + // already required. + if ($element['#required'] && $element['#required'] !== self::REQUIRED_ALL && empty($value) && $has_access) { + if (isset($element['#required_error'])) { + $form_state->setError($element, $element['#required_error']); + } + elseif (isset($element['#title'])) { + $form_state->setError($element, t('@name field is required.', ['@name' => $element['#title']])); + } + else { + $form_state->setError($element); + } + } + + $form_state->setValueForElement($element, $value); } } diff --git a/src/Plugin/WebformElement/WebformMapping.php b/src/Plugin/WebformElement/WebformMapping.php index d803a0fb..05f2e44d 100644 --- a/src/Plugin/WebformElement/WebformMapping.php +++ b/src/Plugin/WebformElement/WebformMapping.php @@ -40,6 +40,7 @@ class WebformMapping extends WebformElementBase { 'description_display' => '', // Form validation. 'required' => FALSE, + 'required_error' => '', // Submission display. 'format' => $this->getItemDefaultFormat(), // Mapping settings. diff --git a/src/Tests/Element/WebformElementMappingTest.php b/src/Tests/Element/WebformElementMappingTest.php index e757b59b..30558707 100644 --- a/src/Tests/Element/WebformElementMappingTest.php +++ b/src/Tests/Element/WebformElementMappingTest.php @@ -40,11 +40,27 @@ class WebformElementMappingTest extends WebformTestBase { // Check custom textfield #size property. $this->assertRaw(''); + // Check required. + $this->drupalPostForm('webform/test_element_mapping', [], t('Submit')); + $this->assertRaw('webform_mapping_required field is required.'); + $this->assertRaw('One field is required.'); + $this->assertRaw('Two field is required.'); + $this->assertRaw('Three field is required.'); + + // Check that required all element does not display error since all the + // destination elements are required. + // @see \Drupal\webform\Element\WebformMapping::validateWebformMapping + $this->assertNoRaw('webform_mapping_required_all field is required.'); + // Check processing. $edit = [ 'webform_mapping[one]' => 'four', 'webform_mapping[two]' => '', 'webform_mapping[three]' => 'six', + 'webform_mapping_required[one]' => 'four', + 'webform_mapping_required_all[one]' => 'four', + 'webform_mapping_required_all[two]' => 'five', + 'webform_mapping_required_all[three]' => 'six', 'webform_mapping_custom[Sunday]' => 'four', 'webform_mapping_custom[Monday]' => 'four', 'webform_mapping_custom[Tuesday]' => 'four', @@ -75,6 +91,12 @@ webform_mapping_custom: Thursday: four Friday: four Saturday: four +webform_mapping_required: + one: four +webform_mapping_required_all: + one: four + two: five + three: six webform_mapping_select_other: one: five two: five diff --git a/tests/modules/webform_test/config/install/webform.webform.test_element_mapping.yml b/tests/modules/webform_test/config/install/webform.webform.test_element_mapping.yml index 3179f853..cc443e5b 100644 --- a/tests/modules/webform_test/config/install/webform.webform.test_element_mapping.yml +++ b/tests/modules/webform_test/config/install/webform.webform.test_element_mapping.yml @@ -40,6 +40,30 @@ elements: | four: Four five: Five six: Six + webform_mapping_required: + '#type': webform_mapping + '#title': webform_mapping_required + '#required': true + '#source': + one: One + two: Two + three: Three + '#destination': + four: Four + five: Five + six: Six + webform_mapping_required_all: + '#type': webform_mapping + '#title': webform_mapping_required_all + '#required': all + '#source': + one: One + two: Two + three: Three + '#destination': + four: Four + five: Five + six: Six webform_mapping_select_other_elements: '#type': details '#title': webform_mapping_select_other_elements