[FrameworkBundle] Implemented configuration to select the desired Validator API

This commit is contained in:
Bernhard Schussek 2014-03-18 17:36:12 +01:00
parent 0946dbe7a0
commit 9b204c9354
21 changed files with 264 additions and 103 deletions

View File

@ -19,15 +19,17 @@ class AddValidatorInitializersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('validator')) {
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);
}
$container->getDefinition('validator')->replaceArgument(4, $initializers);
$validatorBuilder->addMethodCall('addObjectInitializers', array($initializers));
}
}

View File

@ -444,8 +444,25 @@ class Configuration implements ConfigurationInterface
->children()
->scalarNode('cache')->end()
->booleanNode('enable_annotations')->defaultFalse()->end()
->arrayNode('static_method')
->defaultValue(array('loadClassMetadata'))
->prototype('scalar')->end()
->treatFalseLike(array())
->validate()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return (array) $v; })
->end()
->end()
->scalarNode('translation_domain')->defaultValue('validators')->end()
->booleanNode('strict_email')->defaultFalse()->end()
->enumNode('api')
->values(array('2.4', '2.5', '2.5-bc', 'auto'))
->defaultValue('auto')
->beforeNormalization()
->ifTrue(function ($v) { return is_scalar($v); })
->then(function ($v) { return (string) $v; })
->end()
->end()
->end()
->end()
->end()

View File

