diff --git a/core/lib/Drupal/Core/Form/FormState.php b/core/lib/Drupal/Core/Form/FormState.php index 79a3abb..c37269a 100644 --- a/core/lib/Drupal/Core/Form/FormState.php +++ b/core/lib/Drupal/Core/Form/FormState.php @@ -1212,8 +1212,8 @@ protected function moduleLoadInclude($module, $type, $name = NULL) { /** * {@inheritdoc} */ - public function getFormStateForElement(array $element) { - return SubFormState::createForFormElement($this, $element); + public function getFormStateForSubform(array $element) { + return SubFormState::createForSubform($element, $this); } } diff --git a/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php b/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php index 9361b87..4111b46 100644 --- a/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php +++ b/core/lib/Drupal/Core/Form/FormStateDecoratorBase.php @@ -23,16 +23,6 @@ protected $decoratedFormState; /** - * Constructs a new instance. - * - * @param \Drupal\Core\Form\FormStateInterface $decorated_form_state - * The decorated form state. - */ - public function __construct(FormStateInterface $decorated_form_state) { - $this->decoratedFormState = $decorated_form_state; - } - - /** * {@inheritdoc} */ public function setFormState(array $form_state_additions) { diff --git a/core/lib/Drupal/Core/Form/FormStateInterface.php b/core/lib/Drupal/Core/Form/FormStateInterface.php index 761e4d2..a396440 100644 --- a/core/lib/Drupal/Core/Form/FormStateInterface.php +++ b/core/lib/Drupal/Core/Form/FormStateInterface.php @@ -1099,13 +1099,13 @@ public function addCleanValueKey($key); public function cleanValues(); /** - * Gets the form state for a form element. + * Gets the form state for a subform. * - * @param mixed[] $element - * The form element for which to get the form state. + * @param mixed[] $subform + * The subform for which to get the form state. * * @return \Drupal\Core\Form\FormStateInterface */ - public function getFormStateForElement(array $element); + public function getFormStateForSubform(array $subform); } diff --git a/core/lib/Drupal/Core/Form/SubFormState.php b/core/lib/Drupal/Core/Form/SubFormState.php index dbdb7b9..746dfc7 100644 --- a/core/lib/Drupal/Core/Form/SubFormState.php +++ b/core/lib/Drupal/Core/Form/SubFormState.php @@ -18,63 +18,76 @@ class SubFormState extends FormStateDecoratorBase { use FormStateValuesTrait; /** - * The root #array_parents value of the subform. + * The subform. * - * @var string[] + * @var mixed[] */ - protected $arrayParents = []; - - /** - * The root #parents value of the subform. - * - * @var string[] - */ - protected $parents = []; + protected $subform = []; /** * Constructs a new instance. * + * @param mixed[] $subform + * The subform for which to create a form state. * @param \Drupal\Core\Form\FormStateInterface $parent_form_state * The parent form state. - * @param string[] $array_parents - * The root #array_parents value of the subset of the form. - * @param string[] $parents - * The root #parents value of the subset of the form. */ - public function __construct(FormStateInterface $parent_form_state, array $array_parents, array $parents) { - parent::__construct($parent_form_state); - $this->arrayParents = $array_parents; - $this->parents = $parents; + protected function __construct(array &$subform, FormStateInterface $parent_form_state) { + $this->decoratedFormState = $parent_form_state; + $this->subform = $subform; } /** - * Creates a new instance based on a form element. + * Creates a new instance for a subform. * + * @param mixed[] $subform + * The subform for which to create a form state. * @param \Drupal\Core\Form\FormStateInterface $parent_form_state * The parent form state. - * @param mixed[] $element - * The element to create the sub form state for. * * @return static + */ + public static function createForSubform(array &$subform, FormStateInterface $parent_form_state) { + return new static($subform, $parent_form_state); + } + + /** + * Gets a subform property value. + * + * @param string $property + * The property name. + * + * @return mixed * * @throws \InvalidArgumentException - * Thrown when the form element does not wrap other form elements, or if it - * does not have the necessary Form API properties assigned. + * Thrown when the requested property does not exist. */ - public static function createForFormElement(FormStateInterface $parent_form_state, array $element) { - // Make sure the element contains the required properties. - $children = Element::children($element); - if (empty($children)) { - throw new \InvalidArgumentException('nope'); - } - $required_keys = ['#array_parents', '#parents']; - foreach ($required_keys as $required_key) { - if (!array_key_exists($required_key, $element) || !is_array($element[$required_key])) { - throw new \InvalidArgumentException(sprintf('$element must contain the %s key. Try calling this method from a #process callback instead.', $required_key)); - } + protected function getSubFormProperty($property) { + if (!array_key_exists($property, $this->subform)) { + throw new \InvalidArgumentException(sprintf('The subform must contain the %s property. Try calling this method from a #process callback instead.', $property)); } - return new static($parent_form_state, $element['#parents'], $element['#array_parents']); + return $this->subform[$property]; + } + + /** + * Gets the subform's parents. + * + * @return string[] + * The parent keys (#array_parents). + */ + protected function getSubFormParents() { + return $this->getSubFormProperty('#array_parents'); + } + + /** + * Gets the subform state's parents. + * + * @return string[] + * The parent keys (#parents). + */ + protected function getSubFormStateParents() { + return $this->getSubFormProperty('#parents'); } /** @@ -82,12 +95,12 @@ public static function createForFormElement(FormStateInterface $parent_form_stat */ public function &getValues() { $exists = NULL; - $values = &NestedArray::getValue(parent::getValues(), $this->parents, $exists); + $values = &NestedArray::getValue(parent::getValues(), $this->getSubFormStateParents(), $exists); if (!$exists) { $values = []; } elseif (!is_array($values)) { - throw new \UnexpectedValueException('Drilled down too far! This violates the interface.'); + throw new \UnexpectedValueException('The form state values do not belong to the subform.'); } @@ -97,8 +110,8 @@ public function &getValues() { /** * {@inheritdoc} */ - public function getFormStateForElement(array $element) { - return static::createForFormElement($this, $element); + public function getFormStateForSubform(array $element) { + return static::createForSubform($element, $this); } } diff --git a/core/modules/block/src/BlockForm.php b/core/modules/block/src/BlockForm.php index 2720a7f..0c3287f 100644 --- a/core/modules/block/src/BlockForm.php +++ b/core/modules/block/src/BlockForm.php @@ -125,7 +125,9 @@ public function form(array $form, FormStateInterface $form_state) { $form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts()); $form['#tree'] = TRUE; - $form['settings'] = $entity->getPlugin()->buildConfigurationForm(array(), $form_state); + $form['settings'] = []; + $subform_state = $form_state->getFormStateForSubform($form['settings']); + $form['settings'] = $entity->getPlugin()->buildConfigurationForm($form['settings'], $subform_state); $form['visibility'] = $this->buildVisibilityInterface([], $form_state); // If creating a new block, calculate a safe default machine name. @@ -285,7 +287,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) { // The Block Entity form puts all block plugin form elements in the // settings form element, so just pass that to the block for validation. - $this->entity->getPlugin()->validateConfigurationForm($form, $form_state->getFormStateForElement($form['settings'])); + $this->entity->getPlugin()->validateConfigurationForm($form['settings'], $form_state->getFormStateForSubform($form['settings'])); $this->validateVisibility($form, $form_state); } @@ -309,7 +311,7 @@ protected function validateVisibility(array $form, FormStateInterface $form_stat // Allow the condition to validate the form. $condition = $form_state->get(['conditions', $condition_id]); - $condition->validateConfigurationForm($form, $form_state->getFormStateForElement($form['visibility'][$condition_id])); + $condition->validateConfigurationForm($form['visibility'][$condition_id], $form_state->getFormStateForSubform($form['visibility'][$condition_id])); } } @@ -322,13 +324,13 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $entity = $this->entity; // The Block Entity form puts all block plugin form elements in the // settings form element, so just pass that to the block for submission. - $entity->getPlugin()->submitConfigurationForm($form, $form_state->getFormStateForElement($form['settings'])); + $entity->getPlugin()->submitConfigurationForm($form['settings'], $form_state->getFormStateForSubform($form['settings'])); // Submit visibility condition settings. foreach ($form_state->getValue('visibility') as $condition_id => $values) { // Allow the condition to submit the form. $condition = $form_state->get(['conditions', $condition_id]); - $condition->submitConfigurationForm($form, $form_state->getFormStateForElement($form['visibility'][$condition_id])); + $condition->submitConfigurationForm($form['visibility'][$condition_id], $form_state->getFormStateForSubform($form['visibility'][$condition_id])); if ($condition instanceof ContextAwarePluginInterface) { $context_mapping = isset($values['context_mapping']) ? $values['context_mapping'] : []; diff --git a/core/modules/image/src/Form/ImageEffectFormBase.php b/core/modules/image/src/Form/ImageEffectFormBase.php index bc12fb0..538d54f 100644 --- a/core/modules/image/src/Form/ImageEffectFormBase.php +++ b/core/modules/image/src/Form/ImageEffectFormBase.php @@ -79,7 +79,9 @@ public function buildForm(array $form, FormStateInterface $form_state, ImageStyl '#value' => $this->imageEffect->getPluginId(), ); - $form['data'] = $this->imageEffect->buildConfigurationForm(array(), $form_state); + $form['data'] = []; + $subform_state = $form_state->getFormStateForSubform($form['data']); + $form['data'] = $this->imageEffect->buildConfigurationForm($form['data'], $subform_state); $form['data']['#tree'] = TRUE; // Check the URL for a weight, then the image effect, otherwise use default. @@ -108,7 +110,7 @@ public function buildForm(array $form, FormStateInterface $form_state, ImageStyl public function validateForm(array &$form, FormStateInterface $form_state) { // The image effect configuration is stored in the 'data' key in the form, // pass that through for validation. - $this->imageEffect->validateConfigurationForm($form, $form_state->getFormStateForElement($form['data'])); + $this->imageEffect->validateConfigurationForm($form, $form_state->getFormStateForSubform($form['data'])); } /** @@ -119,7 +121,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // The image effect configuration is stored in the 'data' key in the form, // pass that through for submission. - $this->imageEffect->submitConfigurationForm($form, $form_state->getFormStateForElement($form['data'])); + $this->imageEffect->submitConfigurationForm($form, $form_state->getFormStateForSubform($form['data'])); $this->imageEffect->setWeight($form_state->getValue('weight')); if (!$this->imageEffect->getUuid()) { diff --git a/core/tests/Drupal/Tests/Core/Form/FormStateTest.php b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php index 4fca585..6cd0ded 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormStateTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormStateTest.php @@ -430,7 +430,7 @@ public function testGetFormStateForElement() { 'bar' => [], ]; - $sub_form_state = $form_state->getFormStateForElement($element); + $sub_form_state = $form_state->getFormStateForSubform($element); $this->assertNotSame($form_state, $sub_form_state); $this->assertInstanceOf(FormStateInterface::class, $sub_form_state); } diff --git a/core/tests/Drupal/Tests/Core/Form/SubFormStateTest.php b/core/tests/Drupal/Tests/Core/Form/SubFormStateTest.php index 55c060a..429a530 100644 --- a/core/tests/Drupal/Tests/Core/Form/SubFormStateTest.php +++ b/core/tests/Drupal/Tests/Core/Form/SubFormStateTest.php @@ -61,7 +61,7 @@ public function testCreateForFormElement() { 'bar' => [], ]; - $sub_form_state = $form_state->getFormStateForElement($element); + $sub_form_state = $form_state->getFormStateForSubform($element); $this->assertNotSame($form_state, $sub_form_state); $this->assertInstanceOf(FormStateInterface::class, $sub_form_state); } @@ -78,7 +78,7 @@ public function testCreateForFormElementMissingArrayParents() { 'bar' => [], ]; - $form_state->getFormStateForElement($element); + $form_state->getFormStateForSubform($element); } /** @@ -94,7 +94,7 @@ public function testCreateForFormElementMissingParents() { 'bar' => [], ]; - $form_state->getFormStateForElement($element); + $form_state->getFormStateForSubform($element); } /** @@ -107,7 +107,7 @@ public function testGetValues($parents, $expected) { $form_state->setValues($this->initialValues); $element = NestedArray::getValue($this->element, $parents); - $sub_form_state = $form_state->getFormStateForElement($element); + $sub_form_state = $form_state->getFormStateForSubform($element); $sub_values = $sub_form_state->getValues(); $this->assertSame($expected, $sub_values); } @@ -155,7 +155,7 @@ public function testGetValue($parents, $key, $expected, $default = NULL) { $form_state->setValues($this->initialValues); $element = NestedArray::getValue($this->element, $parents); - $sub_form_state = $form_state->getFormStateForElement($element); + $sub_form_state = $form_state->getFormStateForSubform($element); $sub_values = $sub_form_state->getValue($key, $default); $this->assertSame($expected, $sub_values); } @@ -201,7 +201,7 @@ public function testSetValues($parents, $new_values, $expected) { $form_state->setValues($this->initialValues); $element = NestedArray::getValue($this->element, $parents); - $sub_form_state = $form_state->getFormStateForElement($element); + $sub_form_state = $form_state->getFormStateForSubform($element); $sub_form_state->setValues($new_values); $this->assertSame($expected, $form_state->getValues()); }