invalidate forms on transformation failures
This commit is contained in:
parent
d1ca2ac4af
commit
385d9df29c
@ -166,6 +166,11 @@
|
|||||||
<tag name="form.type" alias="currency" />
|
<tag name="form.type" alias="currency" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="form.type_extension.form.transformation_failure_handling" class="Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension">
|
||||||
|
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
|
||||||
|
<argument type="service" id="translator" on-invalid="ignore" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<!-- FormTypeHttpFoundationExtension -->
|
<!-- FormTypeHttpFoundationExtension -->
|
||||||
<service id="form.type_extension.form.http_foundation" class="Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension">
|
<service id="form.type_extension.form.http_foundation" class="Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension">
|
||||||
<argument type="service" id="form.type_extension.form.request_handler" />
|
<argument type="service" id="form.type_extension.form.request_handler" />
|
||||||
|
@ -16,8 +16,10 @@ use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator;
|
|||||||
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface;
|
||||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||||
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
|
use Symfony\Component\Translation\TranslatorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the main form extension, which loads the core functionality.
|
* Represents the main form extension, which loads the core functionality.
|
||||||
@ -28,11 +30,13 @@ class CoreExtension extends AbstractExtension
|
|||||||
{
|
{
|
||||||
private $propertyAccessor;
|
private $propertyAccessor;
|
||||||
private $choiceListFactory;
|
private $choiceListFactory;
|
||||||
|
private $translator;
|
||||||
|
|
||||||
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null)
|
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null)
|
||||||
{
|
{
|
||||||
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
||||||
$this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor));
|
$this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor));
|
||||||
|
$this->translator = $translator;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadTypes()
|
protected function loadTypes()
|
||||||
@ -71,4 +75,11 @@ class CoreExtension extends AbstractExtension
|
|||||||
new Type\CurrencyType(),
|
new Type\CurrencyType(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function loadTypeExtensions()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new TransformationFailureExtension($this->translator),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Component\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
|
||||||
|
*/
|
||||||
|
class TransformationFailureListener implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
private $translator;
|
||||||
|
|
||||||
|
public function __construct(TranslatorInterface $translator = null)
|
||||||
|
{
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
FormEvents::POST_SUBMIT => array('convertTransformationFailureToFormError', -1024),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertTransformationFailureToFormError(FormEvent $event)
|
||||||
|
{
|
||||||
|
$form = $event->getForm();
|
||||||
|
|
||||||
|
if (null === $form->getTransformationFailure() || !$form->isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form as $child) {
|
||||||
|
if (!$child->isSynchronized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientDataAsString = is_scalar($form->getViewData()) ? (string) $form->getViewData() : \gettype($form->getViewData());
|
||||||
|
$messageTemplate = 'The value {{ value }} is not valid.';
|
||||||
|
|
||||||
|
if (null !== $this->translator) {
|
||||||
|
$message = $this->translator->trans($messageTemplate, array('{{ value }}' => $clientDataAsString));
|
||||||
|
} else {
|
||||||
|
$message = strtr($messageTemplate, array('{{ value }}' => $clientDataAsString));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->addError(new FormError($message, $messageTemplate, array('{{ value }}' => $clientDataAsString), null, $form->getTransformationFailure()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<?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\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractTypeExtension;
|
||||||
|
use Symfony\Component\Form\Extension\Core\EventListener\TransformationFailureListener;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
|
||||||
|
*/
|
||||||
|
class TransformationFailureExtension extends AbstractTypeExtension
|
||||||
|
{
|
||||||
|
private $translator;
|
||||||
|
|
||||||
|
public function __construct(TranslatorInterface $translator = null)
|
||||||
|
{
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
if (!isset($options['invalid_message']) && !isset($options['invalid_message_parameters'])) {
|
||||||
|
$builder->addEventSubscriber(new TransformationFailureListener($this->translator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtendedType()
|
||||||
|
{
|
||||||
|
return 'Symfony\Component\Form\Extension\Core\Type\FormType';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Form\Extension\Core\CoreExtension;
|
||||||
|
use Symfony\Component\Form\FormFactoryBuilder;
|
||||||
|
|
||||||
|
class CoreExtensionTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testTransformationFailuresAreConvertedIntoFormErrors()
|
||||||
|
{
|
||||||
|
$formFactoryBuilder = new FormFactoryBuilder();
|
||||||
|
$formFactory = $formFactoryBuilder->addExtension(new CoreExtension())
|
||||||
|
->getFormFactory();
|
||||||
|
|
||||||
|
$form = $formFactory->createBuilder()
|
||||||
|
->add('foo', 'Symfony\Component\Form\Extension\Core\Type\DateType')
|
||||||
|
->getForm();
|
||||||
|
$form->submit('foo');
|
||||||
|
|
||||||
|
$this->assertFalse($form->isValid());
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user