From f1de4134d1447d01eecfbaf43e4a69a258ffa25a Mon Sep 17 00:00:00 2001 From: catch Date: Thu, 15 Sep 2022 10:29:08 +0100 Subject: [PATCH] Issue #3298731 by alexpott, andypost, catch, longwave, Berdir, bbrala, Wim Leers: Using ConstraintViolation::$arrayPropertyPath bugs on PHP 8.2 (cherry picked from commit a8f48db6635b58d097d632342efc2f0d5f3197cf) --- .../Drupal/Core/Field/InternalViolation.php | 133 ++++++++++++++++++ core/lib/Drupal/Core/Field/WidgetBase.php | 3 +- .../Field/FieldWidget/TextareaWidget.php | 2 +- .../FieldWidget/TextareaWithSummaryWidget.php | 3 +- .../Field/FieldWidget/TextfieldWidget.php | 2 +- .../Core/Field/InternalViolationTest.php | 38 +++++ 6 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 core/lib/Drupal/Core/Field/InternalViolation.php create mode 100644 core/tests/Drupal/Tests/Core/Field/InternalViolationTest.php diff --git a/core/lib/Drupal/Core/Field/InternalViolation.php b/core/lib/Drupal/Core/Field/InternalViolation.php new file mode 100644 index 00000000000..73a1950a94e --- /dev/null +++ b/core/lib/Drupal/Core/Field/InternalViolation.php @@ -0,0 +1,133 @@ +violation = $violation; + } + + /** + * {@inheritdoc} + */ + public function __get(string $name) { + if ($name === 'arrayPropertyPath') { + @trigger_error('Accessing the arrayPropertyPath property is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. Use \Symfony\Component\Validator\ConstraintViolationInterface::getPropertyPath() instead. See https://www.drupal.org/node/3307919', E_USER_DEPRECATED); + return $this->arrayPropertyPath; + } + @trigger_error('Accessing dynamic properties on violations is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3307919', E_USER_DEPRECATED); + return $this->properties[$name] ?? NULL; + } + + /** + * {@inheritdoc} + */ + public function __set(string $name, $value): void { + if ($name === 'arrayPropertyPath') { + $this->arrayPropertyPath = $value; + return; + } + @trigger_error('Setting dynamic properties on violations is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3307919', E_USER_DEPRECATED); + $this->properties[$name] = $value; + } + + /** + * {@inheritdoc} + */ + public function __toString(): string { + return (string) $this->violation; + } + + /** + * {@inheritdoc} + */ + public function getMessage(): string|\Stringable { + return $this->violation->getMessage(); + } + + /** + * {@inheritdoc} + */ + public function getMessageTemplate(): string { + return $this->violation->getMessageTemplate(); + } + + /** + * {@inheritdoc} + */ + public function getParameters(): array { + return $this->violation->getParameters(); + } + + /** + * {@inheritdoc} + */ + public function getPlural(): ?int { + return $this->violation->getPlural(); + } + + /** + * {@inheritdoc} + */ + public function getRoot(): mixed { + return $this->violation->getRoot(); + } + + /** + * {@inheritdoc} + */ + public function getPropertyPath(): string { + return $this->violation->getPropertyPath(); + } + + /** + * {@inheritdoc} + */ + public function getInvalidValue(): mixed { + return $this->violation->getInvalidValue(); + } + + /** + * {@inheritdoc} + */ + public function getCode(): ?string { + return $this->violation->getCode(); + } + +} diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php index a5549e67013..e1da2b90528 100644 --- a/core/lib/Drupal/Core/Field/WidgetBase.php +++ b/core/lib/Drupal/Core/Field/WidgetBase.php @@ -444,6 +444,7 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface, $violations_by_delta = $item_list_violations = []; foreach ($violations as $violation) { + $violation = new InternalViolation($violation); // Separate violations by delta. $property_path = explode('.', $violation->getPropertyPath()); $delta = array_shift($property_path); @@ -454,6 +455,7 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface, else { $item_list_violations[] = $violation; } + // @todo Remove BC layer https://www.drupal.org/i/3307859 on PHP 8.2. $violation->arrayPropertyPath = $property_path; } @@ -470,7 +472,6 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface, $delta_element = $element[$original_delta]; } foreach ($delta_violations as $violation) { - // @todo: Pass $violation->arrayPropertyPath as property path. $error_element = $this->errorElement($delta_element, $violation, $form, $form_state); if ($error_element !== FALSE) { $form_state->setError($error_element, $violation->getMessage()); diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php index 11e84f1c3ef..fc02ac1e9c3 100644 --- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php +++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php @@ -46,7 +46,7 @@ class TextareaWidget extends StringTextareaWidget { * {@inheritdoc} */ public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) { - if ($violation->arrayPropertyPath == ['format'] && isset($element['format']['#access']) && !$element['format']['#access']) { + if (isset($element['format']['#access']) && !$element['format']['#access'] && preg_match('/^[0-9]*\.format$/', $violation->getPropertyPath())) { // Ignore validation errors for formats if formats may not be changed, // such as when existing formats become invalid. // See \Drupal\filter\Element\TextFormat::processFormat(). diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php index 1dcb00b96b5..999bfc46239 100644 --- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php +++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php @@ -100,7 +100,8 @@ class TextareaWithSummaryWidget extends TextareaWidget { */ public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) { $element = parent::errorElement($element, $violation, $form, $form_state); - return ($element === FALSE) ? FALSE : $element[$violation->arrayPropertyPath[0]]; + $property_path_array = explode('.', $violation->getPropertyPath()); + return ($element === FALSE) ? FALSE : $element[$property_path_array[1]]; } } diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php index e6954cc1df0..29934378f01 100644 --- a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php +++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php @@ -37,7 +37,7 @@ class TextfieldWidget extends StringTextfieldWidget { * {@inheritdoc} */ public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) { - if ($violation->arrayPropertyPath == ['format'] && isset($element['format']['#access']) && !$element['format']['#access']) { + if (isset($element['format']['#access']) && !$element['format']['#access'] && preg_match('/^[0-9]*\.format$/', $violation->getPropertyPath())) { // Ignore validation errors for formats that may not be changed, // such as when existing formats become invalid. // See \Drupal\filter\Element\TextFormat::processFormat(). diff --git a/core/tests/Drupal/Tests/Core/Field/InternalViolationTest.php b/core/tests/Drupal/Tests/Core/Field/InternalViolationTest.php new file mode 100644 index 00000000000..391eb2f658f --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Field/InternalViolationTest.php @@ -0,0 +1,38 @@ +prophesize(ConstraintViolationInterface::class)->reveal()); + $this->expectDeprecation('Setting dynamic properties on violations is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3307919'); + $this->expectDeprecation('Accessing dynamic properties on violations is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3307919'); + $violation->foo = 'bar'; + $this->assertSame('bar', $violation->foo); + } + + /** + * @covers ::__get + * @covers ::__set + */ + public function testSetGetArrayPropertyPath() { + $violation = new InternalViolation($this->prophesize(ConstraintViolationInterface::class)->reveal()); + $this->expectDeprecation('Accessing the arrayPropertyPath property is deprecated in drupal:9.5.0 and is removed from drupal:11.0.0. Use \Symfony\Component\Validator\ConstraintViolationInterface::getPropertyPath() instead. See https://www.drupal.org/node/3307919'); + $violation->arrayPropertyPath = ['bar']; + $this->assertSame(['bar'], $violation->arrayPropertyPath); + } + +}