bug #11350 [2.5][Form] solved dependency to ValidatorInterface, fix #11036 (Sebastian Blum)

This PR was submitted for the master branch but it was merged into the 2.5 branch instead (closes #11350).

Discussion
----------

[2.5][Form] solved dependency to ValidatorInterface, fix #11036

| Q             | A
| ------------- | ---
| Bug fix?      | [yes]
| New feature?  | [no]
| BC breaks?    | [no]
| Deprecations? | [no]
| Tests pass?   | [yes]
| Fixed tickets | #11036, #11345
| License       | MIT
| Doc PR        |

Since Symfony 2.5

The problem was that the form component has a hardcoded depencency to the deprecated validator component (api Version 2.4)
The pull request fixes the dependency to the validator component and supports now both implementations, apiVersion 2.5 and apiVersion 2.4 of the validator component.

@Symfony Core Members
please review the changes 0a1e9c208f/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php
I'm not sure if it was the right solution

Commits
-------

705d67b [2.5][Form] solved dependency to ValidatorInterface, fix #11036
This commit is contained in:
Fabien Potencier 2014-07-15 16:46:59 +02:00
commit f11da64cb9
6 changed files with 189 additions and 9 deletions

View File

@ -13,7 +13,8 @@ namespace Symfony\Component\Form\Extension\Validator\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ValidatorInterface as LegacyValidatorInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
@ -35,8 +36,16 @@ class ValidationListener implements EventSubscriberInterface
return array(FormEvents::POST_SUBMIT => 'validateForm');
}
public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
/**
* @param ValidatorInterface|LegacyValidatorInterface $validator
* @param ViolationMapperInterface $violationMapper
*/
public function __construct($validator, ViolationMapperInterface $violationMapper)
{
if (!$validator instanceof ValidatorInterface && !$validator instanceof LegacyValidatorInterface) {
throw new \InvalidArgumentException('Validator must be instance of Symfony\Component\Validator\Validator\ValidatorInterface or Symfony\Component\Validator\ValidatorInterface');
}
$this->validator = $validator;
$this->violationMapper = $violationMapper;
}

View File

@ -14,7 +14,8 @@ namespace Symfony\Component\Form\Extension\Validator\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ValidatorInterface as LegacyValidatorInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
@ -33,8 +34,15 @@ class FormTypeValidatorExtension extends BaseValidatorExtension
*/
private $violationMapper;
public function __construct(ValidatorInterface $validator)
/**
* @param ValidatorInterface|LegacyValidatorInterface $validator
*/
public function __construct($validator)
{
if (!$validator instanceof ValidatorInterface && !$validator instanceof LegacyValidatorInterface) {
throw new \InvalidArgumentException('Validator must be instance of Symfony\Component\Validator\Validator\ValidatorInterface or Symfony\Component\Validator\ValidatorInterface');
}
$this->validator = $validator;
$this->violationMapper = new ViolationMapper();
}

View File

@ -13,8 +13,10 @@ namespace Symfony\Component\Form\Extension\Validator;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
use Symfony\Component\Form\AbstractExtension;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ValidatorInterface as LegacyValidatorInterface;
/**
* Extension supporting the Symfony2 Validator component in forms.
@ -25,17 +27,32 @@ class ValidatorExtension extends AbstractExtension
{
private $validator;
public function __construct(ValidatorInterface $validator)
/**
* @param ValidatorInterface|LegacyValidatorInterface $validator
*/
public function __construct($validator)
{
$this->validator = $validator;
// since validator apiVersion 2.5
if ($validator instanceof ValidatorInterface) {
$this->validator = $validator;
/** @var $metadata ClassMetadata */
$metadata = $this->validator->getMetadataFor('Symfony\Component\Form\Form');
// until validator apiVersion 2.4
} elseif ($validator instanceof LegacyValidatorInterface) {
$this->validator = $validator;
/** @var $metadata ClassMetadata */
$metadata = $this->validator->getMetadataFactory()->getMetadataFor('Symfony\Component\Form\Form');
} else {
throw new \InvalidArgumentException('Validator must be instance of Symfony\Component\Validator\Validator\ValidatorInterface or Symfony\Component\Validator\ValidatorInterface');
}
// Register the form constraints in the validator programmatically.
// This functionality is required when using the Form component without
// the DIC, where the XML file is loaded automatically. Thus the following
// code must be kept synchronized with validation.xml
/** @var \Symfony\Component\Validator\Mapping\ClassMetadata $metadata */
$metadata = $this->validator->getMetadataFactory()->getMetadataFor('Symfony\Component\Form\Form');
$metadata->addConstraint(new Form());
$metadata->addPropertyConstraint('children', new Valid());
}

