diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 5d903a12eb..efd9c54374 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -175,7 +175,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $this->buildViolation('myMessage') ->atPath('property.path.name') ->setParameter('{{ value }}', '"Foo"') - ->setInvalidValue('Foo') + ->setInvalidValue($entity2) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -200,7 +200,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $this->buildViolation('myMessage') ->atPath('property.path.bar') ->setParameter('{{ value }}', '"Foo"') - ->setInvalidValue('Foo') + ->setInvalidValue($entity2) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -419,7 +419,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', $entity1) + ->setParameter('{{ value }}', 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity") identified by (id => 1)') ->setInvalidValue($entity1) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -452,12 +452,12 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $this->validator->validate($associated2, $constraint); - $expectedValue = 'Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2" identified by "2"'; + $expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)'; $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', '"'.$expectedValue.'"') - ->setInvalidValue($expectedValue) + ->setParameter('{{ value }}', $expectedValue) + ->setInvalidValue($entity1) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -574,6 +574,11 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $objectOne = new SingleIntIdNoToStringEntity(1, 'foo'); $objectTwo = new SingleIntIdNoToStringEntity(2, 'bar'); + + $this->em->persist($objectOne); + $this->em->persist($objectTwo); + $this->em->flush(); + $entity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo); $this->em->persist($entity); @@ -583,12 +588,12 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest $this->validator->validate($newEntity, $constraint); - $expectedValue = 'Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity" identified by "(Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity" identified by "1"), (Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity" identified by "2")"'; + $expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)'; $this->buildViolation('myMessage') ->atPath('property.path.objectOne') - ->setParameter('{{ value }}', '"'.$expectedValue.'"') - ->setInvalidValue($expectedValue) + ->setParameter('{{ value }}', $expectedValue) + ->setInvalidValue($objectOne) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 68ea4a6709..16b74b98c3 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -129,36 +129,41 @@ class UniqueEntityValidator extends ConstraintValidator $errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0]; $invalidValue = isset($criteria[$errorPath]) ? $criteria[$errorPath] : $criteria[$fields[0]]; - if (is_object($invalidValue) && !method_exists($invalidValue, '__toString')) { - $invalidValue = $this->buildInvalidValueString($em, $class, $entity); - } - $this->context->buildViolation($constraint->message) ->atPath($errorPath) - ->setParameter('{{ value }}', $this->formatValue($invalidValue, static::OBJECT_TO_STRING | static::PRETTY_DATE)) + ->setParameter('{{ value }}', $this->formatWithIdentifiers($em, $class, $invalidValue)) ->setInvalidValue($invalidValue) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->addViolation(); } - /** - * @param ObjectManager $em - * @param ClassMetadata $class - * @param object $entity - * - * @return string - */ - private function buildInvalidValueString(ObjectManager $em, ClassMetadata $class, $entity) + private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, $value) { - $identifiers = array_map(function ($identifier) use ($em) { - // identifiers can be objects (without any __toString method) if its a composite PK - if (is_object($identifier) && !method_exists($identifier, '__toString')) { - return sprintf('(%s)', $this->buildInvalidValueString($em, $em->getClassMetadata(get_class($identifier)), $identifier)); + if (!is_object($value) || $value instanceof \DateTimeInterface) { + return $this->formatValue($value, self::PRETTY_DATE); + } + + // non unique value is a composite PK + if ($class->getName() !== $idClass = get_class($value)) { + $identifiers = $em->getClassMetadata($idClass)->getIdentifierValues($value); + } else { + $identifiers = $class->getIdentifierValues($value); + } + + if (!$identifiers) { + return sprintf('object("%s")', $idClass); + } + + array_walk($identifiers, function (&$id, $field) { + if (!is_object($id) || $id instanceof \DateTimeInterface) { + $idAsString = $this->formatValue($id, self::PRETTY_DATE); + } else { + $idAsString = sprintf('object("%s")', get_class($id)); } - return $identifier; - }, $class->getIdentifierValues($entity)); + $id = sprintf('%s => %s', $field, $idAsString); + }); - return sprintf('Object of class "%s" identified by "%s"', get_class($entity), implode(', ', $identifiers)); + return sprintf('object("%s") identified by (%s)', $idClass, implode(', ', $identifiers)); } }