Skip to content

Commit

Permalink
[11.x] Adding minRatio & maxRatio rules on Dimension validation rules…
Browse files Browse the repository at this point in the history
…et (#52482)

* feat(dim-ratio): add min, max & range methods to Dimensions rule

* feat(dim-ratio): add logic for what makes a min or max failing ratio

* test(dim-ratio): add test for the new rules to the validator

* test(dim-ratio): add more tests for coverage for the new methods on the Dimension rule test

* test(dim-ratio): update condition where full ratio not provided in test (edge-case)

* chore: styleci fixes

* formatting

* test: added validation message test

* test: fixed naming

* chore: styleci fixes

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
CamKem and taylorotwell authored Sep 5, 2024
1 parent d8aabd9 commit ffa4d15
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 6 deletions.
54 changes: 48 additions & 6 deletions src/Illuminate/Validation/Concerns/ValidatesAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -740,12 +740,12 @@ public function validateDimensions($attribute, $value, $parameters)

$parameters = $this->parseNamedParameters($parameters);

if ($this->failsBasicDimensionChecks($parameters, $width, $height) ||
$this->failsRatioCheck($parameters, $width, $height)) {
return false;
}

return true;
return ! (
$this->failsBasicDimensionChecks($parameters, $width, $height) ||
$this->failsRatioCheck($parameters, $width, $height) ||
$this->failsMinRatioCheck($parameters, $width, $height) ||
$this->failsMaxRatioCheck($parameters, $width, $height)
);
}

/**
Expand Down Expand Up @@ -789,6 +789,48 @@ protected function failsRatioCheck($parameters, $width, $height)
return abs($numerator / $denominator - $width / $height) > $precision;
}

/**
* Determine if the given parameters fail a dimension minimum ratio check.
*
* @param array<string,string> $parameters
* @param int $width
* @param int $height
* @return bool
*/
private function failsMinRatioCheck($parameters, $width, $height)
{
if (! isset($parameters['min_ratio'])) {
return false;
}

[$minNumerator, $minDenominator] = array_replace(
[1, 1], array_filter(sscanf($parameters['min_ratio'], '%f/%d'))
);

return ($width / $height) > ($minNumerator / $minDenominator);
}

/**
* Determine if the given parameters fail a dimension maximum ratio check.
*
* @param array<string,string> $parameters
* @param int $width
* @param int $height
* @return bool
*/
private function failsMaxRatioCheck($parameters, $width, $height)
{
if (! isset($parameters['max_ratio'])) {
return false;
}

[$maxNumerator, $maxDenominator] = array_replace(
[1, 1], array_filter(sscanf($parameters['max_ratio'], '%f/%d'))
);

return ($width / $height) < ($maxNumerator / $maxDenominator);
}

/**
* Validate an attribute is unique among other values.
*
Expand Down
41 changes: 41 additions & 0 deletions src/Illuminate/Validation/Rules/Dimensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,47 @@ public function ratio($value)
return $this;
}

/**
* Set the minimum aspect ratio.
*
* @param float $value
* @return $this
*/
public function minRatio($value)
{
$this->constraints['min_ratio'] = $value;

return $this;
}

/**
* Set the maximum aspect ratio.
*
* @param float $value
* @return $this
*/
public function maxRatio($value)
{
$this->constraints['max_ratio'] = $value;

return $this;
}

/**
* Set the aspect ratio range.
*
* @param float $min
* @param float $max
* @return $this
*/
public function ratioBetween($min, $max)
{
$this->constraints['min_ratio'] = $min;
$this->constraints['max_ratio'] = $max;

return $this;
}

