feature #22081 [FrameworkBundle][Validator] Move Validator passes to the component (chalasr)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[FrameworkBundle][Validator] Move Validator passes to the component

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

Commits
-------

0b741da343 Move AddValidatorInitializersrPass & AddConstraintValidatorsPass to the Validator
This commit is contained in:
Fabien Potencier 2017-03-22 14:26:38 -07:00
commit c73009a996
14 changed files with 269 additions and 56 deletions

View File

@ -186,6 +186,14 @@ FrameworkBundle
* The `Symfony\Bundle\FrameworkBundle\Translation\Translator` constructor now takes the
default locale as 3rd argument. Not passing it will trigger an error in 4.0.
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass`
class has been deprecated and will be removed in 4.0.
Use the `Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass` class instead.
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass`
class has been deprecated and will be removed in 4.0.
Use the `Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass` class instead.
HttpFoundation
--------------

View File

@ -279,8 +279,13 @@ FrameworkBundle
* The `Symfony\Bundle\FrameworkBundle\Translation\Translator` constructor now takes the
default locale as mandatory 3rd argument.
HttpFoundation
---------------
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass` class has been
removed. Use the `Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass`
class instead.
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass` class has been
removed. Use the `Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass`
class instead.
HttpFoundation
--------------

View File

@ -40,6 +40,10 @@ CHANGELOG
making `Translator` works with any PSR-11 container
* Added `framework.serializer.mapping` config option allowing to define custom
serialization mapping files and directories
* Deprecated `AddValidatorInitializersPass`, use
`Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass` instead
* Deprecated `AddConstraintValidatorsPass`, use
`Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass` instead
3.2.0
-----

View File

@ -11,36 +11,13 @@
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass as BaseAddConstraintValidatorsPass;
class AddConstraintValidatorsPass implements CompilerPassInterface
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use %s instead.', AddConstraintValidatorsPass::class, BaseAddConstraintValidatorsPass::class), E_USER_DEPRECATED);
/**
* @deprecated since version 3.3, to be removed in 4.0. Use {@link BaseAddConstraintValidatorsPass} instead
*/
class AddConstraintValidatorsPass extends BaseAddConstraintValidatorsPass
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('validator.validator_factory')) {
return;
}
$validators = array();
foreach ($container->findTaggedServiceIds('validator.constraint_validator') as $id => $attributes) {
$definition = $container->getDefinition($id);
if ($definition->isAbstract()) {
continue;
}
if (isset($attributes[0]['alias'])) {
$validators[$attributes[0]['alias']] = new ServiceClosureArgument(new Reference($id));
}
$validators[$definition->getClass()] = new ServiceClosureArgument(new Reference($id));
}
$container->getDefinition('validator.validator_factory')->replaceArgument(0, (new Definition(ServiceLocator::class, array($validators)))->addTag('container.service_locator'));
}
}

View File

@ -11,25 +11,13 @@
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass as BaseAddValidatorsInitializerPass;
class AddValidatorInitializersPass implements CompilerPassInterface
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use %s instead.', AddValidatorInitializersPass::class, BaseAddValidatorsInitializerPass::class), E_USER_DEPRECATED);
/**
* @deprecated since version 3.3, to be removed in 4.0. Use {@link BaseAddValidatorInitializersPass} instead
*/
class AddValidatorInitializersPass extends BaseAddValidatorsInitializerPass
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('validator.builder')) {
return;
}
$validatorBuilder = $container->getDefinition('validator.builder');
$initializers = array();
foreach ($container->findTaggedServiceIds('validator.initializer') as $id => $attributes) {
$initializers[] = new Reference($id);
}
$validatorBuilder->addMethodCall('addObjectInitializers', array($initializers));
}
}

View File

