bug #11582 [DoctrineBridge] Changed UniqueEntityValidator to use the 2.5 Validation API (webmozart)
This PR was merged into the 2.5 branch.
Discussion
----------
[DoctrineBridge] Changed UniqueEntityValidator to use the 2.5 Validation API
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #11578
| License | MIT
| Doc PR | -
Commits
-------
f45f1ab
[DoctrineBridge] Changed UniqueEntityValidator to use the 2.5 Validation API
This commit is contained in:
commit
8bedf86f31
@ -0,0 +1,26 @@
|
|||||||
|
<?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\Bridge\Doctrine\Tests\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Validation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.5.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class LegacyUniqueEntityValidator2Dot4ApiTest extends UniqueEntityValidatorTest
|
||||||
|
{
|
||||||
|
protected function getApiVersion()
|
||||||
|
{
|
||||||
|
return Validation::API_VERSION_2_4;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?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\Bridge\Doctrine\Tests\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Validation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.5.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class LegacyUniqueEntityValidatorLegacyApiTest extends UniqueEntityValidatorTest
|
||||||
|
{
|
||||||
|
protected function getApiVersion()
|
||||||
|
{
|
||||||
|
return Validation::API_VERSION_2_5_BC;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,445 @@
|
|||||||
|
<?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\Bridge\Doctrine\Tests\Validator\Constraints;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
use Doctrine\Common\Persistence\ObjectRepository;
|
||||||
|
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
|
||||||
|
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity;
|
||||||
|
use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest;
|
||||||
|
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
|
||||||
|
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity;
|
||||||
|
use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity;
|
||||||
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;
|
||||||
|
use Symfony\Component\Validator\Validation;
|
||||||
|
use Symfony\Component\Validator\Validator;
|
||||||
|
use Doctrine\ORM\Tools\SchemaTool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
|
||||||
|
{
|
||||||
|
const EM_NAME = 'foo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ManagerRegistry
|
||||||
|
*/
|
||||||
|
protected $registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ObjectRepository
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
protected function getApiVersion()
|
||||||
|
{
|
||||||
|
return Validation::API_VERSION_2_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->em = DoctrineTestHelper::createTestEntityManager();
|
||||||
|
$this->registry = $this->createRegistryMock($this->em);
|
||||||
|
$this->createSchema($this->em);
|
||||||
|
|
||||||
|
parent::setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createRegistryMock(ObjectManager $em = null)
|
||||||
|
{
|
||||||
|
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
||||||
|
$registry->expects($this->any())
|
||||||
|
->method('getManager')
|
||||||
|
->with($this->equalTo(self::EM_NAME))
|
||||||
|
->will($this->returnValue($em));
|
||||||
|
|
||||||
|
return $registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createRepositoryMock()
|
||||||
|
{
|
||||||
|
$repository = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectRepository')
|
||||||
|
->setMethods(array('findByCustom', 'find', 'findAll', 'findOneBy', 'findBy', 'getClassName'))
|
||||||
|
->getMock()
|
||||||
|
;
|
||||||
|
|
||||||
|
return $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createEntityManagerMock($repositoryMock)
|
||||||
|
{
|
||||||
|
$em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')
|
||||||
|
->getMock()
|
||||||
|
;
|
||||||
|
$em->expects($this->any())
|
||||||
|
->method('getRepository')
|
||||||
|
->will($this->returnValue($repositoryMock))
|
||||||
|
;
|
||||||
|
|
||||||
|
$classMetadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
|
||||||
|
$classMetadata
|
||||||
|
->expects($this->any())
|
||||||
|
->method('hasField')
|
||||||
|
->will($this->returnValue(true))
|
||||||
|
;
|
||||||
|
$reflParser = $this->getMockBuilder('Doctrine\Common\Reflection\StaticReflectionParser')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock()
|
||||||
|
;
|
||||||
|
$refl = $this->getMockBuilder('Doctrine\Common\Reflection\StaticReflectionProperty')
|
||||||
|
->setConstructorArgs(array($reflParser, 'property-name'))
|
||||||
|
->setMethods(array('getValue'))
|
||||||
|
->getMock()
|
||||||
|
;
|
||||||
|
$refl
|
||||||
|
->expects($this->any())
|
||||||
|
->method('getValue')
|
||||||
|
->will($this->returnValue(true))
|
||||||
|
;
|
||||||
|
$classMetadata->reflFields = array('name' => $refl);
|
||||||
|
$em->expects($this->any())
|
||||||
|
->method('getClassMetadata')
|
||||||
|
->will($this->returnValue($classMetadata))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $em;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createValidator()
|
||||||
|
{
|
||||||
|
return new UniqueEntityValidator($this->registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createSchema(ObjectManager $em)
|
||||||
|
{
|
||||||
|
$schemaTool = new SchemaTool($em);
|
||||||
|
$schemaTool->createSchema(array(
|
||||||
|
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity'),
|
||||||
|
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity'),
|
||||||
|
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'),
|
||||||
|
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a functional test as there is a large integration necessary to get the validator working.
|
||||||
|
*/
|
||||||
|
public function testValidateUniqueness()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, 'Foo');
|
||||||
|
$entity2 = new SingleIntIdEntity(2, 'Foo');
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
|
||||||
|
$this->validator->validate($entity2, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.name', 'Foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateCustomErrorPath()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
'errorPath' => 'bar',
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, 'Foo');
|
||||||
|
$entity2 = new SingleIntIdEntity(2, 'Foo');
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($entity2, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.bar', 'Foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateUniquenessWithNull()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, null);
|
||||||
|
$entity2 = new SingleIntIdEntity(2, null);
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->persist($entity2);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateUniquenessWithIgnoreNull()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name', 'name2'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
'ignoreNull' => false,
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new DoubleNameEntity(1, 'Foo', null);
|
||||||
|
$entity2 = new DoubleNameEntity(2, 'Foo', null);
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
|
||||||
|
$this->validator->validate($entity2, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.name', 'Foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateUniquenessAfterConsideringMultipleQueryResults()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, 'Foo');
|
||||||
|
$entity2 = new SingleIntIdEntity(2, 'Foo');
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->persist($entity2);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.name', 'Foo');
|
||||||
|
$this->context->getViolations()->remove(0);
|
||||||
|
|
||||||
|
$this->validator->validate($entity2, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.name', 'Foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateUniquenessUsingCustomRepositoryMethod()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
'repositoryMethod' => 'findByCustom',
|
||||||
|
));
|
||||||
|
|
||||||
|
$repository = $this->createRepositoryMock();
|
||||||
|
$repository->expects($this->once())
|
||||||
|
->method('findByCustom')
|
||||||
|
->will($this->returnValue(array()))
|
||||||
|
;
|
||||||
|
$this->em = $this->createEntityManagerMock($repository);
|
||||||
|
$this->registry = $this->createRegistryMock($this->em);
|
||||||
|
$this->validator = $this->createValidator();
|
||||||
|
$this->validator->initialize($this->context);
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, 'foo');
|
||||||
|
|
||||||
|
$this->validator->validate($entity1, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateUniquenessWithUnrewoundArray()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
'repositoryMethod' => 'findByCustom',
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity = new SingleIntIdEntity(1, 'foo');
|
||||||
|
|
||||||
|
$repository = $this->createRepositoryMock();
|
||||||
|
$repository->expects($this->once())
|
||||||
|
->method('findByCustom')
|
||||||
|
->will(
|
||||||
|
$this->returnCallback(function () use ($entity) {
|
||||||
|
$returnValue = array(
|
||||||
|
$entity,
|
||||||
|
);
|
||||||
|
next($returnValue);
|
||||||
|
|
||||||
|
return $returnValue;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
;
|
||||||
|
$this->em = $this->createEntityManagerMock($repository);
|
||||||
|
$this->registry = $this->createRegistryMock($this->em);
|
||||||
|
$this->validator = $this->createValidator();
|
||||||
|
$this->validator->initialize($this->context);
|
||||||
|
|
||||||
|
$this->validator->validate($entity, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group GH-1635
|
||||||
|
*/
|
||||||
|
public function testAssociatedEntity()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('single'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$entity1 = new SingleIntIdEntity(1, 'foo');
|
||||||
|
$associated = new AssociationEntity();
|
||||||
|
$associated->single = $entity1;
|
||||||
|
$associated2 = new AssociationEntity();
|
||||||
|
$associated2->single = $entity1;
|
||||||
|
|
||||||
|
$this->em->persist($entity1);
|
||||||
|
$this->em->persist($associated);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($associated, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
|
||||||
|
$this->em->persist($associated2);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($associated2, $constraint);
|
||||||
|
|
||||||
|
$this->assertViolation('myMessage', array(), 'property.path.single', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAssociatedEntityWithNull()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('single'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
'ignoreNull' => false,
|
||||||
|
));
|
||||||
|
|
||||||
|
$associated = new AssociationEntity();
|
||||||
|
$associated->single = null;
|
||||||
|
|
||||||
|
$this->em->persist($associated);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($associated, $constraint);
|
||||||
|
|
||||||
|
$this->assertNoViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
|
||||||
|
* @expectedExceptionMessage Associated entities are not allowed to have more than one identifier field
|
||||||
|
* @group GH-1635
|
||||||
|
*/
|
||||||
|
public function testAssociatedCompositeEntity()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('composite'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$composite = new CompositeIntIdEntity(1, 1, "test");
|
||||||
|
$associated = new AssociationEntity();
|
||||||
|
$associated->composite = $composite;
|
||||||
|
|
||||||
|
$this->em->persist($composite);
|
||||||
|
$this->em->persist($associated);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->validator->validate($associated, $constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
|
||||||
|
* @expectedExceptionMessage Object manager "foo" does not exist.
|
||||||
|
*/
|
||||||
|
public function testDedicatedEntityManagerNullObject()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
'em' => self::EM_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->em = null;
|
||||||
|
$this->registry = $this->createRegistryMock($this->em);
|
||||||
|
$this->validator = $this->createValidator();
|
||||||
|
$this->validator->initialize($this->context);
|
||||||
|
|
||||||
|
$entity = new SingleIntIdEntity(1, null);
|
||||||
|
|
||||||
|
$this->validator->validate($entity, $constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
|
||||||
|
* @expectedExceptionMessage Unable to find the object manager associated with an entity of class "Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity"
|
||||||
|
*/
|
||||||
|
public function testEntityManagerNullObject()
|
||||||
|
{
|
||||||
|
$constraint = new UniqueEntity(array(
|
||||||
|
'message' => 'myMessage',
|
||||||
|
'fields' => array('name'),
|
||||||
|
// no "em" option set
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->em = null;
|
||||||
|
$this->registry = $this->createRegistryMock($this->em);
|
||||||
|
$this->validator = $this->createValidator();
|
||||||
|
$this->validator->initialize($this->context);
|
||||||
|
|
||||||
|
$entity = new SingleIntIdEntity(1, null);
|
||||||
|
|
||||||
|
$this->validator->validate($entity, $constraint);
|
||||||
|
}
|
||||||
|
}
|
@ -1,424 +0,0 @@
|
|||||||
<?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\Bridge\Doctrine\Tests\Validator\Constraints;
|
|
||||||
|
|
||||||
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
|
|
||||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity;
|
|
||||||
use Symfony\Component\Validator\DefaultTranslator;
|
|
||||||
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
|
|
||||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
|
|
||||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity;
|
|
||||||
use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity;
|
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator;
|
|
||||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
|
||||||
use Symfony\Component\Validator\Validator;
|
|
||||||
use Doctrine\ORM\Tools\SchemaTool;
|
|
||||||
|
|
||||||
class UniqueValidatorTest extends \PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
protected function createRegistryMock($entityManagerName, $em)
|
|
||||||
{
|
|
||||||
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
|
||||||
$registry->expects($this->any())
|
|
||||||
->method('getManager')
|
|
||||||
->with($this->equalTo($entityManagerName))
|
|
||||||
->will($this->returnValue($em));
|
|
||||||
|
|
||||||
return $registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createRepositoryMock()
|
|
||||||
{
|
|
||||||
$repository = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectRepository')
|
|
||||||
->setMethods(array('findByCustom', 'find', 'findAll', 'findOneBy', 'findBy', 'getClassName'))
|
|
||||||
->getMock()
|
|
||||||
;
|
|
||||||
|
|
||||||
return $repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createEntityManagerMock($repositoryMock)
|
|
||||||
{
|
|
||||||
$em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')
|
|
||||||
->getMock()
|
|
||||||
;
|
|
||||||
$em->expects($this->any())
|
|
||||||
->method('getRepository')
|
|
||||||
->will($this->returnValue($repositoryMock))
|
|
||||||
;
|
|
||||||
|
|
||||||
$classMetadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
|
|
||||||
$classMetadata
|
|
||||||
->expects($this->any())
|
|
||||||
->method('hasField')
|
|
||||||
->will($this->returnValue(true))
|
|
||||||
;
|
|
||||||
$reflParser = $this->getMockBuilder('Doctrine\Common\Reflection\StaticReflectionParser')
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock()
|
|
||||||
;
|
|
||||||
$refl = $this->getMockBuilder('Doctrine\Common\Reflection\StaticReflectionProperty')
|
|
||||||
->setConstructorArgs(array($reflParser, 'property-name'))
|
|
||||||
->setMethods(array('getValue'))
|
|
||||||
->getMock()
|
|
||||||
;
|
|
||||||
$refl
|
|
||||||
->expects($this->any())
|
|
||||||
->method('getValue')
|
|
||||||
->will($this->returnValue(true))
|
|
||||||
;
|
|
||||||
$classMetadata->reflFields = array('name' => $refl);
|
|
||||||
$em->expects($this->any())
|
|
||||||
->method('getClassMetadata')
|
|
||||||
->will($this->returnValue($classMetadata))
|
|
||||||
;
|
|
||||||
|
|
||||||
return $em;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createValidatorFactory($uniqueValidator)
|
|
||||||
{
|
|
||||||
$validatorFactory = $this->getMock('Symfony\Component\Validator\ConstraintValidatorFactoryInterface');
|
|
||||||
$validatorFactory->expects($this->any())
|
|
||||||
->method('getInstance')
|
|
||||||
->with($this->isInstanceOf('Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity'))
|
|
||||||
->will($this->returnValue($uniqueValidator));
|
|
||||||
|
|
||||||
return $validatorFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createValidator($entityManagerName, $em, $validateClass = null, $uniqueFields = null, $errorPath = null, $repositoryMethod = 'findBy', $ignoreNull = true)
|
|
||||||
{
|
|
||||||
if (!$validateClass) {
|
|
||||||
$validateClass = 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity';
|
|
||||||
}
|
|
||||||
if (!$uniqueFields) {
|
|
||||||
$uniqueFields = array('name');
|
|
||||||
}
|
|
||||||
|
|
||||||
$registry = $this->createRegistryMock($entityManagerName, $em);
|
|
||||||
|
|
||||||
$uniqueValidator = new UniqueEntityValidator($registry);
|
|
||||||
|
|
||||||
$metadata = new ClassMetadata($validateClass);
|
|
||||||
$constraint = new UniqueEntity(array(
|
|
||||||
'fields' => $uniqueFields,
|
|
||||||
'em' => $entityManagerName,
|
|
||||||
'errorPath' => $errorPath,
|
|
||||||
'repositoryMethod' => $repositoryMethod,
|
|
||||||
'ignoreNull' => $ignoreNull
|
|
||||||
));
|
|
||||||
$metadata->addConstraint($constraint);
|
|
||||||
|
|
||||||
$metadataFactory = new FakeMetadataFactory();
|
|
||||||
$metadataFactory->addMetadata($metadata);
|
|
||||||
$validatorFactory = $this->createValidatorFactory($uniqueValidator);
|
|
||||||
|
|
||||||
return new Validator($metadataFactory, $validatorFactory, new DefaultTranslator());
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createSchema($em)
|
|
||||||
{
|
|
||||||
$schemaTool = new SchemaTool($em);
|
|
||||||
$schemaTool->createSchema(array(
|
|
||||||
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity'),
|
|
||||||
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity'),
|
|
||||||
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'),
|
|
||||||
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity'),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a functional test as there is a large integration necessary to get the validator working.
|
|
||||||
*/
|
|
||||||
public function testValidateUniqueness()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em);
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, 'Foo');
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), "No violations found on entity before it is saved to the database.");
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), "No violations found on entity after it was saved to the database.");
|
|
||||||
|
|
||||||
$entity2 = new SingleIntIdEntity(2, 'Foo');
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity2);
|
|
||||||
$this->assertEquals(1, $violationsList->count(), "Violation found on entity with conflicting entity existing in the database.");
|
|
||||||
|
|
||||||
$violation = $violationsList[0];
|
|
||||||
$this->assertEquals('This value is already used.', $violation->getMessage());
|
|
||||||
$this->assertEquals('name', $violation->getPropertyPath());
|
|
||||||
$this->assertEquals('Foo', $violation->getInvalidValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateCustomErrorPath()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, null, null, 'bar');
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, 'Foo');
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$entity2 = new SingleIntIdEntity(2, 'Foo');
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity2);
|
|
||||||
$this->assertEquals(1, $violationsList->count(), "Violation found on entity with conflicting entity existing in the database.");
|
|
||||||
|
|
||||||
$violation = $violationsList[0];
|
|
||||||
$this->assertEquals('This value is already used.', $violation->getMessage());
|
|
||||||
$this->assertEquals('bar', $violation->getPropertyPath());
|
|
||||||
$this->assertEquals('Foo', $violation->getInvalidValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateUniquenessWithNull()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em);
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, null);
|
|
||||||
$entity2 = new SingleIntIdEntity(2, null);
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->persist($entity2);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), "No violations found on entity having a null value.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateUniquenessWithIgnoreNull()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$validateClass = 'Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity';
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, $validateClass, array('name', 'name2'), 'bar', 'findby', false);
|
|
||||||
|
|
||||||
$entity1 = new DoubleNameEntity(1, 'Foo', null);
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), "No violations found on entity before it is saved to the database.");
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), "No violations found on entity after it was saved to the database.");
|
|
||||||
|
|
||||||
$entity2 = new DoubleNameEntity(2, 'Foo', null);
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity2);
|
|
||||||
$this->assertEquals(1, $violationsList->count(), "Violation found on entity with conflicting entity existing in the database.");
|
|
||||||
|
|
||||||
$violation = $violationsList[0];
|
|
||||||
$this->assertEquals('This value is already used.', $violation->getMessage());
|
|
||||||
$this->assertEquals('bar', $violation->getPropertyPath());
|
|
||||||
$this->assertEquals('Foo', $violation->getInvalidValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateUniquenessAfterConsideringMultipleQueryResults()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em);
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, 'foo');
|
|
||||||
$entity2 = new SingleIntIdEntity(2, 'foo');
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->persist($entity2);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(1, $violationsList->count(), 'Violation found on entity with conflicting entity existing in the database.');
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity2);
|
|
||||||
$this->assertEquals(1, $violationsList->count(), 'Violation found on entity with conflicting entity existing in the database.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateUniquenessUsingCustomRepositoryMethod()
|
|
||||||
{
|
|
||||||
$entityManagerName = 'foo';
|
|
||||||
$repository = $this->createRepositoryMock();
|
|
||||||
$repository->expects($this->once())
|
|
||||||
->method('findByCustom')
|
|
||||||
->will($this->returnValue(array()))
|
|
||||||
;
|
|
||||||
$em = $this->createEntityManagerMock($repository);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, null, array(), null, 'findByCustom');
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, 'foo');
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity1);
|
|
||||||
$this->assertEquals(0, $violationsList->count(), 'Violation is using custom repository method.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateUniquenessWithUnrewoundArray()
|
|
||||||
{
|
|
||||||
$entity = new SingleIntIdEntity(1, 'foo');
|
|
||||||
|
|
||||||
$entityManagerName = 'foo';
|
|
||||||
$repository = $this->createRepositoryMock();
|
|
||||||
$repository->expects($this->once())
|
|
||||||
->method('findByCustom')
|
|
||||||
->will(
|
|
||||||
$this->returnCallback(function () use ($entity) {
|
|
||||||
$returnValue = array(
|
|
||||||
$entity,
|
|
||||||
);
|
|
||||||
next($returnValue);
|
|
||||||
|
|
||||||
return $returnValue;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
;
|
|
||||||
$em = $this->createEntityManagerMock($repository);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, null, array(), null, 'findByCustom');
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($entity);
|
|
||||||
$this->assertCount(0, $violationsList, 'Violation is using unrewound array as return value in the repository method.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group GH-1635
|
|
||||||
*/
|
|
||||||
public function testAssociatedEntity()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, 'Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity', array('single'));
|
|
||||||
|
|
||||||
$entity1 = new SingleIntIdEntity(1, 'foo');
|
|
||||||
$associated = new AssociationEntity();
|
|
||||||
$associated->single = $entity1;
|
|
||||||
|
|
||||||
$em->persist($entity1);
|
|
||||||
$em->persist($associated);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($associated);
|
|
||||||
$this->assertEquals(0, $violationsList->count());
|
|
||||||
|
|
||||||
$associated2 = new AssociationEntity();
|
|
||||||
$associated2->single = $entity1;
|
|
||||||
|
|
||||||
$em->persist($associated2);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($associated2);
|
|
||||||
$this->assertEquals(1, $violationsList->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAssociatedEntityWithNull()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, 'Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity', array('single'), null, 'findBy', false);
|
|
||||||
|
|
||||||
$associated = new AssociationEntity();
|
|
||||||
$associated->single = null;
|
|
||||||
|
|
||||||
$em->persist($associated);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$violationsList = $validator->validate($associated);
|
|
||||||
$this->assertEquals(0, $violationsList->count());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group GH-1635
|
|
||||||
*/
|
|
||||||
public function testAssociatedCompositeEntity()
|
|
||||||
{
|
|
||||||
$entityManagerName = "foo";
|
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
|
||||||
$this->createSchema($em);
|
|
||||||
$validator = $this->createValidator($entityManagerName, $em, 'Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity', array('composite'));
|
|
||||||
|
|
||||||
$composite = new CompositeIntIdEntity(1, 1, "test");
|
|
||||||
$associated = new AssociationEntity();
|
|
||||||
$associated->composite = $composite;
|
|
||||||
|
|
||||||
$em->persist($composite);
|
|
||||||
$em->persist($associated);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$this->setExpectedException(
|
|
||||||
'Symfony\Component\Validator\Exception\ConstraintDefinitionException',
|
|
||||||
'Associated entities are not allowed to have more than one identifier field'
|
|
||||||
);
|
|
||||||
$violationsList = $validator->validate($associated);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDedicatedEntityManagerNullObject()
|
|
||||||
{
|
|
||||||
$uniqueFields = array('name');
|
|
||||||
$entityManagerName = 'foo';
|
|
||||||
|
|
||||||
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
|
||||||
|
|
||||||
$constraint = new UniqueEntity(array(
|
|
||||||
'fields' => $uniqueFields,
|
|
||||||
'em' => $entityManagerName,
|
|
||||||
));
|
|
||||||
|
|
||||||
$uniqueValidator = new UniqueEntityValidator($registry);
|
|
||||||
|
|
||||||
$entity = new SingleIntIdEntity(1, null);
|
|
||||||
|
|
||||||
$this->setExpectedException(
|
|
||||||
'Symfony\Component\Validator\Exception\ConstraintDefinitionException',
|
|
||||||
'Object manager "foo" does not exist.'
|
|
||||||
);
|
|
||||||
|
|
||||||
$uniqueValidator->validate($entity, $constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEntityManagerNullObject()
|
|
||||||
{
|
|
||||||
$uniqueFields = array('name');
|
|
||||||
|
|
||||||
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
|
||||||
|
|
||||||
$constraint = new UniqueEntity(array(
|
|
||||||
'fields' => $uniqueFields,
|
|
||||||
));
|
|
||||||
|
|
||||||
$uniqueValidator = new UniqueEntityValidator($registry);
|
|
||||||
|
|
||||||
$entity = new SingleIntIdEntity(1, null);
|
|
||||||
|
|
||||||
$this->setExpectedException(
|
|
||||||
'Symfony\Component\Validator\Exception\ConstraintDefinitionException',
|
|
||||||
'Unable to find the object manager associated with an entity of class "Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity"'
|
|
||||||
);
|
|
||||||
|
|
||||||
$uniqueValidator->validate($entity, $constraint);
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,6 +13,7 @@ namespace Symfony\Bridge\Doctrine\Validator\Constraints;
|
|||||||
|
|
||||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
@ -136,6 +137,14 @@ class UniqueEntityValidator extends ConstraintValidator
|
|||||||
|
|
||||||
$errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0];
|
$errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0];
|
||||||
|
|
||||||
$this->context->addViolationAt($errorPath, $constraint->message, array(), $criteria[$fields[0]]);
|
if ($this->context instanceof ExecutionContextInterface) {
|
||||||
|
$this->context->buildViolation($constraint->message)
|
||||||
|
->atPath($errorPath)
|
||||||
|
->setInvalidValue($criteria[$fields[0]])
|
||||||
|
->addViolation();
|
||||||
|
} else {
|
||||||
|
// 2.4 API
|
||||||
|
$this->context->addViolationAt($errorPath, $constraint->message, array(), $criteria[$fields[0]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ abstract class AbstractConstraintValidatorTest extends \PHPUnit_Framework_TestCa
|
|||||||
$violations = $this->context->getViolations();
|
$violations = $this->context->getViolations();
|
||||||
|
|
||||||
$this->assertCount(1, $violations);
|
$this->assertCount(1, $violations);
|
||||||
$this->assertEquals($this->createViolation($message, $parameters, $propertyPath, $invalidValue, $plural, $code), $violations[0]);
|
$this->assertEquals($this->createViolation($message, $parameters, $propertyPath, $invalidValue, $plural, $code), current(iterator_to_array($violations)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertViolations(array $expected)
|
protected function assertViolations(array $expected)
|
||||||
|
Reference in New Issue
Block a user