Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a0ceb81

Browse filesBrowse files
ph-fritschexabbuh
authored andcommitted
silently ignore uninitialized properties when mapping data to forms
1 parent 13982b5 commit a0ceb81
Copy full SHA for a0ceb81

File tree

3 files changed

+74
-5
lines changed
Filter options

3 files changed

+74
-5
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php
+21-3Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
use Symfony\Component\Form\DataMapperInterface;
1515
use Symfony\Component\Form\Exception\UnexpectedTypeException;
16+
use Symfony\Component\PropertyAccess\Exception\AccessException;
17+
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
1618
use Symfony\Component\PropertyAccess\PropertyAccess;
1719
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
1820

@@ -46,7 +48,7 @@ public function mapDataToForms($data, $forms)
4648
$config = $form->getConfig();
4749

4850
if (!$empty && null !== $propertyPath && $config->getMapped()) {
49-
$form->setData($this->propertyAccessor->getValue($data, $propertyPath));
51+
$form->setData($this->getPropertyValue($data, $propertyPath));
5052
} else {
5153
$form->setData($config->getData());
5254
}
@@ -76,16 +78,32 @@ public function mapFormsToData($forms, &$data)
7678
$propertyValue = $form->getData();
7779
// If the field is of type DateTimeInterface and the data is the same skip the update to
7880
// keep the original object hash
79-
if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->propertyAccessor->getValue($data, $propertyPath)) {
81+
if ($propertyValue instanceof \DateTimeInterface && $propertyValue == $this->getPropertyValue($data, $propertyPath)) {
8082
continue;
8183
}
8284

8385
// If the data is identical to the value in $data, we are
8486
// dealing with a reference
85-
if (!\is_object($data) || !$config->getByReference() || $propertyValue !== $this->propertyAccessor->getValue($data, $propertyPath)) {
87+
if (!\is_object($data) || !$config->getByReference() || $propertyValue !== $this->getPropertyValue($data, $propertyPath)) {
8688
$this->propertyAccessor->setValue($data, $propertyPath, $propertyValue);
8789
}
8890
}
8991
}
9092
}
93+
94+
private function getPropertyValue($data, $propertyPath)
95+
{
96+
try {
97+
return $this->propertyAccessor->getValue($data, $propertyPath);
98+
} catch (AccessException $e) {
99+
if (!$e instanceof UninitializedPropertyException
100+
// For versions without UninitializedPropertyException check the exception message
101+
&& (class_exists(UninitializedPropertyException::class) || false === strpos($e->getMessage(), 'You should initialize it'))
102+
) {
103+
throw $e;
104+
}
105+
106+
return null;
107+
}
108+
}
91109
}

‎src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php
+35-2Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
1818
use Symfony\Component\Form\Form;
1919
use Symfony\Component\Form\FormConfigBuilder;
20+
use Symfony\Component\Form\Tests\Fixtures\TypehintedPropertiesCar;
2021
use Symfony\Component\PropertyAccess\PropertyAccess;
2122
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2223
use Symfony\Component\PropertyAccess\PropertyPath;
@@ -113,6 +114,23 @@ public function testMapDataToFormsIgnoresUnmapped()
113114
$this->assertNull($form->getData());
114115
}
115116

117+
/**
118+
* @requires PHP 7.4
119+
*/
120+
public function testMapDataToFormsIgnoresUninitializedProperties()
121+
{
122+
$engineForm = new Form(new FormConfigBuilder('engine', null, $this->dispatcher));
123+
$colorForm = new Form(new FormConfigBuilder('color', null, $this->dispatcher));
124+
125+
$car = new TypehintedPropertiesCar();
126+
$car->engine = 'BMW';
127+
128+
$this->mapper->mapDataToForms($car, [$engineForm, $colorForm]);
129+
130+
$this->assertSame($car->engine, $engineForm->getData());
131+
$this->assertNull($colorForm->getData());
132+
}
133+
116134
public function testMapDataToFormsSetsDefaultDataIfPassedDataIsNull()
117135
{
118136
$default = new \stdClass();
@@ -293,13 +311,28 @@ public function testMapFormsToDataIgnoresDisabled()
293311
$config->setPropertyPath($propertyPath);
294312
$config->setData($engine);
295313
$config->setDisabled(true);
296-
$form = new Form($config);
314+
$form = new SubmittedForm($config);
297315

298316
$this->mapper->mapFormsToData([$form], $car);
299317

300318
$this->assertSame($initialEngine, $car->engine);
301319
}
302320

321+
/**
322+
* @requires PHP 7.4
323+
*/
324+
public function testMapFormsToUninitializedProperties()
325+
{
326+
$car = new TypehintedPropertiesCar();
327+
$config = new FormConfigBuilder('engine', null, $this->dispatcher);
328+
$config->setData('BMW');
329+
$form = new SubmittedForm($config);
330+
331+
$this->mapper->mapFormsToData([$form], $car);
332+
333+
$this->assertSame('BMW', $car->engine);
334+
}
335+
303336
/**
304337
* @dataProvider provideDate
305338
*/
@@ -339,7 +372,7 @@ public function isSubmitted()
339372
}
340373
}
341374

342-
class NotSynchronizedForm extends Form
375+
class NotSynchronizedForm extends SubmittedForm
343376
{
344377
public function isSynchronized()
345378
{
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests\Fixtures;
13+
14+
class TypehintedPropertiesCar
15+
{
16+
public ?string $engine;
17+
public ?string $color;
18+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.