From 0c32fa012bf37d3cb2afd106dd9fad896104f8dd Mon Sep 17 00:00:00 2001 From: Luciano Mammino Date: Sun, 14 Jul 2013 19:03:22 +0200 Subject: [PATCH 1/5] improved image validator --- .../Component/Validator/Constraints/Image.php | 10 ++ .../Validator/Constraints/ImageValidator.php | 58 ++++++- .../Constraints/Fixtures/test_landscape.gif | Bin 0 -> 43 bytes .../Constraints/Fixtures/test_portrait.gif | Bin 0 -> 43 bytes .../Tests/Constraints/ImageValidatorTest.php | 141 ++++++++++++++++++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_landscape.gif create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_portrait.gif diff --git a/src/Symfony/Component/Validator/Constraints/Image.php b/src/Symfony/Component/Validator/Constraints/Image.php index a23106489f354..9fa8725c6da15 100644 --- a/src/Symfony/Component/Validator/Constraints/Image.php +++ b/src/Symfony/Component/Validator/Constraints/Image.php @@ -23,6 +23,11 @@ class Image extends File public $maxWidth = null; public $maxHeight = null; public $minHeight = null; + public $maxRatio = null; + public $minRatio = null; + public $allowSquare = true; + public $allowLandscape = true; + public $allowPortrait = true; public $mimeTypesMessage = 'This file is not a valid image.'; public $sizeNotDetectedMessage = 'The size of the image could not be detected.'; @@ -30,4 +35,9 @@ class Image extends File public $minWidthMessage = 'The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.'; public $maxHeightMessage = 'The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.'; public $minHeightMessage = 'The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.'; + public $maxRatioMessage = 'The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.'; + public $minRatioMessage = 'The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.'; + public $allowSquareMessage = 'The image is square ({{ width }}x{{ height }}px). Square images are not allowed.'; + public $allowLandscapeMessage = 'The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.'; + public $allowPortraitMessage = 'The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.'; } diff --git a/src/Symfony/Component/Validator/Constraints/ImageValidator.php b/src/Symfony/Component/Validator/Constraints/ImageValidator.php index 79e6bdcddbbb1..1f07845b0be6e 100644 --- a/src/Symfony/Component/Validator/Constraints/ImageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ImageValidator.php @@ -38,7 +38,9 @@ public function validate($value, Constraint $constraint) } if (null === $constraint->minWidth && null === $constraint->maxWidth - && null === $constraint->minHeight && null === $constraint->maxHeight) { + && null === $constraint->minHeight && null === $constraint->maxHeight + && null === $constraint->minRatio && null === $constraint->maxRatio + && $constraint->allowSquare && $constraint->allowLandscape && $constraint->allowPortrait) { return; } @@ -109,5 +111,59 @@ public function validate($value, Constraint $constraint) )); } } + + $ratio = $width/$height; + + if (null !== $constraint->minRatio) { + if (!is_numeric((string) $constraint->minRatio)) { + throw new ConstraintDefinitionException(sprintf('"%s" is not a valid minimum ratio', $constraint->minRatio)); + } + + if ($ratio < $constraint->minRatio) { + $this->context->addViolation($constraint->minRatioMessage, array( + '{{ ratio }}' => $ratio, + '{{ min_ratio }}' => $constraint->minRatio + )); + } + } + + if (null !== $constraint->maxRatio) { + if (!is_numeric((string) $constraint->maxRatio)) { + throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum ratio', $constraint->maxRatio)); + } + + if ($ratio > $constraint->maxRatio) { + $this->context->addViolation($constraint->maxRatioMessage, array( + '{{ ratio }}' => $ratio, + '{{ max_ratio }}' => $constraint->maxRatio + )); + } + } + + $isSquare = ($width == $height); + $isLandscape = ($width > $height); + $isPortrait = ($width < $height); + + if (!$constraint->allowSquare && $isSquare) { + $this->context->addViolation($constraint->allowSquareMessage, array( + '{{ width }}' => $width, + '{{ height }}' => $height + )); + } + + if (!$constraint->allowLandscape && $isLandscape) { + $this->context->addViolation($constraint->allowLandscapeMessage, array( + '{{ width }}' => $width, + '{{ height }}' => $height + )); + } + + if (!$constraint->allowPortrait && $isPortrait) { + $this->context->addViolation($constraint->allowPortraitMessage, array( + '{{ width }}' => $width, + '{{ height }}' => $height + )); + } + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_landscape.gif b/src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_landscape.gif new file mode 100644 index 0000000000000000000000000000000000000000..870123532c3b97be8e2ab75452eca7060fb474c4 GIT binary patch literal 43 qcmZ?wbhEHbWMW`sXkcLY4+e@qSs1y10y+#p0Fq%~V)Ef)um%7ZunH6a literal 0 HcmV?d00001 diff --git a/src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_portrait.gif b/src/Symfony/Component/Validator/Tests/Constraints/Fixtures/test_portrait.gif new file mode 100644 index 0000000000000000000000000000000000000000..cc480ca88ed7fa80ff8e3907ba14d692e3e9d3d4 GIT binary patch literal 43 rcmZ?wbhEHbWMp7sXkcLY4+e@qSs1w(7#VaJfB+=Jz{KRk#b6Bp7pw{t literal 0 HcmV?d00001 diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php index 88545016243d1..4fe4146e5295c 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php @@ -20,6 +20,8 @@ class ImageValidatorTest extends \PHPUnit_Framework_TestCase protected $validator; protected $path; protected $image; + protected $image_landscape; + protected $image_portrait; protected function setUp() { @@ -27,6 +29,8 @@ protected function setUp() $this->validator = new ImageValidator(); $this->validator->initialize($this->context); $this->image = __DIR__.'/Fixtures/test.gif'; + $this->image_landscape = __DIR__.'/Fixtures/test_landscape.gif'; + $this->image_portrait = __DIR__.'/Fixtures/test_portrait.gif'; } public function testNullIsValid() @@ -223,4 +227,141 @@ public function testInvalidMaxHeight() $this->validator->validate($this->image, $constraint); } + + public function testRatioTooSmall() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'minRatio' => 2, + 'minRatioMessage' => 'myMessage', + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ ratio }}' => 1, + '{{ min_ratio }}' => 2, + )); + + $this->validator->validate($this->image, $constraint); + } + + public function testRatioTooBig() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'maxRatio' => 0.5, + 'maxRatioMessage' => 'myMessage', + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ ratio }}' => 1, + '{{ max_ratio }}' => 0.5, + )); + + $this->validator->validate($this->image, $constraint); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testInvalidMinRatio() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'minRatio' => '1abc', + )); + + $this->validator->validate($this->image, $constraint); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testInvalidMaxRatio() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'maxRatio' => '1abc', + )); + + $this->validator->validate($this->image, $constraint); + } + + public function testSquareNotAllowed() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'allowSquare' => false, + 'allowSquareMessage' => 'myMessage', + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ width }}' => 2, + '{{ height }}' => 2, + )); + + $this->validator->validate($this->image, $constraint); + } + + public function testLandscapeNotAllowed() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'allowLandscape' => false, + 'allowLandscapeMessage' => 'myMessage', + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ width }}' => 2, + '{{ height }}' => 1, + )); + + $this->validator->validate($this->image_landscape, $constraint); + } + + public function testPortraitNotAllowed() + { + if (!class_exists('Symfony\Component\HttpFoundation\File\File')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $constraint = new Image(array( + 'allowPortrait' => false, + 'allowPortraitMessage' => 'myMessage', + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ width }}' => 1, + '{{ height }}' => 2, + )); + + $this->validator->validate($this->image_portrait, $constraint); + } } From 27083573f1ab3a58eb9078c3c2a727483b8ed037 Mon Sep 17 00:00:00 2001 From: Luciano Mammino Date: Mon, 15 Jul 2013 15:36:25 +0200 Subject: [PATCH 2/5] Fixed variable names --- .../Tests/Constraints/ImageValidatorTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php index 4fe4146e5295c..12cdbf0380544 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php @@ -20,8 +20,8 @@ class ImageValidatorTest extends \PHPUnit_Framework_TestCase protected $validator; protected $path; protected $image; - protected $image_landscape; - protected $image_portrait; + protected $imageLandscape; + protected $imagePortrait; protected function setUp() { @@ -29,8 +29,8 @@ protected function setUp() $this->validator = new ImageValidator(); $this->validator->initialize($this->context); $this->image = __DIR__.'/Fixtures/test.gif'; - $this->image_landscape = __DIR__.'/Fixtures/test_landscape.gif'; - $this->image_portrait = __DIR__.'/Fixtures/test_portrait.gif'; + $this->imageLandscape = __DIR__.'/Fixtures/test_landscape.gif'; + $this->imagePortrait = __DIR__.'/Fixtures/test_portrait.gif'; } public function testNullIsValid() @@ -341,7 +341,7 @@ public function testLandscapeNotAllowed() '{{ height }}' => 1, )); - $this->validator->validate($this->image_landscape, $constraint); + $this->validator->validate($this->imageLandscape, $constraint); } public function testPortraitNotAllowed() @@ -362,6 +362,6 @@ public function testPortraitNotAllowed() '{{ height }}' => 2, )); - $this->validator->validate($this->image_portrait, $constraint); + $this->validator->validate($this->imagePortrait, $constraint); } } From 0e90e9b029b07f2f327e5e1b4a81b1ccbb8578f4 Mon Sep 17 00:00:00 2001 From: Luciano Mammino Date: Sun, 21 Jul 2013 23:45:19 +0200 Subject: [PATCH 3/5] Code readability improvements --- .../Validator/Constraints/ImageValidator.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/ImageValidator.php b/src/Symfony/Component/Validator/Constraints/ImageValidator.php index 1f07845b0be6e..76ce8767fcea8 100644 --- a/src/Symfony/Component/Validator/Constraints/ImageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ImageValidator.php @@ -112,7 +112,7 @@ public function validate($value, Constraint $constraint) } } - $ratio = $width/$height; + $ratio = $width / $height; if (null !== $constraint->minRatio) { if (!is_numeric((string) $constraint->minRatio)) { @@ -140,25 +140,21 @@ public function validate($value, Constraint $constraint) } } - $isSquare = ($width == $height); - $isLandscape = ($width > $height); - $isPortrait = ($width < $height); - - if (!$constraint->allowSquare && $isSquare) { + if (!$constraint->allowSquare && $width == $height) { $this->context->addViolation($constraint->allowSquareMessage, array( '{{ width }}' => $width, '{{ height }}' => $height )); } - if (!$constraint->allowLandscape && $isLandscape) { + if (!$constraint->allowLandscape && $width > $height) { $this->context->addViolation($constraint->allowLandscapeMessage, array( '{{ width }}' => $width, '{{ height }}' => $height )); } - if (!$constraint->allowPortrait && $isPortrait) { + if (!$constraint->allowPortrait && $width < $height) { $this->context->addViolation($constraint->allowPortraitMessage, array( '{{ width }}' => $width, '{{ height }}' => $height From e72bb01ed434020795b3fd6e60bd7756faed57ae Mon Sep 17 00:00:00 2001 From: Luciano Mammino Date: Mon, 22 Jul 2013 01:48:29 +0200 Subject: [PATCH 4/5] Updated changelog --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 7ab8051c1a92b..1ea783d75b87e 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG `Symfony\Component\Validator\Constraints\` namespace and deprecated the original classes. * added comparison validators (EqualTo, NotEqualTo, LessThan, LessThanOrEqualTo, GreaterThan, GreaterThanOrEqualTo, IdenticalTo, NotIdenticalTo) + * added minRatio, maxRatio, allowSquare, allowLandscape, and allowPortrait to Image validator 2.2.0 ----- From 54a419ecc05d9bf430ec88ff1793a3dc5dc5d4b0 Mon Sep 17 00:00:00 2001 From: Luciano Mammino Date: Wed, 24 Jul 2013 17:04:01 +0200 Subject: [PATCH 5/5] Update CHANGELOG.md Fixed wrong version in changelog --- src/Symfony/Component/Validator/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 1ea783d75b87e..d874ed07deece 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +2.4.0 +----- + + * added `minRatio`, `maxRatio`, `allowSquare`, `allowLandscape`, and `allowPortrait` to Image validator + 2.3.0 ----- @@ -9,7 +14,6 @@ CHANGELOG `Symfony\Component\Validator\Constraints\` namespace and deprecated the original classes. * added comparison validators (EqualTo, NotEqualTo, LessThan, LessThanOrEqualTo, GreaterThan, GreaterThanOrEqualTo, IdenticalTo, NotIdenticalTo) - * added minRatio, maxRatio, allowSquare, allowLandscape, and allowPortrait to Image validator 2.2.0 -----