@ -12,9 +12,7 @@
namespace Symfony\Bundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CacheCollectorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolClearerPass;
@ -47,6 +45,8 @@ use Symfony\Component\Form\DependencyInjection\FormPass;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
/**
* Bundle.
@ -84,9 +84,9 @@ class FrameworkBundle extends Bundle
// but as late as possible to get resolved parameters
$container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new TemplatingPass());
$container->addCompilerPass(new AddConstraintValidatorsPass(), PassConfig::TYPE_BEFORE_REMOVING);
$this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class, PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new AddValidatorInitializersPass());
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
$this->addCompilerPassIfExists($container, AddConsoleCommandPass::class);
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new LoggingTranslatorPass());

View File

@ -19,6 +19,9 @@ use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
/**
* @group legacy
*/
class AddConstraintValidatorsPassTest extends TestCase
{
public function testThatConstraintValidatorServicesAreProcessed()

View File

@ -16,7 +16,6 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
use Symfony\Bundle\FullStack;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
@ -41,6 +40,7 @@ use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
abstract class FrameworkExtensionTest extends TestCase
{

View File

@ -1,6 +1,12 @@
CHANGELOG
=========
3.3.0
-----
* added `AddValidatorInitializersPass`
* added `AddConstraintValidatorsPass`
3.2.0
-----

View File

@ -0,0 +1,62 @@
<?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\Validator\DependencyInjection;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
/**
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class AddConstraintValidatorsPass implements CompilerPassInterface
{
private $validatorFactoryServiceId;
private $constraintValidatorTag;
public function __construct($validatorFactoryServiceId = 'validator.validator_factory', $constraintValidatorTag = 'validator.constraint_validator')
{
$this->validatorFactoryServiceId = $validatorFactoryServiceId;
$this->constraintValidatorTag = $constraintValidatorTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->validatorFactoryServiceId)) {
return;
}
$validators = array();
foreach ($container->findTaggedServiceIds($this->constraintValidatorTag) as $id => $attributes) {
$definition = $container->getDefinition($id);
if ($definition->isAbstract()) {
continue;
}
if (isset($attributes[0]['alias'])) {
$validators[$attributes[0]['alias']] = new ServiceClosureArgument(new Reference($id));
}
$validators[$definition->getClass()] = new ServiceClosureArgument(new Reference($id));
}
$container
->getDefinition('validator.validator_factory')
->replaceArgument(0, (new Definition(ServiceLocator::class, array($validators)))->addTag('container.service_locator'))
;
}
}

View File

@ -0,0 +1,50 @@
<?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\Validator\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* @author Fabien Potencier <fabien@symfony.com>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class AddValidatorInitializersPass implements CompilerPassInterface
{
private $builderService;
private $initializerTag;
public function __construct($builderService = 'validator.builder', $initializerTag = 'validator.initializer')
{
$this->builderService = $builderService;
$this->initializerTag = $initializerTag;
}
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->builderService)) {
return;
}
$initializers = array();
foreach ($container->findTaggedServiceIds($this->initializerTag) as $id => $attributes) {
if ($container->getDefinition($id)->isAbstract()) {
continue;
}
$initializers[] = new Reference($id);
}
$container->getDefinition($this->builderService)->addMethodCall('addObjectInitializers', array($initializers));
}
}

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\Validator\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
class AddConstraintValidatorsPassTest extends TestCase
{
public function testThatConstraintValidatorServicesAreProcessed()
{
$container = new ContainerBuilder();
$validatorFactory = $container->register('validator.validator_factory')
->addArgument(array());
$container->register('my_constraint_validator_service1', Validator1::class)
->addTag('validator.constraint_validator', array('alias' => 'my_constraint_validator_alias1'));
$container->register('my_constraint_validator_service2', Validator2::class)
->addTag('validator.constraint_validator');
$container->register('my_abstract_constraint_validator')
->setAbstract(true)
->addTag('validator.constraint_validator');
$addConstraintValidatorsPass = new AddConstraintValidatorsPass();
$addConstraintValidatorsPass->process($container);
$this->assertEquals((new Definition(ServiceLocator::class, array(array(
Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')),
))))->addTag('container.service_locator'), $validatorFactory->getArgument(0));
}
public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition()
{
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock();
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->setMethods(array('hasDefinition', 'findTaggedServiceIds', 'getDefinition'))->getMock();
$container->expects($this->never())->method('findTaggedServiceIds');
$container->expects($this->never())->method('getDefinition');
$container->expects($this->atLeastOnce())
->method('hasDefinition')
->with('validator.validator_factory')
->will($this->returnValue(false));
$definition->expects($this->never())->method('replaceArgument');
$addConstraintValidatorsPass = new AddConstraintValidatorsPass();
$addConstraintValidatorsPass->process($container);
}
}

View File

@ -0,0 +1,44 @@
<?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\Validator\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
class AddValidatorInitializersPassTest extends TestCase
{
public function testProcess()
{
$container = new ContainerBuilder();
$container
->register('initializer1')
->addTag('validator.initializer')
;
$container
->register('initializer2')
->addTag('validator.initializer')
;
$container
->register('validator.builder')
->addArgument(array())
;
(new AddValidatorInitializersPass())->process($container);
$this->assertEquals(
array(array('addObjectInitializers', array(array(new Reference('initializer1'), new Reference('initializer2'))))),
$container->getDefinition('validator.builder')->getMethodCalls()
);
}
}

View File

@ -25,6 +25,7 @@
"symfony/intl": "^2.8.18|^3.2.5",
"symfony/yaml": "~3.3",
"symfony/config": "~2.8|~3.0",
"symfony/dependency-injection": "~3.3",
"symfony/expression-language": "~2.8|~3.0",
"symfony/cache": "~3.1",
"doctrine/annotations": "~1.0",
@ -33,6 +34,7 @@
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.3",
"symfony/yaml": "<3.3"
},
"suggest": {