add new way of mapping data using callback functions
This commit is contained in:
parent
845c232dd5
commit
878effaf47
@ -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
|
||||
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
|
||||
----
|
||||
|
||||
|
@ -48,6 +48,7 @@ Form
|
||||
* 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 `NumberToLocalizedStringTransformer::ROUND_*` constants have been removed, use `\NumberFormatter::ROUND_*` instead.
|
||||
* Removed `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor`.
|
||||
|
||||
FrameworkBundle
|
||||
---------------
|
||||
|
@ -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 `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
|
||||
-----
|
||||
|
69
src/Symfony/Component/Form/DataAccessorInterface.php
Normal file
69
src/Symfony/Component/Form/DataAccessorInterface.php
Normal 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;
|
||||
}
|
16
src/Symfony/Component/Form/Exception/AccessException.php
Normal file
16
src/Symfony/Component/Form/Exception/AccessException.php
Normal 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
|
||||
{
|
||||
}
|
@ -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');
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,10 +18,14 @@ use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
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.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated since symfony/form 5.2. Use {@see DataMapper} instead.
|
||||
*/
|
||||
class PropertyPathMapper implements DataMapperInterface
|
||||
{
|
||||
|
@ -12,7 +12,10 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
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\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormConfigBuilderInterface;
|
||||
@ -25,11 +28,14 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
class FormType extends BaseType
|
||||
{
|
||||
private $propertyAccessor;
|
||||
private $dataMapper;
|
||||
|
||||
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'])
|
||||
->setData($isDataOptionSet ? $options['data'] : null)
|
||||
->setDataLocked($isDataOptionSet)
|
||||
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
|
||||
->setDataMapper($options['compound'] ? $this->dataMapper : null)
|
||||
->setMethod($options['method'])
|
||||
->setAction($options['action']);
|
||||
|
||||
@ -202,6 +208,8 @@ class FormType extends BaseType
|
||||
'invalid_message' => 'This value is not valid.',
|
||||
'invalid_message_parameters' => [],
|
||||
'is_empty_callback' => null,
|
||||
'getter' => null,
|
||||
'setter' => null,
|
||||
]);
|
||||
|
||||
$resolver->setAllowedTypes('label_attr', 'array');
|
||||
@ -211,6 +219,11 @@ class FormType extends BaseType
|
||||
$resolver->setAllowedTypes('help_attr', 'array');
|
||||
$resolver->setAllowedTypes('help_html', 'bool');
|
||||
$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).');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
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\FormBuilder;
|
||||
use Symfony\Component\Form\FormError;
|
||||
@ -409,7 +409,7 @@ abstract class AbstractRequestHandlerTest extends TestCase
|
||||
$builder->setCompound($compound);
|
||||
|
||||
if ($compound) {
|
||||
$builder->setDataMapper(new PropertyPathMapper());
|
||||
$builder->setDataMapper(new DataMapper());
|
||||
}
|
||||
|
||||
return $builder;
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\Form\Tests;
|
||||
|
||||
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\FormError;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
@ -394,17 +394,17 @@ class CompoundFormTest extends AbstractFormTest
|
||||
{
|
||||
$form = $this->getBuilder()
|
||||
->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
|
||||
// if that changes, this test should still function.
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
|
||||
$childToBeRemoved = $this->createForm('removed', false);
|
||||
$childToBeAdded = $this->createForm('added', false);
|
||||
$child = $this->getBuilder('child', new EventDispatcher())
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($form, $childToBeAdded) {
|
||||
$form->remove('removed');
|
||||
$form->add($childToBeAdded);
|
||||
@ -449,7 +449,7 @@ class CompoundFormTest extends AbstractFormTest
|
||||
|
||||
public function testSetDataDoesNotMapViewDataToChildrenWithLockedSetData()
|
||||
{
|
||||
$mapper = new PropertyPathMapper();
|
||||
$mapper = new DataMapper();
|
||||
$viewData = [
|
||||
'firstName' => 'Fabien',
|
||||
'lastName' => 'Pot',
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -22,6 +22,9 @@ use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
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\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilder;
|
||||
@ -31,7 +31,7 @@ class ResizeFormListenerTest extends TestCase
|
||||
$this->factory = (new FormFactoryBuilder())->getFormFactory();
|
||||
$this->form = $this->getBuilder()
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
}
|
||||
|
||||
@ -268,12 +268,12 @@ class ResizeFormListenerTest extends TestCase
|
||||
$this->form->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]);
|
||||
$form1 = $this->getBuilder('0')
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$form1->add($this->getForm('name'));
|
||||
$form2 = $this->getBuilder('1')
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$form2->add($this->getForm('name'));
|
||||
$this->form->add($form1);
|
||||
|
@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
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\FormBuilder;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
@ -33,7 +33,7 @@ class CsrfValidationListenerTest extends TestCase
|
||||
$this->factory = (new FormFactoryBuilder())->getFormFactory();
|
||||
$this->tokenManager = new CsrfTokenManager();
|
||||
$this->form = $this->getBuilder()
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
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\FormType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
@ -81,7 +81,7 @@ class FormDataCollectorTest extends TestCase
|
||||
$this->dataCollector = new FormDataCollector($this->dataExtractor);
|
||||
$this->dispatcher = new EventDispatcher();
|
||||
$this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory()));
|
||||
$this->dataMapper = new PropertyPathMapper();
|
||||
$this->dataMapper = new DataMapper();
|
||||
$this->form = $this->createForm('name');
|
||||
$this->childForm = $this->createForm('child');
|
||||
$this->view = new FormView();
|
||||
|
@ -15,7 +15,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
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\FormValidator;
|
||||
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
||||
@ -107,7 +107,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
$parent = $this->getBuilder('parent')
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$options = [
|
||||
'validation_groups' => ['group1', 'group2'],
|
||||
@ -130,7 +130,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
$parent = $this->getBuilder('parent', null)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$options = ['validation_groups' => ['group1', 'group2']];
|
||||
$form = $this->getBuilder('name', '\stdClass', $options)->getForm();
|
||||
@ -169,7 +169,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
$parent = $this->getBuilder('parent', null)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$options = [
|
||||
'validation_groups' => ['group1', 'group2'],
|
||||
@ -196,7 +196,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
])
|
||||
->setData($object)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
|
||||
$form->setData($object);
|
||||
@ -243,7 +243,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
];
|
||||
$form = $this->getBuilder('name', null, $formOptions)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$childOptions = ['constraints' => [new NotBlank()]];
|
||||
$child = $this->getCompoundForm(new \stdClass(), $childOptions);
|
||||
@ -470,7 +470,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
$parent = $this->getBuilder('parent')
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$form = $this->getForm('name', '\stdClass', [
|
||||
'validation_groups' => 'form_group',
|
||||
@ -497,7 +497,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
$parent = $this->getBuilder('parent')
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$form = $this->getCompoundForm($object, [
|
||||
'validation_groups' => 'form_group',
|
||||
@ -525,7 +525,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
$parentOptions = ['validation_groups' => 'group'];
|
||||
$parent = $this->getBuilder('parent', null, $parentOptions)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$formOptions = ['constraints' => [new Valid()]];
|
||||
$form = $this->getCompoundForm($object, $formOptions);
|
||||
@ -546,7 +546,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
$parentOptions = ['validation_groups' => [$this, 'getValidationGroups']];
|
||||
$parent = $this->getBuilder('parent', null, $parentOptions)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$formOptions = ['constraints' => [new Valid()]];
|
||||
$form = $this->getCompoundForm($object, $formOptions);
|
||||
@ -571,7 +571,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
];
|
||||
$parent = $this->getBuilder('parent', null, $parentOptions)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$formOptions = ['constraints' => [new Valid()]];
|
||||
$form = $this->getCompoundForm($object, $formOptions);
|
||||
@ -618,7 +618,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
{
|
||||
$form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!'])
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->add($this->getBuilder('child'))
|
||||
->getForm();
|
||||
|
||||
@ -643,7 +643,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
{
|
||||
$form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!|Extras!!'])
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->add($this->getBuilder('child'))
|
||||
->getForm();
|
||||
|
||||
@ -669,7 +669,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
$form = $this
|
||||
->getBuilder('parent', null, ['allow_extra_fields' => true])
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->add($this->getBuilder('child'))
|
||||
->getForm();
|
||||
|
||||
@ -698,7 +698,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
$form = $this
|
||||
->getBuilder('form', null, ['constraints' => [new NotBlank(['groups' => ['foo']])]])
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
$form->submit([
|
||||
'extra_data' => 'foo',
|
||||
@ -739,7 +739,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
||||
return $this->getBuilder('name', \is_object($data) ? \get_class($data) : null, $options)
|
||||
->setData($data)
|
||||
->setCompound(true)
|
||||
->setDataMapper(new PropertyPathMapper())
|
||||
->setDataMapper(new DataMapper())
|
||||
->getForm();
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
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\EventListener\ValidationListener;
|
||||
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
|
||||
@ -79,7 +79,7 @@ class ValidationListenerTest extends TestCase
|
||||
$config->setCompound($compound);
|
||||
|
||||
if ($compound) {
|
||||
$config->setDataMapper(new PropertyPathMapper());
|
||||
$config->setDataMapper(new DataMapper());
|
||||
}
|
||||
|
||||
return new Form($config);
|
||||
|
@ -16,7 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
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\Form;
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
@ -82,7 +82,7 @@ class ViolationMapperTest extends TestCase
|
||||
$config->setInheritData($inheritData);
|
||||
$config->setPropertyPath($propertyPath);
|
||||
$config->setCompound(true);
|
||||
$config->setDataMapper(new PropertyPathMapper());
|
||||
$config->setDataMapper(new DataMapper());
|
||||
|
||||
if (!$synchronized) {
|
||||
$config->addViewTransformer(new CallbackTransformer(
|
||||
@ -1643,7 +1643,7 @@ class ViolationMapperTest extends TestCase
|
||||
$config->setInheritData(false);
|
||||
$config->setPropertyPath('name');
|
||||
$config->setCompound(true);
|
||||
$config->setDataMapper(new PropertyPathMapper());
|
||||
$config->setDataMapper(new DataMapper());
|
||||
|
||||
$child = new Form($config);
|
||||
$parent->add($child);
|
||||
@ -1681,7 +1681,7 @@ class ViolationMapperTest extends TestCase
|
||||
$config->setInheritData(false);
|
||||
$config->setPropertyPath('custom');
|
||||
$config->setCompound(true);
|
||||
$config->setDataMapper(new PropertyPathMapper());
|
||||
$config->setDataMapper(new DataMapper());
|
||||
|
||||
$child = new Form($config);
|
||||
$parent->add($child);
|
||||
@ -1719,7 +1719,7 @@ class ViolationMapperTest extends TestCase
|
||||
$config->setInheritData(false);
|
||||
$config->setPropertyPath('custom-id');
|
||||
$config->setCompound(true);
|
||||
$config->setDataMapper(new PropertyPathMapper());
|
||||
$config->setDataMapper(new DataMapper());
|
||||
|
||||
$child = new Form($config);
|
||||
$parent->add($child);
|
||||
|
@ -39,6 +39,7 @@
|
||||
"by_reference",
|
||||
"data",
|
||||
"disabled",
|
||||
"getter",
|
||||
"help",
|
||||
"help_attr",
|
||||
"help_html",
|
||||
@ -57,6 +58,7 @@
|
||||
"property_path",
|
||||
"required",
|
||||
"row_attr",
|
||||
"setter",
|
||||
"translation_domain",
|
||||
"upload_max_size_message"
|
||||
]
|
||||
|
@ -17,7 +17,8 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
|
||||
group_by by_reference
|
||||
multiple data
|
||||
placeholder disabled
|
||||
preferred_choices help
|
||||
preferred_choices getter
|
||||
help
|
||||
help_attr
|
||||
help_html
|
||||
help_translation_parameters
|
||||
@ -35,6 +36,7 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice")
|
||||
property_path
|
||||
required
|
||||
row_attr
|
||||
setter
|
||||
translation_domain
|
||||
upload_max_size_message
|
||||
--------------------------- -------------------- ------------------------------ -----------------------
|
||||
|
@ -17,6 +17,7 @@
|
||||
"disabled",
|
||||
"empty_data",
|
||||
"error_bubbling",
|
||||
"getter",
|
||||
"help",
|
||||
"help_attr",
|
||||
"help_html",
|
||||
@ -36,6 +37,7 @@
|
||||
"property_path",
|
||||
"required",
|
||||
"row_attr",
|
||||
"setter",
|
||||
"translation_domain",
|
||||
"trim",
|
||||
"upload_max_size_message"
|
||||
|
@ -19,6 +19,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
|
||||
disabled
|
||||
empty_data
|
||||
error_bubbling
|
||||
getter
|
||||
help
|
||||
help_attr
|
||||
help_html
|
||||
@ -38,6 +39,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")
|
||||
property_path
|
||||
required
|
||||
row_attr
|
||||
setter
|
||||
translation_domain
|
||||
trim
|
||||
upload_max_size_message
|
||||
|
Reference in New Issue
Block a user