/**
* Convert the rule to a validation string.
*
Expand Down
35 changes: 35 additions & 0 deletions tests/Validation/ValidationDimensionsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace Illuminate\Tests\Validation;

use Illuminate\Http\UploadedFile;
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Dimensions;
use Illuminate\Validation\Validator;
use PHPUnit\Framework\TestCase;

class ValidationDimensionsRuleTest extends TestCase
Expand Down Expand Up @@ -38,5 +42,36 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule()
$rule->width('200');
});
$this->assertSame('dimensions:height=100', (string) $rule);

$rule = Rule::dimensions()
->minRatio(1 / 2)
->maxRatio(1 / 3);
$this->assertSame('dimensions:min_ratio=0.5,max_ratio=0.33333333333333', (string) $rule);

$rule = Rule::dimensions()
->ratioBetween(min: 1 / 2, max: 1 / 3);
$this->assertSame('dimensions:min_ratio=0.5,max_ratio=0.33333333333333', (string) $rule);
}

public function testGeneratesTheCorrectValidationMessages()
{
$rule = Rule::dimensions()
->width(100)->height(100)
->ratioBetween(min: 1 / 2, max: 2 / 5);

$trans = new Translator(new ArrayLoader, 'en');

$image = UploadedFile::fake();

$validator = new Validator(
$trans,
['image' => $image],
['image' => $rule]
);

$this->assertSame(
$trans->get('validation.dimensions', ['width' => 100, 'height' => 100, 'min_ratio' => 0.5, 'max_ratio' => 0.4]),
$validator->errors()->first('image')
);
}
}
56 changes: 56 additions & 0 deletions tests/Validation/ValidationImageFileRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,62 @@ public function testDimensionsWithCustomImageSizeMethod()
);
}

public function testDimentionWithTheRatioMethod()
{
$this->fails(
File::image()->dimensions(Rule::dimensions()->ratio(1)),
UploadedFile::fake()->image('foo.png', 105, 100),
['validation.dimensions'],
);

$this->passes(
File::image()->dimensions(Rule::dimensions()->ratio(1)),
UploadedFile::fake()->image('foo.png', 100, 100),
);
}

public function testDimentionWithTheMinRatioMethod()
{
$this->fails(
File::image()->dimensions(Rule::dimensions()->minRatio(1 / 2)),
UploadedFile::fake()->image('foo.png', 100, 100),
['validation.dimensions'],
);

$this->passes(
File::image()->dimensions(Rule::dimensions()->minRatio(1 / 2)),
UploadedFile::fake()->image('foo.png', 100, 200),
);
}

public function testDimentionWithTheMaxRatioMethod()
{
$this->fails(
File::image()->dimensions(Rule::dimensions()->maxRatio(1 / 2)),
UploadedFile::fake()->image('foo.png', 100, 300),
['validation.dimensions'],
);

$this->passes(
File::image()->dimensions(Rule::dimensions()->maxRatio(1 / 2)),
UploadedFile::fake()->image('foo.png', 100, 100),
);
}

public function testDimentionWithTheRatioBetweenMethod()
{
$this->fails(
File::image()->dimensions(Rule::dimensions()->ratioBetween(1 / 2, 1 / 3)),
UploadedFile::fake()->image('foo.png', 100, 100),
['validation.dimensions'],
);

$this->passes(
File::image()->dimensions(Rule::dimensions()->ratioBetween(1 / 2, 1 / 3)),
UploadedFile::fake()->image('foo.png', 100, 200),
);
}

protected function fails($rule, $values, $messages)
{
$this->assertValidationRules($rule, $values, false, $messages);
Expand Down
16 changes: 16 additions & 0 deletions tests/Validation/ValidationValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4953,6 +4953,14 @@ public function testValidateImageDimensions()
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=1']);
$this->assertTrue($v->fails());

// for min_ratio
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_ratio=1/2']);
$this->assertTrue($v->fails());

// for max_ratio
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_ratio=2/5']);
$this->assertTrue($v->passes());

// Knowing that demo image2.png has width = 4 and height = 2
$uploadedFile = new UploadedFile(__DIR__.'/fixtures/image2.png', '', null, null, true);
$trans = $this->getIlluminateArrayTranslator();
Expand Down Expand Up @@ -5010,6 +5018,14 @@ public function testValidateImageDimensions()
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:ratio=1']);
$this->assertFalse($v->passes());

// evaluates to (64 / 65) > (1 / 1.0) which is true/fails
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:min_ratio=1']);
$this->assertFalse($v->fails());

// evaluates to (64 / 65) < (1 / 1.0) which is false/passes
$v = new Validator($trans, ['x' => $uploadedFile], ['x' => 'dimensions:max_ratio=1']);
$this->assertFalse($v->passes());

// Knowing that demo image5.png has width = 1366 and height = 768
$uploadedFile = new UploadedFile(__DIR__.'/fixtures/image5.png', '', null, null, true);
$trans = $this->getIlluminateArrayTranslator();
Expand Down

0 comments on commit ffa4d15

Please sign in to comment.