diff --git a/Extension/Core/DataAccessor/PropertyPathAccessor.php b/Extension/Core/DataAccessor/PropertyPathAccessor.php index e639bad2a..24de33a6b 100644 --- a/Extension/Core/DataAccessor/PropertyPathAccessor.php +++ b/Extension/Core/DataAccessor/PropertyPathAccessor.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Form\Extension\Core\DataAccessor; use Symfony\Component\Form\DataAccessorInterface; +use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\AccessException; +use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; @@ -57,15 +59,25 @@ public function setValue(&$data, $propertyValue, FormInterface $form): void throw new AccessException('Unable to write the given value as no property path is defined.'); } + $getValue = function () use ($data, $form, $propertyPath) { + $dataMapper = $this->getDataMapper($form); + + if ($dataMapper instanceof DataMapper && null !== $dataAccessor = $dataMapper->getDataAccessor()) { + return $dataAccessor->getValue($data, $form); + } + + return $this->getPropertyValue($data, $propertyPath); + }; + // If the field is of type DateTimeInterface and the data is the same skip the update to // keep the original object hash - if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->getPropertyValue($data, $propertyPath)) { + if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $getValue()) { return; } // If the data is identical to the value in $data, we are // dealing with a reference - if (!\is_object($data) || !$form->getConfig()->getByReference() || $propertyValue !== $this->getPropertyValue($data, $propertyPath)) { + if (!\is_object($data) || !$form->getConfig()->getByReference() || $propertyValue !== $getValue()) { $this->propertyAccessor->setValue($data, $propertyPath, $propertyValue); } } @@ -105,4 +117,13 @@ private function getPropertyValue($data, PropertyPathInterface $propertyPath) return null; } } + + private function getDataMapper(FormInterface $form): ?DataMapperInterface + { + do { + $dataMapper = $form->getConfig()->getDataMapper(); + } while (null === $dataMapper && null !== $form = $form->getParent()); + + return $dataMapper; + } } diff --git a/Extension/Core/DataMapper/DataMapper.php b/Extension/Core/DataMapper/DataMapper.php index 7995842ee..e480f47ba 100644 --- a/Extension/Core/DataMapper/DataMapper.php +++ b/Extension/Core/DataMapper/DataMapper.php @@ -88,4 +88,12 @@ public function mapFormsToData(iterable $forms, &$data): void } } } + + /** + * @internal + */ + public function getDataAccessor(): DataAccessorInterface + { + return $this->dataAccessor; + } } diff --git a/Tests/Extension/Core/DataMapper/DataMapperTest.php b/Tests/Extension/Core/DataMapper/DataMapperTest.php index c119d665b..c4a271cd0 100644 --- a/Tests/Extension/Core/DataMapper/DataMapperTest.php +++ b/Tests/Extension/Core/DataMapper/DataMapperTest.php @@ -17,6 +17,8 @@ use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormFactoryBuilder; @@ -419,6 +421,25 @@ public function testMapFormsToDataMapsDateTimeInstanceToArrayIfNotSetBefore() $this->assertEquals(['date' => new \DateTime('2022-08-04', new \DateTimeZone('UTC'))], $form->getData()); } + + public function testMapFormToDataWithOnlyGetterConfigured() + { + $person = new DummyPerson('foo'); + $form = (new FormFactoryBuilder()) + ->getFormFactory() + ->createBuilder(FormType::class, $person) + ->add('name', TextType::class, [ + 'getter' => function (DummyPerson $person) { + return $person->myName(); + }, + ]) + ->getForm(); + $form->submit([ + 'name' => 'bar', + ]); + + $this->assertSame('bar', $person->myName()); + } } class SubmittedForm extends Form @@ -455,4 +476,9 @@ public function rename($name): void { $this->name = $name; } + + public function setName($name): void + { + $this->name = $name; + } }