Create "Size" rule

This commit is contained in:
Henrique Moody 2015-06-15 23:55:09 -03:00
parent a3c945aa51
commit cc6da3a2e4
7 changed files with 301 additions and 0 deletions

View file

@ -17,6 +17,7 @@
"require-dev": {
"egulias/email-validator": "~1.2",
"malkusch/bav": "~1.0",
"mikey179/vfsStream": "^1.5",
"phpunit/phpunit": "~4.0",
"symfony/validator": "~2.6.9",
"zendframework/zend-validator": "~2.3"

43
docs/Size.md Normal file
View file

@ -0,0 +1,43 @@
# Size
- `v::size(string $minSize)`
- `v::size(string $minSize, string $maxSize)`
- `v::size(null, string $maxSize)`
Validates file sizes:
```php
v::size('1KB')->validate($filename); // Must have at least 1KB size
v::size('1MB', '2MB')->validate($filename); // Must have the size between 1MB and 2MB
v::size(null, '1GB')->validate($filename); // Must not be greater than 1GB
```
Sizes are not case-sensitive and the accepted values are:
- B
- KB
- MB
- GB
- TB
- PB
- EB
- ZB
- YB
This validator will consider `SplFileInfo` instances, like:
```php
$fileInfo = new SplFileInfo($filename);
v::size('1.5mb')->validate($fileInfo); // Will return true or false
```
Message template for this validator includes `{{minSize}}` and `{{maxSize}}`.
See also:
* [Executable](Executable.md)
* [File](File.md)
* [Readable](Readable.md)
* [SymbolicLink](SymbolicLink.md)
* [Uploaded](Uploaded.md)
* [Writable](Writable.md)

View file

@ -128,6 +128,7 @@
* [Exists](Exists.md)
* [File](File.md)
* [Readable](Readable.md)
* [Size](Size.md)
* [SymbolicLink](SymbolicLink.md)
* [Uploaded](Uploaded.md)
* [Writable](Writable.md)
@ -241,6 +242,7 @@
* [Regex](Regex.md)
* [Roman](Roman.md)
* [Sf](Sf.md)
* [Size](Size.md)
* [Slug](Slug.md)
* [Space](Space.md)
* [StartsWith](StartsWith.md)

View file

@ -0,0 +1,36 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
namespace Respect\Validation\Exceptions;
/**
* Exception class for Size rule.
*
* @author Henrique Moody <henriquemoody@gmail.com>
*/
class SizeException extends BetweenException
{
/**
* @var array
*/
public static $defaultTemplates = array(
self::MODE_DEFAULT => array(
self::BOTH => '{{name}} must be between {{minSize}} and {{maxSize}}',
self::LOWER => '{{name}} must be greater than {{minSize}}',
self::GREATER => '{{name}} must be lower than {{maxSize}}',
),
self::MODE_NEGATIVE => array(
self::BOTH => '{{name}} must not be between {{minSize}} and {{maxSize}}',
self::LOWER => '{{name}} must not be greater than {{minSize}}',
self::GREATER => '{{name}} must not be lower than {{maxSize}}',
),
);
}

96
library/Rules/Size.php Normal file
View file

@ -0,0 +1,96 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
namespace Respect\Validation\Rules;
use Respect\Validation\Exceptions\ComponentException;
use SplFileInfo;
/**
* Validate file size.
*
* @author Henrique Moody <henriquemoody@gmail.com>
*/
class Size extends Between
{
/**
* @var string
*/
public $minSize;
/**
* @var string
*/
public $maxSize;
/**
* @param string $minSize
* @param string $maxSize
*/
public function __construct($minSize = null, $maxSize = null)
{
$minSizeBytes = $minSize;
if (null !== $minSizeBytes) {
$minSizeBytes = $this->toBytes($minSize);
}
$this->minSize = $minSize;
$maxSizeBytes = $maxSize;
if (null !== $maxSizeBytes) {
$maxSizeBytes = $this->toBytes($maxSize);
}
$this->maxSize = $maxSize;
parent::__construct($minSizeBytes, $maxSizeBytes, true);
}
/**
* @todo Move it to a trait
*
* @param mixed $size
*
* @return int
*/
private function toBytes($size)
{
$value = $size;
$units = array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb');
foreach ($units as $exponent => $unit) {
if (!preg_match("/^(\d+(.\d+)?){$unit}$/i", $size, $matches)) {
continue;
}
$value = $matches[1] * pow(1024, $exponent);
break;
}
if (!is_numeric($value)) {
throw new ComponentException(sprintf('"%s" is not a recognized file size.', $size));
}
return $value;
}
/**
* {@inheritdoc}
*/
public function validate($input)
{
if ($input instanceof SplFileInfo) {
return parent::validate($input->getSize());
}
if (!is_string($input)) {
return false;
}
return parent::validate(filesize($input));
}
}

View file

@ -95,6 +95,7 @@ use Respect\Validation\Rules\AllOf;
* @method static Validator regex(string $regex)
* @method static Validator roman()
* @method static Validator sf(string $name, array $params = null)
* @method static Validator size(string $minSize = null, string $maxSize = null)
* @method static Validator slug()
* @method static Validator space(string $additionalChars = null)
* @method static Validator startsWith(mixed $startValue, bool $identical = false)

122
tests/Rules/SizeTest.php Normal file
View file

@ -0,0 +1,122 @@
<?php
/*
* This file is part of Respect/Validation.
*
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
*
* For the full copyright and license information, please view the "LICENSE.md"
* file that was distributed with this source code.
*/
namespace Respect\Validation\Rules;
use org\bovigo\vfs\content\LargeFileContent;
use org\bovigo\vfs\vfsStream;
use PHPUnit_Framework_TestCase;
use SplFileInfo;
/**
* @author Henrique Moody <henriquemoody@gmail.com>
*/
class SizeTest extends PHPUnit_Framework_TestCase
{
public function validSizeProvider()
{
return array(
array(42, 42),
array('1b', 1),
array('1kb', 1024),
array('1mb', 1048576),
array('1gb', 1073741824),
array('1tb', 1099511627776),
array('1pb', 1125899906842624),
array('1eb', 1152921504606846976),
array('1zb', 1.1805916207174113E+21),
array('1yb', 1.2089258196146292E+24),
);
}
public function validFileProvider()
{
$root = vfsStream::setup();
$file2Kb = vfsStream::newFile('2kb.txt')->withContent(LargeFileContent::withKilobytes(2))->at($root);
$file2Mb = vfsStream::newFile('2mb.txt')->withContent(LargeFileContent::withMegabytes(2))->at($root);
return array(
// Valid data
array($file2Kb->url(), '1kb', null, true),
array($file2Kb->url(), '2kb', null, true),
array($file2Kb->url(), null, '2kb', true),
array($file2Kb->url(), null, '3kb', true),
array($file2Kb->url(), '1kb', '3kb', true),
array($file2Mb->url(), '1mb', null, true),
array($file2Mb->url(), '2mb', null, true),
array($file2Mb->url(), null, '2mb', true),
array($file2Mb->url(), null, '3mb', true),
array($file2Mb->url(), '1mb', '3mb', true),
// Invalid data
array($file2Kb->url(), '3kb', null, false),
array($file2Kb->url(), null, '1kb', false),
array($file2Kb->url(), '1kb', '1.5kb', false),
array($file2Mb->url(), '2.5mb', null, false),
array($file2Mb->url(), '3gb', null, false),
array($file2Mb->url(), null, '1b', false),
array($file2Mb->url(), '1pb', '3pb', false),
);
}
/**
* @dataProvider validSizeProvider
*/
public function testShouldConvertUnitonConstructor($size, $bytes)
{
$rule = new Size($size);
$this->assertEquals($bytes, $rule->minValue);
}
/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage "42jb" is not a recognized file size
*/
public function testShouldThrowsAnExceptionWhenSizeIsNotValid()
{
new Size('42jb');
}
/**
* @dataProvider validFileProvider
*/
public function testShouldValidateFile($filename, $minSize, $maxSize, $expectedValidation)
{
$rule = new Size($minSize, $maxSize);
$this->assertEquals($expectedValidation, $rule->validate($filename));
}
public function testShouldValidateSplFileInfo()
{
$root = vfsStream::setup();
$file1Gb = vfsStream::newFile('1gb.txt')->withContent(LargeFileContent::withGigabytes(1))->at($root);
$file1GbObject = new SplFileInfo($file1Gb->url());
$rule = new Size('1MB', '2GB');
$this->assertTrue($rule->validate($file1GbObject));
}
/**
* @expectedException Respect\Validation\Exceptions\SizeException
* @expectedExceptionMessage "vfs://root/1gb.txt" must be greater than 2pb
*/
public function testShouldThrowsSizeExceptionWhenAsserting()
{
$root = vfsStream::setup();
$file1Gb = vfsStream::newFile('1gb.txt')->withContent(LargeFileContent::withGigabytes(1))->at($root);
$rule = new Size('2pb');
$rule->assert($file1Gb->url());
}
}