View File

@ -158,4 +158,30 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase
$this->listener->validateForm(new FormEvent($form, null));
}
public function testValidatorInterfaceSinceSymfony25()
{
// Mock of ValidatorInterface since apiVersion 2.5
$validator = $this->getMock('Symfony\Component\Validator\Validator\ValidatorInterface');
$listener = new ValidationListener($validator, $this->violationMapper);
$this->assertAttributeSame($validator, 'validator', $listener);
}
public function testValidatorInterfaceUntilSymfony24()
{
// Mock of ValidatorInterface until apiVersion 2.4
$validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
$listener = new ValidationListener($validator, $this->violationMapper);
$this->assertAttributeSame($validator, 'validator', $listener);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testInvalidValidatorInterface()
{
new ValidationListener(null, $this->violationMapper);
}
}

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension;
use Symfony\Component\Validator\ConstraintViolationList;
class FormTypeValidatorExtensionTest extends BaseValidatorExtensionTest
@ -36,6 +37,32 @@ class FormTypeValidatorExtensionTest extends BaseValidatorExtensionTest
$form->submit(array());
}
public function testValidatorInterfaceSinceSymfony25()
{
// Mock of ValidatorInterface since apiVersion 2.5
$validator = $this->getMock('Symfony\Component\Validator\Validator\ValidatorInterface');
$formTypeValidatorExtension = new FormTypeValidatorExtension($validator);
$this->assertAttributeSame($validator, 'validator', $formTypeValidatorExtension);
}
public function testValidatorInterfaceUntilSymfony24()
{
// Mock of ValidatorInterface until apiVersion 2.4
$validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
$formTypeValidatorExtension = new FormTypeValidatorExtension($validator);
$this->assertAttributeSame($validator, 'validator', $formTypeValidatorExtension);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testInvalidValidatorInterface()
{
new FormTypeValidatorExtension(null);
}
protected function createForm(array $options = array())
{
return $this->factory->create('form', null, $options);

View File

@ -0,0 +1,93 @@
<?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\Validator;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
class ValidatorExtensionTest extends \PHPUnit_Framework_TestCase
{
public function testValidatorInterfaceSinceSymfony25()
{
$classMetaData = $this->createClassMetaDataMock();
// Mock of ValidatorInterface since apiVersion 2.5
$validator = $this->getMock('Symfony\Component\Validator\Validator\ValidatorInterface');
$validator
->expects($this->once())
->method('getMetadataFor')
->with($this->identicalTo('Symfony\Component\Form\Form'))
->will($this->returnValue($classMetaData))
;
$validatorExtension = new ValidatorExtension($validator);
$this->assertAttributeSame($validator, 'validator', $validatorExtension);
}
public function testValidatorInterfaceUntilSymfony24()
{
$classMetaData = $this->createClassMetaDataMock();
$metaDataFactory = $this->getMock('Symfony\Component\Validator\MetadataFactoryInterface');
$metaDataFactory
->expects($this->once())
->method('getMetadataFor')
->with($this->identicalTo('Symfony\Component\Form\Form'))
->will($this->returnValue($classMetaData))
;
// Mock of ValidatorInterface until apiVersion 2.4
$validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
$validator
->expects($this->once())
->method('getMetadataFactory')
->will($this->returnValue($metaDataFactory))
;
$validatorExtension = new ValidatorExtension($validator);
$this->assertAttributeSame($validator, 'validator', $validatorExtension);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testInvalidValidatorInterface()
{
new ValidatorExtension(null);
}
/**
* @return mixed
*/
private function createClassMetaDataMock()
{
$classMetaData = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata')
->disableOriginalConstructor()
->getMock();
$classMetaData
->expects($this->once())
->method('addConstraint')
->with($this->isInstanceOf('Symfony\Component\Form\Extension\Validator\Constraints\Form'));
$classMetaData
->expects($this->once())
->method('addPropertyConstraint')
->with(
$this->identicalTo('children'),
$this->isInstanceOf('Symfony\Component\Validator\Constraints\Valid')
);
return $classMetaData;
}
}