@ -21,6 +21,7 @@ use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Validator\Validation;
/**
* FrameworkExtension.
@ -674,27 +675,57 @@ class FrameworkExtension extends Extension
$loader->load('validator.xml');
$validatorBuilder = $container->getDefinition('validator.builder');
$container->setParameter('validator.translation_domain', $config['translation_domain']);
$container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $this->getValidatorXmlMappingFiles($container));
$container->setParameter('validator.mapping.loader.yaml_files_loader.mapping_files', $this->getValidatorYamlMappingFiles($container));
$xmlMappings = $this->getValidatorXmlMappingFiles($container);
$yamlMappings = $this->getValidatorYamlMappingFiles($container);
if (count($xmlMappings) > 0) {
$validatorBuilder->addMethodCall('addXmlMappings', array($xmlMappings));
}
if (count($yamlMappings) > 0) {
$validatorBuilder->addMethodCall('addYamlMappings', array($yamlMappings));
}
$definition = $container->findDefinition('validator.email');
$definition->replaceArgument(0, $config['strict_email']);
if (array_key_exists('enable_annotations', $config) && $config['enable_annotations']) {
$loaderChain = $container->getDefinition('validator.mapping.loader.loader_chain');
$arguments = $loaderChain->getArguments();
array_unshift($arguments[0], new Reference('validator.mapping.loader.annotation_loader'));
$loaderChain->setArguments($arguments);
$validatorBuilder->addMethodCall('enableAnnotations', array(new Reference('annotation_reader')));
}
if (array_key_exists('static_method', $config) && $config['static_method']) {
foreach ($config['static_method'] as $methodName) {
$validatorBuilder->addMethodCall('addMethodMapping', array($methodName));
}
}
if (isset($config['cache'])) {
$container->getDefinition('validator.mapping.class_metadata_factory')
->replaceArgument(1, new Reference('validator.mapping.cache.'.$config['cache']));
$container->setParameter(
'validator.mapping.cache.prefix',
'validator_'.hash('sha256', $container->getParameter('kernel.root_dir'))
);
$validatorBuilder->addMethodCall('setCache', array(new Reference('validator.mapping.cache.'.$config['cache'])));
}
if ('auto' !== $config['api']) {
switch ($config['api']) {
case '2.4':
$api = Validation::API_VERSION_2_4;
break;
case '2.5':
$api = Validation::API_VERSION_2_5;
break;
default:
$api = Validation::API_VERSION_2_5_BC;
break;
}
$validatorBuilder->addMethodCall('setApiVersion', array($api));
}
}

View File

@ -7,6 +7,14 @@
<xsd:element name="config" type="config" />
<xsd:simpleType name="validator_api_version">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="2.4" />
<xsd:enumeration value="2.5" />
<xsd:enumeration value="2.5-api" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="config">
<xsd:all>
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
@ -151,9 +159,15 @@
</xsd:complexType>
<xsd:complexType name="validation">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="static-method" type="xsd:string" />
</xsd:choice>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="static-method" type="xsd:boolean" />
<xsd:attribute name="api" type="validator_api_version" />
</xsd:complexType>
<xsd:complexType name="annotations">

View File

@ -5,35 +5,33 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="validator.class">Symfony\Component\Validator\Validator</parameter>
<parameter key="validator.class">Symfony\Component\Validator\ValidatorInterface</parameter>
<parameter key="validator.builder.class">Symfony\Component\Validator\ValidatorBuilderInterface</parameter>
<parameter key="validator.builder.factory.class">Symfony\Component\Validator\Validation</parameter>
<parameter key="validator.mapping.class_metadata_factory.class">Symfony\Component\Validator\Mapping\ClassMetadataFactory</parameter>
<parameter key="validator.mapping.cache.apc.class">Symfony\Component\Validator\Mapping\Cache\ApcCache</parameter>
<parameter key="validator.mapping.cache.prefix" />
<parameter key="validator.mapping.loader.loader_chain.class">Symfony\Component\Validator\Mapping\Loader\LoaderChain</parameter>
<parameter key="validator.mapping.loader.static_method_loader.class">Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader</parameter>
<parameter key="validator.mapping.loader.annotation_loader.class">Symfony\Component\Validator\Mapping\Loader\AnnotationLoader</parameter>
<parameter key="validator.mapping.loader.xml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\XmlFilesLoader</parameter>
<parameter key="validator.mapping.loader.yaml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\YamlFilesLoader</parameter>
<parameter key="validator.validator_factory.class">Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory</parameter>
<parameter key="validator.mapping.loader.xml_files_loader.mapping_files" type="collection" />
<parameter key="validator.mapping.loader.yaml_files_loader.mapping_files" type="collection" />
<parameter key="validator.expression.class">Symfony\Component\Validator\Constraints\ExpressionValidator</parameter>
<parameter key="validator.email.class">Symfony\Component\Validator\Constraints\EmailValidator</parameter>
</parameters>
<services>
<service id="validator" class="%validator.class%">
<argument type="service" id="validator.mapping.class_metadata_factory" />
<argument type="service" id="validator.validator_factory" />
<argument type="service" id="translator" />
<argument>%validator.translation_domain%</argument>
<argument type="collection" />
<service id="validator" class="%validator.class%" factory-service="validator.builder" factory-method="getValidator" />
<service id="validator.builder" class="%validator.builder.class%" factory-class="%validator.builder.factory.class%" factory-method="createValidatorBuilder" public="false">
<call method="setValidatorFactory">
<argument type="service" id="validator.validator_factory" />
</call>
<call method="setTranslator">
<argument type="service" id="translator" />
</call>
<call method="setTranslationDomain">
<argument>%validator.translation_domain%</argument>
</call>
</service>
<service id="validator.mapping.class_metadata_factory" class="%validator.mapping.class_metadata_factory.class%" public="false">
<argument type="service" id="validator.mapping.loader.loader_chain" />
<argument>null</argument>
</service>
<service id="validator.mapping.class_metadata_factory" alias="validator" public="false" />
<service id="validator.mapping.cache.apc" class="%validator.mapping.cache.apc.class%" public="false">
<argument>%validator.mapping.cache.prefix%</argument>
@ -44,28 +42,6 @@
<argument type="collection" />
</service>
<service id="validator.mapping.loader.loader_chain" class="%validator.mapping.loader.loader_chain.class%" public="false">
<argument type="collection">
<argument type="service" id="validator.mapping.loader.static_method_loader" />
<argument type="service" id="validator.mapping.loader.xml_files_loader" />
<argument type="service" id="validator.mapping.loader.yaml_files_loader" />
</argument>
</service>
<service id="validator.mapping.loader.static_method_loader" class="%validator.mapping.loader.static_method_loader.class%" public="false" />
<service id="validator.mapping.loader.annotation_loader" class="%validator.mapping.loader.annotation_loader.class%" public="false">
<argument type="service" id="annotation_reader" />
</service>
<service id="validator.mapping.loader.xml_files_loader" class="%validator.mapping.loader.xml_files_loader.class%" public="false">
<argument>%validator.mapping.loader.xml_files_loader.mapping_files%</argument>
</service>
<service id="validator.mapping.loader.yaml_files_loader" class="%validator.mapping.loader.yaml_files_loader.class%" public="false">
<argument>%validator.mapping.loader.yaml_files_loader.mapping_files%</argument>
</service>
<service id="validator.expression" class="%validator.expression.class%">
<argument type="service" id="property_accessor" />
<tag name="validator.constraint_validator" alias="validator.expression" />

View File

@ -126,8 +126,10 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
'validation' => array(
'enabled' => false,
'enable_annotations' => false,
'static_method' => array('loadClassMetadata'),
'translation_domain' => 'validators',
'strict_email' => false,
'api' => 'auto',
),
'annotations' => array(
'cache' => 'file',

View File

@ -0,0 +1,9 @@
<?php
$container->loadFromExtension('framework', array(
'secret' => 's3cr3t',
'validation' => array(
'enabled' => true,
'api' => '2.4',
),
));

View File

@ -0,0 +1,9 @@
<?php
$container->loadFromExtension('framework', array(
'secret' => 's3cr3t',
'validation' => array(
'enabled' => true,
'static_method' => array('loadFoo', 'loadBar'),
),
));

View File

@ -0,0 +1,9 @@
<?php
$container->loadFromExtension('framework', array(
'secret' => 's3cr3t',
'validation' => array(
'enabled' => true,
'static_method' => false,
),
));

View File

@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config secret="s3cr3t">
<framework:validation enabled="true" api="2.4" />
</framework:config>
</container>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config secret="s3cr3t">
<framework:validation enabled="true">
<framework:static-method>loadFoo</framework:static-method>
<framework:static-method>loadBar</framework:static-method>
</framework:validation>
</framework:config>
</container>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config secret="s3cr3t">
<framework:validation enabled="true" static-method="false" />
</framework:config>
</container>

View File

@ -0,0 +1,5 @@
framework:
secret: s3cr3t
validation:
enabled: true
api: 2.4

View File

@ -0,0 +1,5 @@
framework:
secret: s3cr3t
validation:
enabled: true
static_method: [loadFoo, loadBar]

View File

@ -0,0 +1,5 @@
framework:
secret: s3cr3t
validation:
enabled: true
static_method: false

View File

@ -15,6 +15,8 @@ use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Validator\Validation;
abstract class FrameworkExtensionTest extends TestCase
{
@ -257,17 +259,24 @@ abstract class FrameworkExtensionTest extends TestCase
{
$container = $this->createContainerFromFile('full');
$this->assertTrue($container->hasDefinition('validator'), '->registerValidationConfiguration() loads validator.xml');
$this->assertTrue($container->hasDefinition('validator.mapping.loader.xml_files_loader'), '->registerValidationConfiguration() defines the XML loader');
$this->assertTrue($container->hasDefinition('validator.mapping.loader.yaml_files_loader'), '->registerValidationConfiguration() defines the YAML loader');
$xmlFiles = $container->getParameter('validator.mapping.loader.xml_files_loader.mapping_files');
$ref = new \ReflectionClass('Symfony\Component\Form\Form');
$this->assertContains(
realpath(dirname($ref->getFileName()).'/Resources/config/validation.xml'),
array_map('realpath', $xmlFiles),
'->registerValidationConfiguration() adds Form validation.xml to XML loader'
);
$xmlMappings = array(realpath(dirname($ref->getFileName()).'/Resources/config/validation.xml'));
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
$this->assertCount(6, $calls);
$this->assertSame('setValidatorFactory', $calls[0][0]);
$this->assertEquals(array(new Reference('validator.validator_factory')), $calls[0][1]);
$this->assertSame('setTranslator', $calls[1][0]);
$this->assertEquals(array(new Reference('translator')), $calls[1][1]);
$this->assertSame('setTranslationDomain', $calls[2][0]);
$this->assertSame(array('%validator.translation_domain%'), $calls[2][1]);
$this->assertSame('addXmlMappings', $calls[3][0]);
$this->assertSame(array($xmlMappings), $calls[3][1]);
$this->assertSame('addMethodMapping', $calls[4][0]);
$this->assertSame(array('loadClassMetadata'), $calls[4][1]);
$this->assertSame('setCache', $calls[5][0]);
$this->assertEquals(array(new Reference('validator.mapping.cache.apc')), $calls[5][1]);
}
public function testAnnotations()
@ -289,15 +298,14 @@ abstract class FrameworkExtensionTest extends TestCase
{
$container = $this->createContainerFromFile('validation_annotations');
$this->assertTrue($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->registerValidationConfiguration() defines the annotation loader');
$loaders = $container->getDefinition('validator.mapping.loader.loader_chain')->getArgument(0);
$found = false;
foreach ($loaders as $loader) {
if ('validator.mapping.loader.annotation_loader' === (string) $loader) {
$found = true;
}
}
$this->assertTrue($found, 'validator.mapping.loader.annotation_loader is added to the loader chain.');
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
$this->assertCount(6, $calls);
$this->assertSame('enableAnnotations', $calls[4][0]);
$this->assertEquals(array(new Reference('annotation_reader')), $calls[4][1]);
$this->assertSame('addMethodMapping', $calls[5][0]);
$this->assertSame(array('loadClassMetadata'), $calls[5][1]);
// no cache this time
}
public function testValidationPaths()
@ -308,14 +316,49 @@ abstract class FrameworkExtensionTest extends TestCase
'kernel.bundles' => array('TestBundle' => 'Symfony\Bundle\FrameworkBundle\Tests\TestBundle'),
));
$yamlArgs = $container->getParameter('validator.mapping.loader.yaml_files_loader.mapping_files');
$this->assertCount(1, $yamlArgs);
$this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.yml', $yamlArgs[0]);
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
$xmlArgs = $container->getParameter('validator.mapping.loader.xml_files_loader.mapping_files');
$this->assertCount(2, $xmlArgs);
$this->assertStringEndsWith('Component'.DIRECTORY_SEPARATOR.'Form/Resources/config/validation.xml', $xmlArgs[0]);
$this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.xml', $xmlArgs[1]);
$this->assertCount(7, $calls);
$this->assertSame('addXmlMappings', $calls[3][0]);
$this->assertSame('addYamlMappings', $calls[4][0]);
$this->assertSame('enableAnnotations', $calls[5][0]);
$this->assertSame('addMethodMapping', $calls[6][0]);
$this->assertSame(array('loadClassMetadata'), $calls[6][1]);
$xmlMappings = $calls[3][1][0];
$this->assertCount(2, $xmlMappings);
$this->assertStringEndsWith('Component'.DIRECTORY_SEPARATOR.'Form/Resources/config/validation.xml', $xmlMappings[0]);
$this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.xml', $xmlMappings[1]);
$yamlMappings = $calls[4][1][0];
$this->assertCount(1, $yamlMappings);
$this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.yml', $yamlMappings[0]);
}
public function testValidationNoStaticMethod()
{
$container = $this->createContainerFromFile('validation_no_static_method');
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
$this->assertCount(4, $calls);
$this->assertSame('addXmlMappings', $calls[3][0]);
// no cache, no annotations, no static methods
}
public function testValidationApiVersion()
{
$container = $this->createContainerFromFile('validation_2_4_api');
$calls = $container->getDefinition('validator.builder')->getMethodCalls();
$this->assertCount(6, $calls);
$this->assertSame('addXmlMappings', $calls[3][0]);
$this->assertSame('addMethodMapping', $calls[4][0]);
$this->assertSame(array('loadClassMetadata'), $calls[4][1]);
$this->assertSame('setApiVersion', $calls[5][0]);
$this->assertSame(array(Validation::API_VERSION_2_4), $calls[5][1]);
// no cache, no annotations
}
public function testFormsCanBeEnabledWithoutCsrfProtection()

View File

@ -139,7 +139,7 @@ class ValidatorBuilderTest extends \PHPUnit_Framework_TestCase
$this->markTestSkipped('Not supported prior to PHP 5.3.9');
}
$this->assertSame($this->builder, $this->builder->setApiVersion(Validation::API_VERSION_2_4 | Validation::API_VERSION_2_5));
$this->assertSame($this->builder, $this->builder->setApiVersion(Validation::API_VERSION_2_5_BC));
$this->assertInstanceOf('Symfony\Component\Validator\Validator\LegacyValidator', $this->builder->getValidator());
}
}

View File

@ -28,6 +28,12 @@ final class Validation
*/
const API_VERSION_2_5 = 2;
/**
* The Validator API provided by Symfony 2.5 and newer with a backwards
* compatibility layer for 2.4 and older.
*/
const API_VERSION_2_5_BC = 3;
/**
* Creates a new validator.
*

View File

@ -22,9 +22,9 @@ use Symfony\Component\Validator\Exception\ValidatorException;
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.5, to be removed in Symfony 3.0.
* Use {@link Validator\TraversingValidator} instead.
* Use {@link Validator\RecursiveValidator} instead.
*/
class Validator implements ValidatorInterface
class Validator implements ValidatorInterface, Mapping\Factory\MetadataFactoryInterface
{
/**
* @var MetadataFactoryInterface
@ -82,6 +82,14 @@ class Validator implements ValidatorInterface
return $this->metadataFactory->getMetadataFor($value);
}
/**
* {@inheritDoc}
*/
public function hasMetadataFor($value)
{
return $this->metadataFactory->hasMetadataFor($value);
}
/**
* {@inheritDoc}
*/

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
/**
* Validates PHP values against constraints.
@ -21,7 +22,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* @since 2.5
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface ValidatorInterface
interface ValidatorInterface extends MetadataFactoryInterface
{
/**
* Validates a value against a constraint or a list of constraints.
@ -96,24 +97,4 @@ interface ValidatorInterface
* @return ContextualValidatorInterface The validator for that context
*/
public function inContext(ExecutionContextInterface $context);
/**
* Returns the metadata for an object.
*
* @param object $object The object
*
* @return \Symfony\Component\Validator\Mapping\MetadataInterface The metadata
*
* @throws \Symfony\Component\Validator\Exception\NoSuchMetadataException If no metadata exists
*/
public function getMetadataFor($object);
/**
* Returns whether the validator has metadata for an object.
*
* @param object $object The object
*
* @return Boolean Whether metadata exists for that object
*/
public function hasMetadataFor($object);
}

