diff --git a/core/lib/Drupal/Core/Form/FormState.php b/core/lib/Drupal/Core/Form/FormState.php index 6655494..3195202 100644 --- a/core/lib/Drupal/Core/Form/FormState.php +++ b/core/lib/Drupal/Core/Form/FormState.php @@ -250,7 +250,7 @@ class FormState implements FormStateInterface { * * @var array */ - protected $input; + protected $input = []; /** * If TRUE and the method is GET, a form_id is not necessary. diff --git a/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php b/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php index cf8b2cb..c063666 100644 --- a/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php +++ b/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php @@ -1,10 +1,5 @@ getValues(); @@ -45,7 +40,7 @@ public function setValues(array $values) { } /** - * @see \Drupal\Core\Form\FormStateInterface::setValue() + * Implements \Drupal\Core\Form\FormStateInterface::setValue() */ public function setValue($key, $value) { NestedArray::setValue($this->getValues(), (array) $key, $value, TRUE); @@ -53,7 +48,7 @@ public function setValue($key, $value) { } /** - * @see \Drupal\Core\Form\FormStateInterface::unsetValue() + * Implements \Drupal\Core\Form\FormStateInterface::unsetValue() */ public function unsetValue($key) { NestedArray::unsetValue($this->getValues(), (array) $key); @@ -61,7 +56,7 @@ public function unsetValue($key) { } /** - * @see \Drupal\Core\Form\FormStateInterface::hasValue() + * Implements \Drupal\Core\Form\FormStateInterface::hasValue() */ public function hasValue($key) { $exists = NULL; @@ -70,7 +65,7 @@ public function hasValue($key) { } /** - * @see \Drupal\Core\Form\FormStateInterface::isValueEmpty() + * Implements \Drupal\Core\Form\FormStateInterface::isValueEmpty() */ public function isValueEmpty($key) { $exists = NULL; @@ -79,7 +74,7 @@ public function isValueEmpty($key) { } /** - * @see \Drupal\Core\Form\FormStateInterface::setValueForElement() + * Implements \Drupal\Core\Form\FormStateInterface::setValueForElement() */ public function setValueForElement(array $element, $value) { return $this->setValue($element['#parents'], $value); diff --git a/core/lib/Drupal/Core/Form/SubformState.php b/core/lib/Drupal/Core/Form/SubformState.php index f6ed8c0..543b199 100644 --- a/core/lib/Drupal/Core/Form/SubformState.php +++ b/core/lib/Drupal/Core/Form/SubformState.php @@ -1,10 +1,5 @@ getParents('#parents'), $exists); + + // If no input already exists, create it, so it can be referenced. + if (!$exists) { + $this->setUserInput([]); + $input = &NestedArray::getValue(parent::getUserInput(), $this->getParents('#parents'), $exists); + } + + return $input; + } + + /** + * {@inheritdoc} + */ + public function setUserInput(array $user_input) { + NestedArray::setValue(parent::getUserInput(), $this->getParents('#parents'), $user_input, TRUE); + + return $this; + } + } diff --git a/core/lib/Drupal/Core/Form/SubformStateInterface.php b/core/lib/Drupal/Core/Form/SubformStateInterface.php index 7329c41..4d04d58 100644 --- a/core/lib/Drupal/Core/Form/SubformStateInterface.php +++ b/core/lib/Drupal/Core/Form/SubformStateInterface.php @@ -1,10 +1,5 @@ 'bar', + 'dog' => [ + 'breed' => 'Pit bull', + 'name' => 'Dodger', + ], + ]; + + /** + * The form state's values test fixture. * * @var mixed[] */ @@ -74,8 +82,13 @@ public function testGetValues(array $parents, $expected) { $subform = NestedArray::getValue($this->parentForm, $parents); $subform_state = SubformState::createForSubform($subform, $this->parentForm, $parent_form_state); - $sub_values = $subform_state->getValues(); - $this->assertSame($expected, $sub_values); + $subform_state_values = &$subform_state->getValues(); + $this->assertSame($expected, $subform_state_values); + + // Modify the retrieved values and confirm they are modified by reference in + // the parent form state. + $subform_state_values['fish'] = 'Jim'; + $this->assertSame($subform_state_values, $subform_state->getValues()); } /** @@ -134,8 +147,13 @@ public function testGetValue($parents, $key, $expected, $default = NULL) { $subform = NestedArray::getValue($this->parentForm, $parents); $subform_state = SubformState::createForSubform($subform, $this->parentForm, $parent_form_state); - $sub_values = $subform_state->getValue($key, $default); - $this->assertSame($expected, $sub_values); + $subform_state_value = &$subform_state->getValue($key, $default); + $this->assertSame($expected, $subform_state_value); + + // Modify the retrieved values and confirm they are modified by reference in + // the parent form state. + $subform_state_value = 'Jim'; + $this->assertSame($subform_state_value, $subform_state->getValue($key)); } /** @@ -304,4 +322,56 @@ public function testSetErrorByName() { $this->assertSame($subform_state, $subform_state->setErrorByName($subform_error_name, $message)); } + /** + * @covers ::getUserInput + * + * @dataProvider providerGetUserInput + */ + public function testGetUserInput($parent_form_state_user_input, $expected_subform_state_user_input) { + $parent_form_state = new FormState(); + $parent_form_state->setUserInput($parent_form_state_user_input); + $parents = ['dog']; + + $subform = NestedArray::getValue($this->parentForm, $parents); + $subform_state = SubformState::createForSubform($subform, $this->parentForm, $parent_form_state); + $subform_state_user_input = &$subform_state->getUserInput(); + $this->assertSame($expected_subform_state_user_input, $subform_state_user_input); + + // Modify the retrieved user input and confirm it is modified by reference + // in the parent form state. + $subform_state_user_input['fish'] = 'Jim'; + $this->assertSame($subform_state_user_input, $subform_state->getUserInput()); + } + + /** + * Provides data to self::testGetUserInput(). + */ + public function providerGetUserInput() { + $data = []; + + $data['existing-data'] = [$this->formStateUserInput, $this->formStateUserInput['dog']]; + $data['non-existing-data'] = [[], []]; + + return $data; + } + + /** + * @covers ::setUserInput + */ + public function testSetUserInput() { + $parents = ['dog']; + + $subform_state_user_input = NestedArray::getValue($this->formStateUserInput, $parents); + + $parent_form_state = new FormState(); + $parent_form_state_user_input = []; + NestedArray::setValue($parent_form_state_user_input, $parents, $subform_state_user_input); + + $subform = NestedArray::getValue($this->parentForm, $parents); + $subform_state = SubformState::createForSubform($subform, $this->parentForm, $parent_form_state); + $this->assertSame($subform_state, $subform_state->setUserInput($subform_state_user_input)); + + $this->assertSame($parent_form_state_user_input, $parent_form_state->getUserInput()); + } + }