[Validator] Added GroupSequenceProvider
This commit is contained in:
parent
2cd246786d
commit
6c4455fef7
@ -0,0 +1,31 @@
|
||||
<?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\Constraints;
|
||||
|
||||
/**
|
||||
* Annotation to define a group sequence provider
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class GroupSequenceProvider
|
||||
{
|
||||
/**
|
||||
* The name of the provider class
|
||||
* @var string
|
||||
*/
|
||||
public $class;
|
||||
|
||||
public function __construct(array $options)
|
||||
{
|
||||
$this->class = $options['value'];
|
||||
}
|
||||
}
|
@ -67,8 +67,13 @@ class GraphWalker
|
||||
$initializer->initialize($object);
|
||||
}
|
||||
|
||||
if ($group === Constraint::DEFAULT_GROUP && $metadata->hasGroupSequence()) {
|
||||
if ($group === Constraint::DEFAULT_GROUP && ($metadata->hasGroupSequence() || $metadata->hasGroupSequenceProvider())) {
|
||||
$groups = $metadata->getGroupSequence();
|
||||
|
||||
if ($groupSequenceProvider = $metadata->getGroupSequenceProvider()) {
|
||||
$groups = $groupSequenceProvider->getValidationGroups($object);
|
||||
}
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$this->walkObjectForGroup($metadata, $object, $group, $propertyPath, Constraint::DEFAULT_GROUP);
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Defines the interface for a group sequence provider.
|
||||
*/
|
||||
interface GroupSequenceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Returns which validation groups should be used for a certain state
|
||||
* of the object.
|
||||
*
|
||||
* @param mixed $object The object that is validated.
|
||||
*
|
||||
* @return array An array of validation groups
|
||||
*/
|
||||
function getValidationGroups($object);
|
||||
}
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Mapping;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\Exception\GroupDefinitionException;
|
||||
use Symfony\Component\Validator\GroupSequenceProviderInterface;
|
||||
|
||||
/**
|
||||
* Represents all the configured constraints on a given class.
|
||||
@ -29,6 +30,8 @@ class ClassMetadata extends ElementMetadata
|
||||
public $properties = array();
|
||||
public $getters = array();
|
||||
public $groupSequence = array();
|
||||
public $groupSequenceProviderClass;
|
||||
public $groupSequenceProvider;
|
||||
private $reflClass;
|
||||
|
||||
/**
|
||||
@ -57,6 +60,7 @@ class ClassMetadata extends ElementMetadata
|
||||
return array_merge(parent::__sleep(), array(
|
||||
'getters',
|
||||
'groupSequence',
|
||||
'groupSequenceProviderClass',
|
||||
'members',
|
||||
'name',
|
||||
'properties',
|
||||
@ -293,4 +297,66 @@ class ClassMetadata extends ElementMetadata
|
||||
|
||||
return $this->reflClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class name of the group sequence provider.
|
||||
*
|
||||
* @param string $class Sequence provider class name
|
||||
*/
|
||||
public function setGroupSequenceProviderClass($class)
|
||||
{
|
||||
$this->groupSequenceProviderClass = $class;
|
||||
$this->groupSequenceProvider = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the group sequence provider class.
|
||||
*
|
||||
* @return string Class name
|
||||
*/
|
||||
public function getGroupSequenceProviderClass()
|
||||
{
|
||||
return $this->groupSequenceProviderClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a group sequence provider is set.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasGroupSequenceProvider()
|
||||
{
|
||||
return $this->groupSequenceProviderClass || $this->groupSequenceProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group sequence provider if specified.
|
||||
*
|
||||
* @return GroupSequenceProviderInterface The provider or null
|
||||
*/
|
||||
public function getGroupSequenceProvider()
|
||||
{
|
||||
if (!$this->groupSequenceProvider && $this->groupSequenceProviderClass) {
|
||||
$reflClass = new \ReflectionClass($this->groupSequenceProviderClass);
|
||||
$interface = 'Symfony\Component\Validator\GroupSequenceProviderInterface';
|
||||
|
||||
if (!$reflClass->implementsInterface($interface)) {
|
||||
throw new \InvalidArgumentException(sprintf('The class "%s" must implement interface "%s".', $this->groupSequenceProviderClass, $interface));
|
||||
}
|
||||
|
||||
$this->groupSequenceProvider = $reflClass->newInstance();
|
||||
}
|
||||
|
||||
return $this->groupSequenceProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group sequence provider.
|
||||
*
|
||||
* @param GroupSequenceProviderInterface $provider Group sequence provider
|
||||
*/
|
||||
public function setGroupSequenceProvider(GroupSequenceProviderInterface $provider)
|
||||
{
|
||||
$this->groupSequenceProvider = $provider;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Doctrine\Common\Annotations\Reader;
|
||||
use Symfony\Component\Validator\Exception\MappingException;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequenceProvider;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
class AnnotationLoader implements LoaderInterface
|
||||
@ -38,6 +39,8 @@ class AnnotationLoader implements LoaderInterface
|
||||
foreach ($this->reader->getClassAnnotations($reflClass) as $constraint) {
|
||||
if ($constraint instanceof GroupSequence) {
|
||||
$metadata->setGroupSequence($constraint->groups);
|
||||
} elseif ($constraint instanceof GroupSequenceProvider) {
|
||||
$metadata->setGroupSequenceProviderClass($constraint->class);
|
||||
} elseif ($constraint instanceof Constraint) {
|
||||
$metadata->addConstraint($constraint);
|
||||
}
|
||||
|
@ -43,6 +43,10 @@ class XmlFileLoader extends FileLoader
|
||||
if (isset($this->classes[$metadata->getClassName()])) {
|
||||
$xml = $this->classes[$metadata->getClassName()];
|
||||
|
||||
foreach ($xml->{'group-sequence-provider'} as $provider) {
|
||||
$metadata->setGroupSequenceProviderClass($provider['class']);
|
||||
}
|
||||
|
||||
foreach ($this->parseConstraints($xml->constraint) as $constraint) {
|
||||
$metadata->addConstraint($constraint);
|
||||
}
|
||||
|
@ -54,6 +54,10 @@ class YamlFileLoader extends FileLoader
|
||||
if (isset($this->classes[$metadata->getClassName()])) {
|
||||
$yaml = $this->classes[$metadata->getClassName()];
|
||||
|
||||
if (isset($yaml['group_sequence_provider'])) {
|
||||
$metadata->setGroupSequenceProviderClass($yaml['group_sequence_provider']);
|
||||
}
|
||||
|
||||
if (isset($yaml['constraints'])) {
|
||||
foreach ($this->parseNodes($yaml['constraints']) as $constraint) {
|
||||
$metadata->addConstraint($constraint);
|
||||
|
@ -52,6 +52,7 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="group-sequence-provider" type="group-sequence-provider" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="constraint" type="constraint" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="getter" type="getter" minOccurs="0" maxOccurs="unbounded" />
|
||||
@ -59,6 +60,15 @@
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="group-sequence-provider">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Defines the name of the group sequence provider for a class.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="class" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="property">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
@ -10,6 +10,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
/**
|
||||
* @Symfony\Tests\Component\Validator\Fixtures\ConstraintA
|
||||
* @Assert\GroupSequence({"Foo", "Entity"})
|
||||
* @Assert\GroupSequenceProvider("Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider")
|
||||
*/
|
||||
class Entity extends EntityParent implements EntityInterface
|
||||
{
|
||||
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Tests\Component\Validator\Fixtures;
|
||||
|
||||
use Symfony\Component\Validator\GroupSequenceProviderInterface;
|
||||
|
||||
class GroupSequenceProvider implements GroupSequenceProviderInterface
|
||||
{
|
||||
protected $groups = array();
|
||||
|
||||
public function setGroups($groups)
|
||||
{
|
||||
$this->groups = $groups;
|
||||
}
|
||||
|
||||
public function getValidationGroups($object)
|
||||
{
|
||||
return $this->groups;
|
||||
}
|
||||
}
|
@ -18,11 +18,13 @@ use Symfony\Tests\Component\Validator\Fixtures\Entity;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\ConstraintA;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\ConstraintB;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\PropertyConstraint;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider;
|
||||
|
||||
require_once __DIR__.'/../Fixtures/Entity.php';
|
||||
require_once __DIR__.'/../Fixtures/ConstraintA.php';
|
||||
require_once __DIR__.'/../Fixtures/ConstraintB.php';
|
||||
require_once __DIR__.'/../Fixtures/PropertyConstraint.php';
|
||||
require_once __DIR__.'/../Fixtures/GroupSequenceProvider.php';
|
||||
|
||||
class ClassMetadataTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -189,5 +191,19 @@ class ClassMetadataTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->metadata->setGroupSequence(array('Foo', $this->metadata->getDefaultGroup(), Constraint::DEFAULT_GROUP));
|
||||
}
|
||||
}
|
||||
|
||||
public function testGroupSequenceProvider()
|
||||
{
|
||||
$this->assertNull($this->metadata->getGroupSequenceProvider());
|
||||
|
||||
$this->metadata->setGroupSequenceProviderClass('stdClass');
|
||||
|
||||
try {
|
||||
$this->metadata->getGroupSequenceProvider();
|
||||
$this->fail();
|
||||
} catch(\InvalidArgumentException $e) {}
|
||||
|
||||
$this->metadata->setGroupSequenceProviderClass('Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider');
|
||||
$this->assertTrue($this->metadata->getGroupSequenceProvider() instanceof GroupSequenceProvider);
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->setGroupSequenceProviderClass('Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider');
|
||||
|
||||
// load reflection class so that the comparison passes
|
||||
$expected->getReflectionClass();
|
||||
@ -137,6 +138,7 @@ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->setGroupSequenceProviderClass('Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider');
|
||||
|
||||
// load reflection class so that the comparison passes
|
||||
$expected->getReflectionClass();
|
||||
|
@ -67,6 +67,7 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->setGroupSequenceProviderClass('Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider');
|
||||
|
||||
$this->assertEquals($expected, $metadata);
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
'choices' => array('A', 'B'),
|
||||
)));
|
||||
$expected->addGetterConstraint('lastName', new NotNull());
|
||||
$expected->setGroupSequenceProviderClass('Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider');
|
||||
|
||||
$this->assertEquals($expected, $metadata);
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
<class name="Symfony\Tests\Component\Validator\Fixtures\Entity">
|
||||
|
||||
<!-- GROUP SEQUENCE PROVIDER -->
|
||||
<group-sequence-provider class="Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider" />
|
||||
|
||||
<!-- CLASS CONSTRAINTS -->
|
||||
|
||||
<!-- Custom constraint -->
|
||||
|
@ -2,6 +2,7 @@ namespaces:
|
||||
custom: Symfony\Tests\Component\Validator\Fixtures\
|
||||
|
||||
Symfony\Tests\Component\Validator\Fixtures\Entity:
|
||||
group_sequence_provider: Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider
|
||||
constraints:
|
||||
# Custom constraint
|
||||
- Symfony\Tests\Component\Validator\Fixtures\ConstraintA: ~
|
||||
|
@ -19,6 +19,7 @@ require_once __DIR__.'/Fixtures/FakeClassMetadataFactory.php';
|
||||
use Symfony\Tests\Component\Validator\Fixtures\Entity;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\FakeClassMetadataFactory;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\FailingConstraint;
|
||||
use Symfony\Tests\Component\Validator\Fixtures\GroupSequenceProvider;
|
||||
use Symfony\Component\Validator\Validator;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationList;
|
||||
@ -122,6 +123,52 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($violations, $result);
|
||||
}
|
||||
|
||||
public function testValidate_groupSequenceProvider()
|
||||
{
|
||||
$groupSequenceProvider = new GroupSequenceProvider;
|
||||
|
||||
$entity = new Entity();
|
||||
$metadata = new ClassMetadata(get_class($entity));
|
||||
$metadata->addPropertyConstraint('firstName', new FailingConstraint(array(
|
||||
'groups' => 'First',
|
||||
)));
|
||||
$metadata->addPropertyConstraint('lastName', new FailingConstraint(array(
|
||||
'groups' => 'Second',
|
||||
)));
|
||||
$metadata->setGroupSequenceProvider($groupSequenceProvider);
|
||||
$this->factory->addClassMetadata($metadata);
|
||||
|
||||
$violations = new ConstraintViolationList();
|
||||
$violations->add(new ConstraintViolation(
|
||||
'',
|
||||
array(),
|
||||
$entity,
|
||||
'firstName',
|
||||
''
|
||||
));
|
||||
|
||||
$groupSequenceProvider->setGroups(array('First'));
|
||||
$result = $this->validator->validate($entity);
|
||||
$this->assertEquals($violations, $result);
|
||||
|
||||
$violations = new ConstraintViolationList();
|
||||
$violations->add(new ConstraintViolation(
|
||||
'',
|
||||
array(),
|
||||
$entity,
|
||||
'lastName',
|
||||
''
|
||||
));
|
||||
|
||||
$groupSequenceProvider->setGroups(array('Second'));
|
||||
$result = $this->validator->validate($entity);
|
||||
$this->assertEquals($violations, $result);
|
||||
|
||||
$groupSequenceProvider->setGroups(array());
|
||||
$result = $this->validator->validate($entity);
|
||||
$this->assertEquals(new ConstraintViolationList(), $result);
|
||||
}
|
||||
|
||||
public function testValidateProperty()
|
||||
{
|
||||
$entity = new Entity();
|
||||
|
Reference in New Issue
Block a user