Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Validator] improved image validator
  • Loading branch information
Luciano Mammino authored and fabpot committed Aug 2, 2013
1 parent 63e6368 commit b030624
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 1 deletion.
5 changes: 5 additions & 0 deletions 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
-----

Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Component/Validator/Constraints/Image.php
Expand Up @@ -23,11 +23,21 @@ 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.';
public $maxWidthMessage = 'The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.';
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.';
}
54 changes: 53 additions & 1 deletion src/Symfony/Component/Validator/Constraints/ImageValidator.php
Expand Up @@ -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;
}

Expand Down Expand Up @@ -109,5 +111,55 @@ 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
));
}
}

if (!$constraint->allowSquare && $width == $height) {
$this->context->addViolation($constraint->allowSquareMessage, array(
'{{ width }}' => $width,
'{{ height }}' => $height
));
}

if (!$constraint->allowLandscape && $width > $height) {
$this->context->addViolation($constraint->allowLandscapeMessage, array(
'{{ width }}' => $width,
'{{ height }}' => $height
));
}

if (!$constraint->allowPortrait && $width < $height) {
$this->context->addViolation($constraint->allowPortraitMessage, array(
'{{ width }}' => $width,
'{{ height }}' => $height
));
}

}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -20,13 +20,17 @@ class ImageValidatorTest extends \PHPUnit_Framework_TestCase
protected $validator;
protected $path;
protected $image;
protected $imageLandscape;
protected $imagePortrait;

protected function setUp()
{
$this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false);
$this->validator = new ImageValidator();
$this->validator->initialize($this->context);
$this->image = __DIR__.'/Fixtures/test.gif';
$this->imageLandscape = __DIR__.'/Fixtures/test_landscape.gif';
$this->imagePortrait = __DIR__.'/Fixtures/test_portrait.gif';
}

public function testNullIsValid()
Expand Down Expand Up @@ -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->imageLandscape, $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->imagePortrait, $constraint);
}
}

0 comments on commit b030624

Please sign in to comment.