add new way of mapping data using callback functions

This commit is contained in:
Yonel Ceruto 2020-08-27 06:09:23 -04:00
parent 845c232dd5
commit 878effaf47
25 changed files with 947 additions and 59 deletions

View File

@ -16,6 +16,28 @@ FrameworkBundle
used to be added by default to the seed, which is not the case anymore. This allows sharing caches between used to be added by default to the seed, which is not the case anymore. This allows sharing caches between
apps or different environments. apps or different environments.
Form
----
* Deprecated `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor`.
Before:
```php
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
$builder->setDataMapper(new PropertyPathMapper());
```
After:
```php
use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
$builder->setDataMapper(new DataMapper(new PropertyPathAccessor()));
```
Lock Lock
---- ----

View File

@ -48,6 +48,7 @@ Form
* Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()`. * Added argument `callable|null $filter` to `ChoiceListFactoryInterface::createListFromChoices()` and `createListFromLoader()`.
* The `Symfony\Component\Form\Extension\Validator\Util\ServerParams` class has been removed, use its parent `Symfony\Component\Form\Util\ServerParams` instead. * The `Symfony\Component\Form\Extension\Validator\Util\ServerParams` class has been removed, use its parent `Symfony\Component\Form\Util\ServerParams` instead.
* The `NumberToLocalizedStringTransformer::ROUND_*` constants have been removed, use `\NumberFormatter::ROUND_*` instead. * The `NumberToLocalizedStringTransformer::ROUND_*` constants have been removed, use `\NumberFormatter::ROUND_*` instead.
* Removed `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor`.
FrameworkBundle FrameworkBundle
--------------- ---------------

View File

@ -5,6 +5,8 @@ CHANGELOG
----- -----
* Added support for using the `{{ label }}` placeholder in constraint messages, which is replaced in the `ViolationMapper` by the corresponding field form label. * Added support for using the `{{ label }}` placeholder in constraint messages, which is replaced in the `ViolationMapper` by the corresponding field form label.
* Added `DataMapper`, `ChainAccessor`, `PropertyPathAccessor` and `CallbackAccessor` with new callable `getter` and `setter` options for each form type
* Deprecated `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor`
5.1.0 5.1.0
----- -----

View File

@ -0,0 +1,69 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* Writes and reads values to/from an object or array bound to a form.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
interface DataAccessorInterface
{
/**
* Returns the value at the end of the property of the object graph.
*
* @param object|array $viewData The view data of the compound form
* @param FormInterface $form The {@link FormInterface()} instance to check
*
* @return mixed The value at the end of the property
*
* @throws Exception\AccessException If unable to read from the given form data
*/
public function getValue($viewData, FormInterface $form);
/**
* Sets the value at the end of the property of the object graph.
*
* @param object|array $viewData The view data of the compound form
* @param mixed $value The value to set at the end of the object graph
* @param FormInterface $form The {@link FormInterface()} instance to check
*
* @throws Exception\AccessException If unable to write the given value
*/
public function setValue(&$viewData, $value, FormInterface $form): void;
/**
* Returns whether a value can be read from an object graph.
*
* Whenever this method returns true, {@link getValue()} is guaranteed not
* to throw an exception when called with the same arguments.
*
* @param object|array $viewData The view data of the compound form
* @param FormInterface $form The {@link FormInterface()} instance to check
*
* @return bool Whether the value can be read
*/
public function isReadable($viewData, FormInterface $form): bool;
/**
* Returns whether a value can be written at a given object graph.
*
* Whenever this method returns true, {@link setValue()} is guaranteed not
* to throw an exception when called with the same arguments.
*
* @param object|array $viewData The view data of the compound form
* @param FormInterface $form The {@link FormInterface()} instance to check
*
* @return bool Whether the value can be set
*/
public function isWritable($viewData, FormInterface $form): bool;
}

View File

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
class AccessException extends RuntimeException
{
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Extension\Core\DataAccessor;
use Symfony\Component\Form\DataAccessorInterface;
use Symfony\Component\Form\Exception\AccessException;
use Symfony\Component\Form\FormInterface;
/**
* Writes and reads values to/from an object or array using callback functions.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class CallbackAccessor implements DataAccessorInterface
{
/**
* {@inheritdoc}
*/
public function getValue($data, FormInterface $form)
{
if (null === $getter = $form->getConfig()->getOption('getter')) {
throw new AccessException('Unable to read from the given form data as no getter is defined.');
}
return ($getter)($data, $form);
}
/**
* {@inheritdoc}
*/
public function setValue(&$data, $value, FormInterface $form): void
{
if (null === $setter = $form->getConfig()->getOption('setter')) {
throw new AccessException('Unable to write the given value as no setter is defined.');
}
($setter)($data, $form->getData(), $form);
}
/**
* {@inheritdoc}
*/
public function isReadable($data, FormInterface $form): bool
{
return null !== $form->getConfig()->getOption('getter');
}
/**
* {@inheritdoc}
*/
public function isWritable($data, FormInterface $form): bool
{
return null !== $form->getConfig()->getOption('setter');
}
}

View File

@ -0,0 +1,90 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Extension\Core\DataAccessor;
use Symfony\Component\Form\DataAccessorInterface;
use Symfony\Component\Form\Exception\AccessException;
use Symfony\Component\Form\FormInterface;
/**
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
class ChainAccessor implements DataAccessorInterface
{
private $accessors;
/**
* @param DataAccessorInterface[]|iterable $accessors
*/
public function __construct(iterable $accessors)
{
$this->accessors = $accessors;
}
/**
* {@inheritdoc}
*/
public function getValue($data, FormInterface $form)
{
foreach ($this->accessors as $accessor) {
if ($accessor->isReadable($data, $form)) {
return $accessor->getValue($data, $form);
}
}
throw new AccessException('Unable to read from the given form data as no accessor in the chain is able to read the data.');
}
/**
* {@inheritdoc}
*/
public function setValue(&$data, $value, FormInterface $form): void
{
foreach ($this->accessors as $accessor) {
if ($accessor->isWritable($data, $form)) {
$accessor->setValue($data, $value, $form);
return;
}
}
throw new AccessException('Unable to write the given value as no accessor in the chain is able to set the data.');
}
/**
* {@inheritdoc}
*/
public function isReadable($data, FormInterface $form): bool
{
foreach ($this->accessors as $accessor) {
if ($accessor->isReadable($data, $form)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function isWritable($data, FormInterface $form): bool
{
foreach ($this->accessors as $accessor) {
if ($accessor->isWritable($data, $form)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Extension\Core\DataAccessor;
use Symfony\Component\Form\DataAccessorInterface;
use Symfony\Component\Form\Exception\AccessException;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException;
use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* Writes and reads values to/from an object or array using property path.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class PropertyPathAccessor implements DataAccessorInterface
{
private $propertyAccessor;
public function __construct(PropertyAccessorInterface $propertyAccessor = null)
{
$this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
}
/**
* {@inheritdoc}
*/
public function getValue($data, FormInterface $form)
{
if (null === $propertyPath = $form->getPropertyPath()) {
throw new AccessException('Unable to read from the given form data as no property path is defined.');
}
return $this->getPropertyValue($data, $propertyPath);
}
/**
* {@inheritdoc}
*/
public function setValue(&$data, $propertyValue, FormInterface $form): void
{
if (null === $propertyPath = $form->getPropertyPath()) {
throw new AccessException('Unable to write the given value as no property path is defined.');
}
// 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)) {
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)) {
$this->propertyAccessor->setValue($data, $propertyPath, $propertyValue);
}
}
/**
* {@inheritdoc}
*/
public function isReadable($data, FormInterface $form): bool
{
return null !== $form->getPropertyPath();
}
/**
* {@inheritdoc}
*/
public function isWritable($data, FormInterface $form): bool
{
return null !== $form->getPropertyPath();
}
private function getPropertyValue($data, $propertyPath)
{
try {
return $this->propertyAccessor->getValue($data, $propertyPath);
} catch (PropertyAccessException $e) {
if (!$e instanceof UninitializedPropertyException
// For versions without UninitializedPropertyException check the exception message
&& (class_exists(UninitializedPropertyException::class) || false === strpos($e->getMessage(), 'You should initialize it'))
) {
throw $e;
}
return null;
}
}
}

View File

@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Extension\Core\DataMapper;
use Symfony\Component\Form\DataAccessorInterface;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Core\DataAccessor\CallbackAccessor;
use Symfony\Component\Form\Extension\Core\DataAccessor\ChainAccessor;
use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
/**
* Maps arrays/objects to/from forms using data accessors.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class DataMapper implements DataMapperInterface
{
private $dataAccessor;
public function __construct(DataAccessorInterface $dataAccessor = null)
{
$this->dataAccessor = $dataAccessor ?? new ChainAccessor([
new CallbackAccessor(),
new PropertyPathAccessor(),
]);
}
/**
* {@inheritdoc}
*/
public function mapDataToForms($data, iterable $forms): void
{
$empty = null === $data || [] === $data;
if (!$empty && !\is_array($data) && !\is_object($data)) {
throw new UnexpectedTypeException($data, 'object, array or empty');
}
foreach ($forms as $form) {
$config = $form->getConfig();
if (!$empty && $config->getMapped() && $this->dataAccessor->isReadable($data, $form)) {
$form->setData($this->dataAccessor->getValue($data, $form));
} else {
$form->setData($config->getData());
}
}
}
/**
* {@inheritdoc}
*/
public function mapFormsToData(iterable $forms, &$data): void
{
if (null === $data) {
return;
}
if (!\is_array($data) && !\is_object($data)) {
throw new UnexpectedTypeException($data, 'object, array or empty');
}
foreach ($forms as $form) {
$config = $form->getConfig();
// Write-back is disabled if the form is not synchronized (transformation failed),
// if the form was not submitted and if the form is disabled (modification not allowed)
if ($config->getMapped() && $form->isSubmitted() && $form->isSynchronized() && !$form->isDisabled() && $this->dataAccessor->isWritable($data, $form)) {
$this->dataAccessor->setValue($data, $form->getData(), $form);
}
}
}
}

View File

@ -18,10 +18,14 @@ use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
trigger_deprecation('symfony/form', '5.2', 'The "%s" class is deprecated. Use "%s" instead.', PropertyPathMapper::class, DataMapper::class);
/** /**
* Maps arrays/objects to/from forms using property paths. * Maps arrays/objects to/from forms using property paths.
* *
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since symfony/form 5.2. Use {@see DataMapper} instead.
*/ */
class PropertyPathMapper implements DataMapperInterface class PropertyPathMapper implements DataMapperInterface
{ {

View File

@ -12,7 +12,10 @@
namespace Symfony\Component\Form\Extension\Core\Type; namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataAccessor\CallbackAccessor;
use Symfony\Component\Form\Extension\Core\DataAccessor\ChainAccessor;
use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener; use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormConfigBuilderInterface; use Symfony\Component\Form\FormConfigBuilderInterface;
@ -25,11 +28,14 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
class FormType extends BaseType class FormType extends BaseType
{ {
private $propertyAccessor; private $dataMapper;
public function __construct(PropertyAccessorInterface $propertyAccessor = null) public function __construct(PropertyAccessorInterface $propertyAccessor = null)
{ {
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); $this->dataMapper = new DataMapper(new ChainAccessor([
new CallbackAccessor(),
new PropertyPathAccessor($propertyAccessor ?? PropertyAccess::createPropertyAccessor()),
]));
} }
/** /**
@ -52,7 +58,7 @@ class FormType extends BaseType
->setCompound($options['compound']) ->setCompound($options['compound'])
->setData($isDataOptionSet ? $options['data'] : null) ->setData($isDataOptionSet ? $options['data'] : null)
->setDataLocked($isDataOptionSet) ->setDataLocked($isDataOptionSet)
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null) ->setDataMapper($options['compound'] ? $this->dataMapper : null)
->setMethod($options['method']) ->setMethod($options['method'])
->setAction($options['action']); ->setAction($options['action']);
@ -202,6 +208,8 @@ class FormType extends BaseType
'invalid_message' => 'This value is not valid.', 'invalid_message' => 'This value is not valid.',
'invalid_message_parameters' => [], 'invalid_message_parameters' => [],
'is_empty_callback' => null, 'is_empty_callback' => null,
'getter' => null,
'setter' => null,
]); ]);
$resolver->setAllowedTypes('label_attr', 'array'); $resolver->setAllowedTypes('label_attr', 'array');
@ -211,6 +219,11 @@ class FormType extends BaseType
$resolver->setAllowedTypes('help_attr', 'array'); $resolver->setAllowedTypes('help_attr', 'array');
$resolver->setAllowedTypes('help_html', 'bool'); $resolver->setAllowedTypes('help_html', 'bool');
$resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']); $resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']);
$resolver->setAllowedTypes('getter', ['null', 'callable']);
$resolver->setAllowedTypes('setter', ['null', 'callable']);
$resolver->setInfo('getter', 'A callable that accepts two arguments (the view data and the current form field) and must return a value.');
$resolver->setInfo('setter', 'A callable that accepts three arguments (a reference to the view data, the submitted value and the current form field).');
} }
/** /**

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Form; use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
@ -409,7 +409,7 @@ abstract class AbstractRequestHandlerTest extends TestCase
$builder->setCompound($compound); $builder->setCompound($compound);
if ($compound) { if ($compound) {
$builder->setDataMapper(new PropertyPathMapper()); $builder->setDataMapper(new DataMapper());
} }
return $builder; return $builder;

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Form\Tests; namespace Symfony\Component\Form\Tests;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
@ -394,17 +394,17 @@ class CompoundFormTest extends AbstractFormTest
{ {
$form = $this->getBuilder() $form = $this->getBuilder()
->setCompound(true) ->setCompound(true)
// We test using PropertyPathMapper on purpose. The traversal logic // We test using DataMapper on purpose. The traversal logic
// is currently contained in InheritDataAwareIterator, but even // is currently contained in InheritDataAwareIterator, but even
// if that changes, this test should still function. // if that changes, this test should still function.
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$childToBeRemoved = $this->createForm('removed', false); $childToBeRemoved = $this->createForm('removed', false);
$childToBeAdded = $this->createForm('added', false); $childToBeAdded = $this->createForm('added', false);
$child = $this->getBuilder('child', new EventDispatcher()) $child = $this->getBuilder('child', new EventDispatcher())
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($form, $childToBeAdded) { ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($form, $childToBeAdded) {
$form->remove('removed'); $form->remove('removed');
$form->add($childToBeAdded); $form->add($childToBeAdded);
@ -449,7 +449,7 @@ class CompoundFormTest extends AbstractFormTest
public function testSetDataDoesNotMapViewDataToChildrenWithLockedSetData() public function testSetDataDoesNotMapViewDataToChildrenWithLockedSetData()
{ {
$mapper = new PropertyPathMapper(); $mapper = new DataMapper();
$viewData = [ $viewData = [
'firstName' => 'Fabien', 'firstName' => 'Fabien',
'lastName' => 'Pot', 'lastName' => 'Pot',

View File

@ -0,0 +1,427 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Tests\Extension\Core\DataMapper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\Tests\Fixtures\TypehintedPropertiesCar;
use Symfony\Component\PropertyAccess\PropertyPath;
class DataMapperTest extends TestCase
{
/**
* @var DataMapper
*/
private $mapper;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
protected function setUp(): void
{
$this->mapper = new DataMapper();
$this->dispatcher = new EventDispatcher();
}
public function testMapDataToFormsPassesObjectRefIfByReference()
{
$car = new \stdClass();
$engine = new \stdClass();
$car->engine = $engine;
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$form = new Form($config);
$this->mapper->mapDataToForms($car, [$form]);
self::assertSame($engine, $form->getData());
}
public function testMapDataToFormsPassesObjectCloneIfNotByReference()
{
$car = new \stdClass();
$engine = new \stdClass();
$engine->brand = 'Rolls-Royce';
$car->engine = $engine;
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(false);
$config->setPropertyPath($propertyPath);
$form = new Form($config);
$this->mapper->mapDataToForms($car, [$form]);
self::assertNotSame($engine, $form->getData());
self::assertEquals($engine, $form->getData());
}
public function testMapDataToFormsIgnoresEmptyPropertyPath()
{
$car = new \stdClass();
$config = new FormConfigBuilder(null, \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$form = new Form($config);
self::assertNull($form->getPropertyPath());
$this->mapper->mapDataToForms($car, [$form]);
self::assertNull($form->getData());
}
public function testMapDataToFormsIgnoresUnmapped()
{
$car = new \stdClass();
$car->engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setMapped(false);
$config->setPropertyPath($propertyPath);
$form = new Form($config);
$this->mapper->mapDataToForms($car, [$form]);
self::assertNull($form->getData());
}
/**
* @requires PHP 7.4
*/
public function testMapDataToFormsIgnoresUninitializedProperties()
{
$engineForm = new Form(new FormConfigBuilder('engine', null, $this->dispatcher));
$colorForm = new Form(new FormConfigBuilder('color', null, $this->dispatcher));
$car = new TypehintedPropertiesCar();
$car->engine = 'BMW';
$this->mapper->mapDataToForms($car, [$engineForm, $colorForm]);
self::assertSame($car->engine, $engineForm->getData());
self::assertNull($colorForm->getData());
}
public function testMapDataToFormsSetsDefaultDataIfPassedDataIsNull()
{
$default = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($default);
$form = new Form($config);
$this->mapper->mapDataToForms(null, [$form]);
self::assertSame($default, $form->getData());
}
public function testMapDataToFormsSetsDefaultDataIfPassedDataIsEmptyArray()
{
$default = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($default);
$form = new Form($config);
$this->mapper->mapDataToForms([], [$form]);
self::assertSame($default, $form->getData());
}
public function testMapFormsToDataWritesBackIfNotByReference()
{
$car = new \stdClass();
$car->engine = new \stdClass();
$engine = new \stdClass();
$engine->brand = 'Rolls-Royce';
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(false);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertEquals($engine, $car->engine);
self::assertNotSame($engine, $car->engine);
}
public function testMapFormsToDataWritesBackIfByReferenceButNoReference()
{
$car = new \stdClass();
$car->engine = new \stdClass();
$engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($engine, $car->engine);
}
public function testMapFormsToDataWritesBackIfByReferenceAndReference()
{
$car = new \stdClass();
$car->engine = 'BMW';
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('engine', null, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData('Rolls-Royce');
$form = new SubmittedForm($config);
$car->engine = 'Rolls-Royce';
$this->mapper->mapFormsToData([$form], $car);
self::assertSame('Rolls-Royce', $car->engine);
}
public function testMapFormsToDataIgnoresUnmapped()
{
$initialEngine = new \stdClass();
$car = new \stdClass();
$car->engine = $initialEngine;
$engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$config->setMapped(false);
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($initialEngine, $car->engine);
}
public function testMapFormsToDataIgnoresUnsubmittedForms()
{
$initialEngine = new \stdClass();
$car = new \stdClass();
$car->engine = $initialEngine;
$engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$form = new Form($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($initialEngine, $car->engine);
}
public function testMapFormsToDataIgnoresEmptyData()
{
$initialEngine = new \stdClass();
$car = new \stdClass();
$car->engine = $initialEngine;
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData(null);
$form = new Form($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($initialEngine, $car->engine);
}
public function testMapFormsToDataIgnoresUnsynchronized()
{
$initialEngine = new \stdClass();
$car = new \stdClass();
$car->engine = $initialEngine;
$engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$form = new NotSynchronizedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($initialEngine, $car->engine);
}
public function testMapFormsToDataIgnoresDisabled()
{
$initialEngine = new \stdClass();
$car = new \stdClass();
$car->engine = $initialEngine;
$engine = new \stdClass();
$propertyPath = new PropertyPath('engine');
$config = new FormConfigBuilder('name', \stdClass::class, $this->dispatcher);
$config->setByReference(true);
$config->setPropertyPath($propertyPath);
$config->setData($engine);
$config->setDisabled(true);
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame($initialEngine, $car->engine);
}
/**
* @requires PHP 7.4
*/
public function testMapFormsToUninitializedProperties()
{
$car = new TypehintedPropertiesCar();
$config = new FormConfigBuilder('engine', null, $this->dispatcher);
$config->setData('BMW');
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $car);
self::assertSame('BMW', $car->engine);
}
/**
* @dataProvider provideDate
*/
public function testMapFormsToDataDoesNotChangeEqualDateTimeInstance($date)
{
$article = [];
$publishedAt = $date;
$publishedAtValue = clone $publishedAt;
$article['publishedAt'] = $publishedAtValue;
$propertyPath = new PropertyPath('[publishedAt]');
$config = new FormConfigBuilder('publishedAt', \get_class($publishedAt), $this->dispatcher);
$config->setByReference(false);
$config->setPropertyPath($propertyPath);
$config->setData($publishedAt);
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $article);
self::assertSame($publishedAtValue, $article['publishedAt']);
}
public function provideDate(): array
{
return [
[new \DateTime()],
[new \DateTimeImmutable()],
];
}
public function testMapDataToFormsUsingGetCallbackOption()
{
$initialName = 'John Doe';
$person = new DummyPerson($initialName);
$config = new FormConfigBuilder('name', null, $this->dispatcher, [
'getter' => static function (DummyPerson $person) {
return $person->myName();
},
]);
$form = new Form($config);
$this->mapper->mapDataToForms($person, [$form]);
self::assertSame($initialName, $form->getData());
}
public function testMapFormsToDataUsingSetCallbackOption()
{
$person = new DummyPerson('John Doe');
$config = new FormConfigBuilder('name', null, $this->dispatcher, [
'setter' => static function (DummyPerson $person, $name) {
$person->rename($name);
},
]);
$config->setData('Jane Doe');
$form = new SubmittedForm($config);
$this->mapper->mapFormsToData([$form], $person);
self::assertSame('Jane Doe', $person->myName());
}
}
class SubmittedForm extends Form
{
public function isSubmitted(): bool
{
return true;
}
}
class NotSynchronizedForm extends SubmittedForm
{
public function isSynchronized(): bool
{
return false;
}
}
class DummyPerson
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function myName(): string
{
return $this->name;
}
public function rename($name): void
{
$this->name = $name;
}
}

View File

@ -22,6 +22,9 @@ use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\PropertyAccess\PropertyPath;
/**
* @group legacy
*/
class PropertyPathMapperTest extends TestCase class PropertyPathMapperTest extends TestCase
{ {
/** /**
@ -363,19 +366,3 @@ class PropertyPathMapperTest extends TestCase
]; ];
} }
} }
class SubmittedForm extends Form
{
public function isSubmitted(): bool
{
return true;
}
}
class NotSynchronizedForm extends SubmittedForm
{
public function isSynchronized(): bool
{
return false;
}
}

View File

@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener; use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
@ -31,7 +31,7 @@ class ResizeFormListenerTest extends TestCase
$this->factory = (new FormFactoryBuilder())->getFormFactory(); $this->factory = (new FormFactoryBuilder())->getFormFactory();
$this->form = $this->getBuilder() $this->form = $this->getBuilder()
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
} }
@ -268,12 +268,12 @@ class ResizeFormListenerTest extends TestCase
$this->form->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]); $this->form->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]);
$form1 = $this->getBuilder('0') $form1 = $this->getBuilder('0')
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form1->add($this->getForm('name')); $form1->add($this->getForm('name'));
$form2 = $this->getBuilder('1') $form2 = $this->getBuilder('1')
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form2->add($this->getForm('name')); $form2->add($this->getForm('name'));
$this->form->add($form1); $this->form->add($form1);

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
@ -33,7 +33,7 @@ class CsrfValidationListenerTest extends TestCase
$this->factory = (new FormFactoryBuilder())->getFormFactory(); $this->factory = (new FormFactoryBuilder())->getFormFactory();
$this->tokenManager = new CsrfTokenManager(); $this->tokenManager = new CsrfTokenManager();
$this->form = $this->getBuilder() $this->form = $this->getBuilder()
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
} }

View File

@ -15,7 +15,7 @@ use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Extension\Core\CoreExtension; use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
@ -81,7 +81,7 @@ class FormDataCollectorTest extends TestCase
$this->dataCollector = new FormDataCollector($this->dataExtractor); $this->dataCollector = new FormDataCollector($this->dataExtractor);
$this->dispatcher = new EventDispatcher(); $this->dispatcher = new EventDispatcher();
$this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory())); $this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory()));
$this->dataMapper = new PropertyPathMapper(); $this->dataMapper = new DataMapper();
$this->form = $this->createForm('name'); $this->form = $this->createForm('name');
$this->childForm = $this->createForm('child'); $this->childForm = $this->createForm('child');
$this->view = new FormView(); $this->view = new FormView();

View File

@ -15,7 +15,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\Constraints\Form;
use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator; use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
@ -107,7 +107,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parent = $this->getBuilder('parent') $parent = $this->getBuilder('parent')
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$options = [ $options = [
'validation_groups' => ['group1', 'group2'], 'validation_groups' => ['group1', 'group2'],
@ -130,7 +130,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parent = $this->getBuilder('parent', null) $parent = $this->getBuilder('parent', null)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$options = ['validation_groups' => ['group1', 'group2']]; $options = ['validation_groups' => ['group1', 'group2']];
$form = $this->getBuilder('name', '\stdClass', $options)->getForm(); $form = $this->getBuilder('name', '\stdClass', $options)->getForm();
@ -169,7 +169,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parent = $this->getBuilder('parent', null) $parent = $this->getBuilder('parent', null)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$options = [ $options = [
'validation_groups' => ['group1', 'group2'], 'validation_groups' => ['group1', 'group2'],
@ -196,7 +196,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
]) ])
->setData($object) ->setData($object)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form->setData($object); $form->setData($object);
@ -243,7 +243,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
]; ];
$form = $this->getBuilder('name', null, $formOptions) $form = $this->getBuilder('name', null, $formOptions)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$childOptions = ['constraints' => [new NotBlank()]]; $childOptions = ['constraints' => [new NotBlank()]];
$child = $this->getCompoundForm(new \stdClass(), $childOptions); $child = $this->getCompoundForm(new \stdClass(), $childOptions);
@ -470,7 +470,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parent = $this->getBuilder('parent') $parent = $this->getBuilder('parent')
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form = $this->getForm('name', '\stdClass', [ $form = $this->getForm('name', '\stdClass', [
'validation_groups' => 'form_group', 'validation_groups' => 'form_group',
@ -497,7 +497,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parent = $this->getBuilder('parent') $parent = $this->getBuilder('parent')
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form = $this->getCompoundForm($object, [ $form = $this->getCompoundForm($object, [
'validation_groups' => 'form_group', 'validation_groups' => 'form_group',
@ -525,7 +525,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parentOptions = ['validation_groups' => 'group']; $parentOptions = ['validation_groups' => 'group'];
$parent = $this->getBuilder('parent', null, $parentOptions) $parent = $this->getBuilder('parent', null, $parentOptions)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$formOptions = ['constraints' => [new Valid()]]; $formOptions = ['constraints' => [new Valid()]];
$form = $this->getCompoundForm($object, $formOptions); $form = $this->getCompoundForm($object, $formOptions);
@ -546,7 +546,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$parentOptions = ['validation_groups' => [$this, 'getValidationGroups']]; $parentOptions = ['validation_groups' => [$this, 'getValidationGroups']];
$parent = $this->getBuilder('parent', null, $parentOptions) $parent = $this->getBuilder('parent', null, $parentOptions)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$formOptions = ['constraints' => [new Valid()]]; $formOptions = ['constraints' => [new Valid()]];
$form = $this->getCompoundForm($object, $formOptions); $form = $this->getCompoundForm($object, $formOptions);
@ -571,7 +571,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
]; ];
$parent = $this->getBuilder('parent', null, $parentOptions) $parent = $this->getBuilder('parent', null, $parentOptions)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$formOptions = ['constraints' => [new Valid()]]; $formOptions = ['constraints' => [new Valid()]];
$form = $this->getCompoundForm($object, $formOptions); $form = $this->getCompoundForm($object, $formOptions);
@ -618,7 +618,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
{ {
$form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!']) $form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!'])
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->add($this->getBuilder('child')) ->add($this->getBuilder('child'))
->getForm(); ->getForm();
@ -643,7 +643,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
{ {
$form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!!']) $form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!!'])
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->add($this->getBuilder('child')) ->add($this->getBuilder('child'))
->getForm(); ->getForm();
@ -669,7 +669,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$form = $this $form = $this
->getBuilder('parent', null, ['allow_extra_fields' => true]) ->getBuilder('parent', null, ['allow_extra_fields' => true])
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->add($this->getBuilder('child')) ->add($this->getBuilder('child'))
->getForm(); ->getForm();
@ -698,7 +698,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
$form = $this $form = $this
->getBuilder('form', null, ['constraints' => [new NotBlank(['groups' => ['foo']])]]) ->getBuilder('form', null, ['constraints' => [new NotBlank(['groups' => ['foo']])]])
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
$form->submit([ $form->submit([
'extra_data' => 'foo', 'extra_data' => 'foo',
@ -739,7 +739,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
return $this->getBuilder('name', \is_object($data) ? \get_class($data) : null, $options) return $this->getBuilder('name', \is_object($data) ? \get_class($data) : null, $options)
->setData($data) ->setData($data)
->setCompound(true) ->setCompound(true)
->setDataMapper(new PropertyPathMapper()) ->setDataMapper(new DataMapper())
->getForm(); ->getForm();
} }

View File

@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint; use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint;
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
@ -79,7 +79,7 @@ class ValidationListenerTest extends TestCase
$config->setCompound($compound); $config->setCompound($compound);
if ($compound) { if ($compound) {
$config->setDataMapper(new PropertyPathMapper()); $config->setDataMapper(new DataMapper());
} }
return new Form($config); return new Form($config);

View File

@ -16,7 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
use Symfony\Component\Form\Form; use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormConfigBuilder;
@ -82,7 +82,7 @@ class ViolationMapperTest extends TestCase
$config->setInheritData($inheritData); $config->setInheritData($inheritData);
$config->setPropertyPath($propertyPath); $config->setPropertyPath($propertyPath);
$config->setCompound(true); $config->setCompound(true);
$config->setDataMapper(new PropertyPathMapper()); $config->setDataMapper(new DataMapper());
if (!$synchronized) { if (!$synchronized) {
$config->addViewTransformer(new CallbackTransformer( $config->addViewTransformer(new CallbackTransformer(
@ -1643,7 +1643,7 @@ class ViolationMapperTest extends TestCase
$config->setInheritData(false); $config->setInheritData(false);
$config->setPropertyPath('name'); $config->setPropertyPath('name');
$config->setCompound(true); $config->setCompound(true);
$config->setDataMapper(new PropertyPathMapper()); $config->setDataMapper(new DataMapper());
$child = new Form($config); $child = new Form($config);
$parent->add($child); $parent->add($child);
@ -1681,7 +1681,7 @@ class ViolationMapperTest extends TestCase
$config->setInheritData(false); $config->setInheritData(false);
$config->setPropertyPath('custom'); $config->setPropertyPath('custom');
$config->setCompound(true); $config->setCompound(true);
$config->setDataMapper(new PropertyPathMapper()); $config->setDataMapper(new DataMapper());
$child = new Form($config); $child = new Form($config);
$parent->add($child); $parent->add($child);
@ -1719,7 +1719,7 @@ class ViolationMapperTest extends TestCase
$config->setInheritData(false); $config->setInheritData(false);
$config->setPropertyPath('custom-id'); $config->setPropertyPath('custom-id');
$config->setCompound(true); $config->setCompound(true);
$config->setDataMapper(new PropertyPathMapper()); $config->setDataMapper(new DataMapper());
$child = new Form($config); $child = new Form($config);
$parent->add($child); $parent->add($child);

View File

@ -39,6 +39,7 @@
"by_reference", "by_reference",
"data", "data",
"disabled", "disabled",
"getter",
"help", "help",
"help_attr", "help_attr",
"help_html", "help_html",
@ -57,6 +58,7 @@
"property_path", "property_path",
"required", "required",
"row_attr", "row_attr",
"setter",
"translation_domain", "translation_domain",
"upload_max_size_message" "upload_max_size_message"
] ]

View File

@ -17,7 +17,8 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
group_by by_reference group_by by_reference
multiple data multiple data
placeholder disabled placeholder disabled
preferred_choices help preferred_choices getter
help
help_attr help_attr
help_html help_html
help_translation_parameters help_translation_parameters
@ -35,6 +36,7 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
property_path property_path
required required
row_attr row_attr
setter
translation_domain translation_domain
upload_max_size_message upload_max_size_message
--------------------------- -------------------- ------------------------------ ----------------------- --------------------------- -------------------- ------------------------------ -----------------------

View File

@ -17,6 +17,7 @@
"disabled", "disabled",
"empty_data", "empty_data",
"error_bubbling", "error_bubbling",
"getter",
"help", "help",
"help_attr", "help_attr",
"help_html", "help_html",
@ -36,6 +37,7 @@
"property_path", "property_path",
"required", "required",
"row_attr", "row_attr",
"setter",
"translation_domain", "translation_domain",
"trim", "trim",
"upload_max_size_message" "upload_max_size_message"

View File

@ -19,6 +19,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
disabled disabled
empty_data empty_data
error_bubbling error_bubbling
getter
help help
help_attr help_attr
help_html help_html
@ -38,6 +39,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
property_path property_path
required required
row_attr row_attr
setter
translation_domain translation_domain
trim trim
upload_max_size_message upload_max_size_message