Skip to content

Commit b5e67f7

Browse files
committed
bug symfony#54723 [Form] read form values using the chain data accessor (xabbuh)
This PR was merged into the 5.4 branch. Discussion ---------- [Form] read form values using the chain data accessor | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix symfony#48167 | License | MIT Commits ------- e0d97f8 read form values using the chain data accessor
2 parents bdf3cc4 + e0d97f8 commit b5e67f7

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

src/Symfony/Component/Form/Extension/Core/DataAccessor/PropertyPathAccessor.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
namespace Symfony\Component\Form\Extension\Core\DataAccessor;
1313

1414
use Symfony\Component\Form\DataAccessorInterface;
15+
use Symfony\Component\Form\DataMapperInterface;
1516
use Symfony\Component\Form\Exception\AccessException;
17+
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
1618
use Symfony\Component\Form\FormInterface;
1719
use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException;
1820
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
@@ -57,15 +59,25 @@ public function setValue(&$data, $propertyValue, FormInterface $form): void
5759
throw new AccessException('Unable to write the given value as no property path is defined.');
5860
}
5961

62+
$getValue = function () use ($data, $form, $propertyPath) {
63+
$dataMapper = $this->getDataMapper($form);
64+
65+
if ($dataMapper instanceof DataMapper && null !== $dataAccessor = $dataMapper->getDataAccessor()) {
66+
return $dataAccessor->getValue($data, $form);
67+
}
68+
69+
return $this->getPropertyValue($data, $propertyPath);
70+
};
71+
6072
// If the field is of type DateTimeInterface and the data is the same skip the update to
6173
// keep the original object hash
62-
if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->getPropertyValue($data, $propertyPath)) {
74+
if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $getValue()) {
6375
return;
6476
}
6577

6678
// If the data is identical to the value in $data, we are
6779
// dealing with a reference
68-
if (!\is_object($data) || !$form->getConfig()->getByReference() || $propertyValue !== $this->getPropertyValue($data, $propertyPath)) {
80+
if (!\is_object($data) || !$form->getConfig()->getByReference() || $propertyValue !== $getValue()) {
6981
$this->propertyAccessor->setValue($data, $propertyPath, $propertyValue);
7082
}
7183
}
@@ -105,4 +117,13 @@ private function getPropertyValue($data, PropertyPathInterface $propertyPath)
105117
return null;
106118
}
107119
}
120+
121+
private function getDataMapper(FormInterface $form): ?DataMapperInterface
122+
{
123+
do {
124+
$dataMapper = $form->getConfig()->getDataMapper();
125+
} while (null === $dataMapper && null !== $form = $form->getParent());
126+
127+
return $dataMapper;
128+
}
108129
}

src/Symfony/Component/Form/Extension/Core/DataMapper/DataMapper.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,12 @@ public function mapFormsToData(iterable $forms, &$data): void
8888
}
8989
}
9090
}
91+
92+
/**
93+
* @internal
94+
*/
95+
public function getDataAccessor(): DataAccessorInterface
96+
{
97+
return $this->dataAccessor;
98+
}
9199
}

src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/DataMapperTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
1818
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
1919
use Symfony\Component\Form\Extension\Core\Type\DateType;
20+
use Symfony\Component\Form\Extension\Core\Type\FormType;
21+
use Symfony\Component\Form\Extension\Core\Type\TextType;
2022
use Symfony\Component\Form\Form;
2123
use Symfony\Component\Form\FormConfigBuilder;
2224
use Symfony\Component\Form\FormFactoryBuilder;
@@ -419,6 +421,25 @@ public function testMapFormsToDataMapsDateTimeInstanceToArrayIfNotSetBefore()
419421

420422
$this->assertEquals(['date' => new \DateTime('2022-08-04', new \DateTimeZone('UTC'))], $form->getData());
421423
}
424+
425+
public function testMapFormToDataWithOnlyGetterConfigured()
426+
{
427+
$person = new DummyPerson('foo');
428+
$form = (new FormFactoryBuilder())
429+
->getFormFactory()
430+
->createBuilder(FormType::class, $person)
431+
->add('name', TextType::class, [
432+
'getter' => function (DummyPerson $person) {
433+
return $person->myName();
434+
},
435+
])
436+
->getForm();
437+
$form->submit([
438+
'name' => 'bar',
439+
]);
440+
441+
$this->assertSame('bar', $person->myName());
442+
}
422443
}
423444

424445
class SubmittedForm extends Form
@@ -455,4 +476,9 @@ public function rename($name): void
455476
{
456477
$this->name = $name;
457478
}
479+
480+
public function setName($name): void
481+
{
482+
$this->name = $name;
483+
}
458484
}

0 commit comments

Comments
 (0)