View File

@ -319,14 +319,14 @@ class ValidatorBuilder implements ValidatorBuilderInterface
*/
public function setApiVersion($apiVersion)
{
if (!($apiVersion & (Validation::API_VERSION_2_4 | Validation::API_VERSION_2_5))) {
if (!in_array($apiVersion, array(Validation::API_VERSION_2_4, Validation::API_VERSION_2_5, Validation::API_VERSION_2_5_BC))) {
throw new InvalidArgumentException(sprintf(
'The requested API version is invalid: "%s"',
$apiVersion
));
}
if (version_compare(PHP_VERSION, '5.3.9', '<') && $apiVersion === (Validation::API_VERSION_2_4 | Validation::API_VERSION_2_5)) {
if (version_compare(PHP_VERSION, '5.3.9', '<') && $apiVersion === Validation::API_VERSION_2_5_BC) {
throw new InvalidArgumentException(sprintf(
'The Validator API that is compatible with both Symfony 2.4 '.
'and Symfony 2.5 can only be used on PHP 5.3.9 and higher. '.
@ -403,7 +403,7 @@ class ValidatorBuilder implements ValidatorBuilderInterface
if (null === $apiVersion) {
$apiVersion = version_compare(PHP_VERSION, '5.3.9', '<')
? Validation::API_VERSION_2_4
: (Validation::API_VERSION_2_4 | Validation::API_VERSION_2_5);
: Validation::API_VERSION_2_5_BC;
}
if (Validation::API_VERSION_2_4 === $apiVersion) {