diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 20d499f855..b037079365 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -28,6 +28,8 @@ CHANGELOG As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead. * [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference` are ignored for arrays now. Arrays are always traversed recursively. + * added dependency to Translation component + * violation messages are now translated with a TranslatorInterface implementation 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/ConstraintViolation.php b/src/Symfony/Component/Validator/ConstraintViolation.php index 7b6f1e1928..8f73d50c85 100644 --- a/src/Symfony/Component/Validator/ConstraintViolation.php +++ b/src/Symfony/Component/Validator/ConstraintViolation.php @@ -18,6 +18,11 @@ namespace Symfony\Component\Validator; */ class ConstraintViolation implements ConstraintViolationInterface { + /** + * @var string + */ + private $message; + /** * @var string */ @@ -56,6 +61,7 @@ class ConstraintViolation implements ConstraintViolationInterface /** * Creates a new constraint violation. * + * @param string $message The violation message. * @param string $messageTemplate The raw violation message. * @param array $messageParameters The parameters to substitute * in the raw message. @@ -70,8 +76,9 @@ class ConstraintViolation implements ConstraintViolationInterface * @param mixed $code The error code of the * violation, if any. */ - public function __construct($messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null) + public function __construct($message, $messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null) { + $this->message = $message; $this->messageTemplate = $messageTemplate; $this->messageParameters = $messageParameters; $this->messagePluralization = $messagePluralization; @@ -132,15 +139,7 @@ class ConstraintViolation implements ConstraintViolationInterface */ public function getMessage() { - $parameters = $this->messageParameters; - - foreach ($parameters as $i => $parameter) { - if (is_array($parameter)) { - $parameters[$i] = 'Array'; - } - } - - return strtr($this->messageTemplate, $parameters); + return $this->message; } /** diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php new file mode 100644 index 0000000000..850e0f1e16 --- /dev/null +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator; + +use Symfony\Component\Translation\TranslatorInterface; + +/** + * Simple translator implementation that simply replaces the parameters in + * the message IDs. + * + * Does not support translation domains or locales. + * + * @author Bernhard Schussek + */ +class DefaultTranslator implements TranslatorInterface +{ + /** + * {@inheritdoc} + */ + public function trans($id, array $parameters = array(), $domain = null, $locale = null) + { + return strtr($id, $parameters); + } + + /** + * {@inheritdoc} + */ + public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) + { + return strtr($id, $parameters); + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + throw new \BadMethodCallException('Unsupported method.'); + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + throw new \BadMethodCallException('Unsupported method.'); + } +} diff --git a/src/Symfony/Component/Validator/ExecutionContext.php b/src/Symfony/Component/Validator/ExecutionContext.php index bfcaba891f..864f749da8 100644 --- a/src/Symfony/Component/Validator/ExecutionContext.php +++ b/src/Symfony/Component/Validator/ExecutionContext.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Validator; +use Symfony\Component\Translation\TranslatorInterface; + /** * Default implementation of {@link ExecutionContextInterface}. * @@ -26,6 +28,16 @@ class ExecutionContext implements ExecutionContextInterface */ private $globalContext; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var MetadataInterface */ @@ -49,19 +61,23 @@ class ExecutionContext implements ExecutionContextInterface /** * Creates a new execution context. * - * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state. - * @param MetadataInterface $metadata The metadata of the validated node. - * @param mixed $value The value of the validated node. - * @param string $group The current validation group. - * @param string $propertyPath The property path to the current node. + * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state. + * @param TranslatorInterface $translator The translator for translating violation messages. + * @param null|string $translationDomain The domain of the validation messages. + * @param MetadataInterface $metadata The metadata of the validated node. + * @param mixed $value The value of the validated node. + * @param string $group The current validation group. + * @param string $propertyPath The property path to the current node. */ - public function __construct(GlobalExecutionContextInterface $globalContext, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '') + public function __construct(GlobalExecutionContextInterface $globalContext, TranslatorInterface $translator, $translationDomain = null, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '') { if (null === $group) { $group = Constraint::DEFAULT_GROUP; } $this->globalContext = $globalContext; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->metadata = $metadata; $this->value = $value; $this->propertyPath = $propertyPath; @@ -74,6 +90,9 @@ class ExecutionContext implements ExecutionContextInterface public function addViolation($message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null) { $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), @@ -103,6 +122,9 @@ class ExecutionContext implements ExecutionContextInterface trigger_error('addViolationAtPath() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED); $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), @@ -146,6 +168,9 @@ class ExecutionContext implements ExecutionContextInterface public function addViolationAt($subPath, $message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null) { $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), diff --git a/src/Symfony/Component/Validator/GraphWalker.php b/src/Symfony/Component/Validator/GraphWalker.php index 8af1a56153..ca212489a6 100644 --- a/src/Symfony/Component/Validator/GraphWalker.php +++ b/src/Symfony/Component/Validator/GraphWalker.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\MemberMetadata; @@ -39,6 +40,16 @@ class GraphWalker */ private $metadataFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -49,16 +60,20 @@ class GraphWalker * * @param ValidationVisitor $visitor * @param MetadataFactoryInterface $metadataFactory + * @param TranslatorInterface $translator + * @param null|string $translationDomain * @param array $validatedObjects * * @deprecated Deprecated since version 2.2, to be removed in 2.3. */ - public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, array &$validatedObjects = array()) + public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, TranslatorInterface $translator, $translationDomain = null, array &$validatedObjects = array()) { trigger_error('GraphWalker is deprecated since version 2.2 and will be removed in 2.3. This class has been replaced by ValidationVisitorInterface and MetadataInterface.', E_USER_DEPRECATED); $this->visitor = $visitor; $this->metadataFactory = $metadataFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->validatedObjects = &$validatedObjects; } @@ -208,6 +223,8 @@ class GraphWalker $context = new ExecutionContext( $this->visitor, + $this->translator, + $this->translationDomain, $metadata, $value, $group, diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php index f0d3e225a3..30d7ff0f64 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php @@ -129,6 +129,6 @@ EOF; protected function getViolation($message, $root = null, $propertyPath = null) { - return new ConstraintViolation($message, array(), $root, $propertyPath, null); + return new ConstraintViolation($message, $message, array(), $root, $propertyPath, null); } } diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php index f4b3652468..e1f06c2428 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php @@ -18,6 +18,7 @@ class ConstraintViolationTest extends \PHPUnit_Framework_TestCase public function testToStringHandlesArrays() { $violation = new ConstraintViolation( + 'Array', '{{ value }}', array('{{ value }}' => array(1, 2, 3)), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php b/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php index 40b5996646..467bdaaed7 100644 --- a/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php +++ b/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php @@ -19,11 +19,14 @@ use Symfony\Component\Validator\ExecutionContext; class ExecutionContextTest extends \PHPUnit_Framework_TestCase { + const TRANS_DOMAIN = 'trans_domain'; + private $visitor; private $violations; private $metadata; private $metadataFactory; private $globalContext; + private $translator; /** * @var ExecutionContext @@ -51,7 +54,8 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase $this->globalContext->expects($this->any()) ->method('getMetadataFactory') ->will($this->returnValue($this->metadataFactory)); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); } protected function tearDown() @@ -82,7 +86,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase { // BC $this->metadata = new ClassMetadata(__NAMESPACE__ . '\ExecutionContextTest_TestClass'); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); $this->assertSame(__NAMESPACE__ . '\ExecutionContextTest_TestClass', $this->context->getCurrentClass()); $this->assertNull($this->context->getCurrentProperty()); @@ -92,7 +96,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase { // BC $this->metadata = new PropertyMetadata(__NAMESPACE__ . '\ExecutionContextTest_TestClass', 'myProperty'); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); $this->assertSame(__NAMESPACE__ . '\ExecutionContextTest_TestClass', $this->context->getCurrentClass()); $this->assertSame('myProperty', $this->context->getCurrentProperty()); @@ -111,10 +115,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolation() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->context->addViolation('Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -126,10 +136,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolation('Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -141,21 +157,32 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo1' => 'bar1')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 1, array('foo2' => 'bar2')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" - $this->context->addViolation('Error', array('foo' => 'bar'), null); - $this->context->addViolation('Error', array('foo' => 'bar'), null, 1); + $this->context->addViolation('Error', array('foo1' => 'bar1'), null); + $this->context->addViolation('Choice error', array('foo2' => 'bar2'), null, 1); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', - array('foo' => 'bar'), + array('foo1' => 'bar1'), 'Root', 'foo.bar', null ), new ConstraintViolation( - 'Error', - array('foo' => 'bar'), + 'Translated choice error', + 'Choice error', + array('foo2' => 'bar2'), 'Root', 'foo.bar', null, @@ -166,11 +193,17 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPath() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + // override preconfigured property path $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -182,10 +215,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPathUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolationAtPath('bar.baz', 'Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -197,12 +236,22 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPathUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 3, array('foo' => 'bar')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), null); - $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), null, 1); + $this->context->addViolationAtPath('bar.baz', 'Choice error', array('foo' => 'bar'), null, 3); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -210,23 +259,30 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase null ), new ConstraintViolation( - 'Error', + 'Translated choice error', + 'Choice error', array('foo' => 'bar'), 'Root', 'bar.baz', null, - 1 + 3 ), )), $this->context->getViolations()); } public function testAddViolationAt() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + // override preconfigured property path $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -238,10 +294,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolationAt('bam.baz', 'Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -253,12 +315,22 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 2, array('foo' => 'bar')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), null); - $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), null, 1); + $this->context->addViolationAt('bam.baz', 'Choice error', array('foo' => 'bar'), null, 2); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -266,12 +338,13 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase null ), new ConstraintViolation( - 'Error', + 'Translated choice error', + 'Choice error', array('foo' => 'bar'), 'Root', 'foo.bar.bam.baz', null, - 1 + 2 ), )), $this->context->getViolations()); } @@ -293,7 +366,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testGetPropertyPathWithEmptyCurrentPropertyPath() { - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', ''); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', ''); $this->assertEquals('bam.baz', $this->context->getPropertyPath('bam.baz')); } diff --git a/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php b/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php index 83a67db3cd..1f8d6213c0 100644 --- a/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php +++ b/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Tests\Fixtures\ConstraintAValidator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ValidationVisitor; use Symfony\Component\Validator\Tests\Fixtures\Entity; use Symfony\Component\Validator\Tests\Fixtures\Reference; @@ -53,7 +54,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory()); + $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->walker = $this->visitor->getGraphWalker(); $this->metadata = new ClassMetadata(self::CLASSNAME); $this->metadataFactory->addMetadata($this->metadata); @@ -172,6 +173,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // validated $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -204,6 +206,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // "Default" was launched $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -231,6 +234,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // Only group "Second" was validated $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -285,6 +289,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -317,6 +322,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -350,6 +356,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -449,6 +456,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -515,6 +523,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'message', 'message', array('param' => 'value'), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php index 86fdbd5e95..1bbb33e26f 100644 --- a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Tests\Fixtures\Reference; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; @@ -49,7 +50,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory()); + $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->metadata = new ClassMetadata(self::CLASS_NAME); $this->metadataFactory->addMetadata($this->metadata); } @@ -154,6 +155,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // validated $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -187,6 +189,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // "Default" was launched $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -215,6 +218,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // Only group "Second" was validated $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -243,6 +247,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -251,6 +256,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -278,6 +284,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -286,6 +293,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -313,6 +321,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -321,6 +330,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -352,6 +362,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -414,6 +425,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -489,6 +501,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -497,6 +510,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // nothing generated by the reference! new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php b/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php index d963e4a848..d77d920704 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php @@ -96,8 +96,8 @@ class ValidatorBuilderTest extends \PHPUnit_Framework_TestCase public function testSetMetadataCache() { - $this->assertSame($this->builder, $this->builder->setMetadataCache($this->getMock( - 'Symfony\Component\Validator\Mapping\Cache\CacheInterface')) + $this->assertSame($this->builder, $this->builder->setMetadataCache( + $this->getMock('Symfony\Component\Validator\Mapping\Cache\CacheInterface')) ); } @@ -107,4 +107,16 @@ class ValidatorBuilderTest extends \PHPUnit_Framework_TestCase $this->getMock('Symfony\Component\Validator\ConstraintValidatorFactoryInterface')) ); } + + public function testSetTranslator() + { + $this->assertSame($this->builder, $this->builder->setTranslator( + $this->getMock('Symfony\Component\Translation\TranslatorInterface')) + ); + } + + public function testSetTranslationDomain() + { + $this->assertSame($this->builder, $this->builder->setTranslationDomain('TRANS_DOMAIN')); + } } diff --git a/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php b/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php index e10c2dad96..212a12cb47 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryAdapter; use Symfony\Component\Validator\ValidatorContext; @@ -57,6 +58,6 @@ class ValidatorContextTest extends \PHPUnit_Framework_TestCase ->setConstraintValidatorFactory($validatorFactory) ->getValidator(); - $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory), $validator); + $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory, new DefaultTranslator()), $validator); } } diff --git a/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php b/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php index 029678a8d4..8ab61cd581 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Tests; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryAdapter; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ValidatorContext; use Symfony\Component\Validator\ValidatorFactory; use Symfony\Component\Validator\ConstraintValidatorFactory; @@ -78,7 +79,7 @@ class ValidatorFactoryTest extends \PHPUnit_Framework_TestCase $validator = $this->factory->getValidator(); - $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory), $validator); + $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory, new DefaultTranslator()), $validator); } public function testBuildDefaultFromAnnotationsWithCustomNamespaces() diff --git a/src/Symfony/Component/Validator/Tests/ValidatorTest.php b/src/Symfony/Component/Validator/Tests/ValidatorTest.php index a2fccc684a..4d184aee3f 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\ConstraintValidatorFactory; @@ -37,7 +38,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); } protected function tearDown() @@ -59,6 +60,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // Only the constraint of group "Default" failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -82,6 +84,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // Only the constraint of group "Custom" failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -107,6 +110,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // The constraints of both groups failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -114,6 +118,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase '' )); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -141,6 +146,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -154,6 +160,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -198,6 +205,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase { $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), '', @@ -232,7 +240,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase ->method('getMetadataFor') ->with('VALUE') ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->validator->validateProperty('VALUE', 'someProperty'); } @@ -249,7 +257,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase ->method('getMetadataFor') ->with('VALUE') ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->validator->validatePropertyValue('VALUE', 'someProperty', 'propertyValue'); } diff --git a/src/Symfony/Component/Validator/ValidationVisitor.php b/src/Symfony/Component/Validator/ValidationVisitor.php index 1ef231ed1c..ad21eff74a 100644 --- a/src/Symfony/Component/Validator/ValidationVisitor.php +++ b/src/Symfony/Component/Validator/ValidationVisitor.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Exception\NoSuchMetadataException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Translation\TranslatorInterface; /** * Default implementation of {@link ValidationVisitorInterface} and @@ -37,6 +38,16 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo */ private $validatorFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -65,11 +76,13 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo * @param mixed $root The value passed to the validator. * @param MetadataFactoryInterface $metadataFactory The factory for obtaining metadata instances. * @param ConstraintValidatorFactoryInterface $validatorFactory The factory for creating constraint validators. + * @param TranslatorInterface $translator The translator for translating violation messages. + * @param string|null $translationDomain The domain of the translation messages. * @param ObjectInitializerInterface[] $objectInitializers The initializers for preparing objects before validation. * * @throws UnexpectedTypeException If any of the object initializers is not an instance of ObjectInitializerInterface */ - public function __construct($root, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = array()) + public function __construct($root, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, TranslatorInterface $translator, $translationDomain = null, array $objectInitializers = array()) { foreach ($objectInitializers as $initializer) { if (!$initializer instanceof ObjectInitializerInterface) { @@ -80,6 +93,8 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo $this->root = $root; $this->metadataFactory = $metadataFactory; $this->validatorFactory = $validatorFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->objectInitializers = $objectInitializers; $this->violations = new ConstraintViolationList(); } @@ -91,6 +106,8 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo { $context = new ExecutionContext( $this, + $this->translator, + $this->translationDomain, $metadata, $value, $group, @@ -161,7 +178,7 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo trigger_error('getGraphWalker() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED); if (null === $this->graphWalker) { - $this->graphWalker = new GraphWalker($this, $this->metadataFactory, $this->validatedObjects); + $this->graphWalker = new GraphWalker($this, $this->metadataFactory, $this->translator, $this->translationDomain, $this->validatedObjects); } return $this->graphWalker; diff --git a/src/Symfony/Component/Validator/Validator.php b/src/Symfony/Component/Validator/Validator.php index 848dc4e2ed..a700692d8d 100644 --- a/src/Symfony/Component/Validator/Validator.php +++ b/src/Symfony/Component/Validator/Validator.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Exception\ValidatorException; +use Symfony\Component\Translation\TranslatorInterface; /** * Default implementation of {@link ValidatorInterface}. @@ -32,6 +33,16 @@ class Validator implements ValidatorInterface */ private $validatorFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -40,11 +51,15 @@ class Validator implements ValidatorInterface public function __construct( MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, + TranslatorInterface $translator, + $translationDomain = null, array $objectInitializers = array() ) { $this->metadataFactory = $metadataFactory; $this->validatorFactory = $validatorFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->objectInitializers = $objectInitializers; } @@ -137,7 +152,7 @@ class Validator implements ValidatorInterface */ public function validateValue($value, $constraints, $groups = null) { - $context = new ExecutionContext($this->createVisitor(null)); + $context = new ExecutionContext($this->createVisitor(null), $this->translator, $this->translationDomain); $constraints = is_array($constraints) ? $constraints : array($constraints); @@ -176,7 +191,14 @@ class Validator implements ValidatorInterface */ private function createVisitor($root) { - return new ValidationVisitor($root, $this->metadataFactory, $this->validatorFactory, $this->objectInitializers); + return new ValidationVisitor( + $root, + $this->metadataFactory, + $this->validatorFactory, + $this->translator, + $this->translationDomain, + $this->objectInitializers + ); } /** diff --git a/src/Symfony/Component/Validator/ValidatorBuilder.php b/src/Symfony/Component/Validator/ValidatorBuilder.php index 8f39d4ae4d..8937042d44 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilder.php +++ b/src/Symfony/Component/Validator/ValidatorBuilder.php @@ -23,6 +23,7 @@ use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; use Symfony\Component\Validator\Mapping\Loader\YamlFilesLoader; use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader; use Symfony\Component\Validator\Mapping\Loader\XmlFilesLoader; +use Symfony\Component\Translation\TranslatorInterface; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\CachedReader; @@ -75,6 +76,16 @@ class ValidatorBuilder implements ValidatorBuilderInterface */ private $metadataCache; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * {@inheritdoc} */ @@ -254,6 +265,26 @@ class ValidatorBuilder implements ValidatorBuilderInterface return $this; } + /** + * {@inheritdoc} + */ + public function setTranslator(TranslatorInterface $translator) + { + $this->translator = $translator; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setTranslationDomain($translationDomain) + { + $this->translationDomain = $translationDomain; + + return $this; + } + /** * {@inheritdoc} */ @@ -296,7 +327,8 @@ class ValidatorBuilder implements ValidatorBuilderInterface } $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory(); + $translator = $this->translator ?: new DefaultTranslator(); - return new Validator($metadataFactory, $validatorFactory, $this->initializers); + return new Validator($metadataFactory, $validatorFactory, $translator, $this->translationDomain, $this->initializers); } } diff --git a/src/Symfony/Component/Validator/ValidatorBuilderInterface.php b/src/Symfony/Component/Validator/ValidatorBuilderInterface.php index 914d4f96d7..18b96eac36 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilderInterface.php +++ b/src/Symfony/Component/Validator/ValidatorBuilderInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Mapping\Cache\CacheInterface; +use Symfony\Component\Translation\TranslatorInterface; use Doctrine\Common\Annotations\Reader; /** @@ -139,6 +140,28 @@ interface ValidatorBuilderInterface */ public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory); + /** + * Sets the translator used for translating violation messages. + * + * @param TranslatorInterface $translator The translator instance. + * + * @return ValidatorBuilderInterface The builder object. + */ + public function setTranslator(TranslatorInterface $translator); + + /** + * Sets the default translation domain of violation messages. + * + * The same message can have different translations in different domains. + * Pass the domain that is used for violation messages by default to this + * method. + * + * @param string $translationDomain The translation domain of the violation messages. + * + * @return ValidatorBuilderInterface The builder object. + */ + public function setTranslationDomain($translationDomain); + /** * Builds and returns a new validator object. * diff --git a/src/Symfony/Component/Validator/ValidatorContext.php b/src/Symfony/Component/Validator/ValidatorContext.php index 9c8ec3d043..c5e9f34e0d 100644 --- a/src/Symfony/Component/Validator/ValidatorContext.php +++ b/src/Symfony/Component/Validator/ValidatorContext.php @@ -89,7 +89,8 @@ class ValidatorContext implements ValidatorContextInterface return new Validator( $this->metadataFactory, - $this->constraintValidatorFactory + $this->constraintValidatorFactory, + new DefaultTranslator() ); } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index e3cb106914..9c65253c8e 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/translation": "2.2.*" }, "require-dev": { "symfony/http-foundation": "2.2.*",