diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Employee.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Employee.php new file mode 100644 index 000000000000..24f08b00d781 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Employee.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping\Entity; + +/** @Entity */ +class Employee extends Person +{ +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Person.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Person.php new file mode 100644 index 000000000000..19a5d8b9569f --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Person.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping\DiscriminatorColumn; +use Doctrine\ORM\Mapping\DiscriminatorMap; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\InheritanceType; + +/** + * @Entity + * @InheritanceType("SINGLE_TABLE") + * @DiscriminatorColumn(name="discr", type="string") + * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) + */ +class Person +{ + /** @Id @Column(type="integer") */ + protected $id; + + /** @Column(type="string") */ + public $name; + + public function __construct($id, $name) + { + $this->id = $id; + $this->name = $name; + } + + public function __toString() + { + return (string) $this->name; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index f1f5bbdc9806..95abaa39884d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -16,6 +16,8 @@ use Doctrine\Common\Persistence\ObjectRepository; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\Employee; +use Symfony\Bridge\Doctrine\Tests\Fixtures\Person; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity; @@ -134,6 +136,8 @@ private function createSchema(ObjectManager $em) $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeIntIdEntity'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity'), + $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Person'), + $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Employee'), )); } @@ -459,4 +463,35 @@ public function testEntityManagerNullObject() $this->validator->validate($entity, $constraint); } + + public function testValidateInheritanceUniqueness() + { + $constraint = new UniqueEntity(array( + 'message' => 'myMessage', + 'fields' => array('name'), + 'em' => self::EM_NAME, + 'repository' => 'Symfony\Bridge\Doctrine\Tests\Fixtures\Person', + )); + + $entity1 = new Person(1, 'Foo'); + $entity2 = new Employee(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->buildViolation('myMessage') + ->atPath('property.path.name') + ->setInvalidValue('Foo') + ->assertRaised(); + } } diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php index fc6e213bd772..3dbbd82da4e6 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php @@ -26,6 +26,7 @@ class UniqueEntity extends Constraint public $message = 'This value is already used.'; public $service = 'doctrine.orm.validator.unique'; public $em = null; + public $repository = null; public $repositoryMethod = 'findBy'; public $fields = array(); public $errorPath = null; diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 6494adb91241..41f49dcefe0c 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -111,7 +111,27 @@ public function validate($entity, Constraint $constraint) } } - $repository = $em->getRepository(get_class($entity)); + if (null !== $constraint->repository) { + /* Retrieve repository from given entity name. + * We ensure the retrieved repository can handle the entity + * by checking the entity is the same, or subclass of the supported entity. + */ + $repository = $em->getRepository($constraint->repository); + $supportedClass = $repository->getClassName(); + + $className = $class->getName(); + + if (!($supportedClass === $className || is_subclass_of($className, $supportedClass))) { + throw new ConstraintDefinitionException(sprintf( + "Unable to use the given '%s' repository for the '%s' entity.", + get_class($repository), + $className + )); + } + } else { + $repository = $em->getRepository(get_class($entity)); + } + $result = $repository->{$constraint->repositoryMethod}($criteria); /* If the result is a MongoCursor, it must be advanced to the first