-
Notifications
You must be signed in to change notification settings - Fork 136
add IsCountable validator, to enforce type and count elements. #157
Changes from 1 commit
0ca7d66
dfca59b
0cfbeba
55e55e0
479f57c
5ba3cdd
6bb4397
9ec7f1a
149f6af
979bd6d
b23cd62
7b52198
fd8c3ed
687eb4a
7c1ee5e
6c60c41
af39b1a
609c866
388400f
33591b6
9d26add
92035a4
1a0717c
407ee84
6500014
bf7be0d
f012441
d7b8d55
9a7c40c
13f88a4
58da575
83aa8e5
4416265
ddcb7cd
e44ce14
7b3c9ac
8d4989d
809093c
d0316a1
6120357
af974c9
93601c7
e7355ab
f527802
9924700
b83a91f
1dc79e6
74b4711
88831e1
97d297c
03c12fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
<?php | ||
|
||
namespace Zend\Validator; | ||
|
||
use Zend\Validator\Exception\RuntimeException; | ||
|
||
class IsCountable extends AbstractValidator | ||
{ | ||
const NOT_COUNTABLE = 'notCountable'; | ||
const NOT_EQUALS = 'notEquals'; | ||
const GREATER_THAN = 'greaterThan'; | ||
const LESS_THAN = 'lessThan'; | ||
|
||
/** | ||
* Validation failure message template definitions | ||
* | ||
* @var array | ||
*/ | ||
protected $messageTemplates = [ | ||
self::NOT_COUNTABLE => "The input must be an array or an instance of \\Countable", | ||
self::NOT_EQUALS => "The input count must equal '%count%'", | ||
self::GREATER_THAN => "The input count must be less than '%max%', inclusively", | ||
self::LESS_THAN => "The input count must be greater than '%min%', inclusively", | ||
]; | ||
|
||
/** | ||
* Additional variables available for validation failure messages | ||
* | ||
* @var array | ||
*/ | ||
protected $messageVariables = [ | ||
'count' => ['options' => 'count'], | ||
'min' => ['options' => 'min'], | ||
'max' => ['options' => 'max'], | ||
]; | ||
|
||
/** | ||
* Options for the between validator | ||
* | ||
* @var array | ||
*/ | ||
protected $options = [ | ||
'count' => null, | ||
'min' => null, | ||
'max' => null, | ||
]; | ||
|
||
/** | ||
* Returns true if and only if $value is countable (and the count validates against optional values). | ||
* | ||
* @param string $value | ||
* @return bool | ||
* @throws Exception\RuntimeException | ||
*/ | ||
public function isValid($value) | ||
{ | ||
if (! (is_array($value) || $value instanceof \Countable)) { | ||
throw new RuntimeException($this->messageTemplates[self::NOT_COUNTABLE]); | ||
} | ||
|
||
$count = count($value); | ||
|
||
if (is_numeric($this->options['count'])) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd recommend using your There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, it looks like the validator will have different behavior based on whether |
||
if ($count != $this->options['count']) { | ||
$this->error(self::NOT_EQUALS); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
if (is_numeric($this->options['max']) && $count > $this->options['max']) { | ||
$this->error(self::GREATER_THAN); | ||
return false; | ||
} | ||
|
||
if (is_numeric($this->options['min']) && $count < $this->options['min']) { | ||
$this->error(self::LESS_THAN); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Returns the count option | ||
* | ||
* @return mixed | ||
*/ | ||
public function getCount() | ||
{ | ||
return $this->options['count']; | ||
} | ||
|
||
/** | ||
* Sets the count option | ||
* | ||
* @param int $count | ||
* @return self Provides a fluent interface | ||
*/ | ||
public function setCount($count) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the class offer setters? Once one of either |
||
{ | ||
$this->options['count'] = $count; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Returns the min option | ||
* | ||
* @return mixed | ||
*/ | ||
public function getMin() | ||
{ | ||
return $this->options['min']; | ||
} | ||
|
||
/** | ||
* Sets the min option | ||
* | ||
* @param int $min | ||
* @return self Provides a fluent interface | ||
*/ | ||
public function setMin($min) | ||
{ | ||
$this->options['min'] = $min; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Returns the max option | ||
* | ||
* @return mixed | ||
*/ | ||
public function getMax() | ||
{ | ||
return $this->options['max']; | ||
} | ||
|
||
/** | ||
* Sets the max option | ||
* | ||
* @param int $max | ||
* @return self Provides a fluent interface | ||
*/ | ||
public function setMax($max) | ||
{ | ||
$this->options['max'] = $max; | ||
return $this; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
|
||
namespace ZendTest\Validator; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Zend\Validator\IsCountable; | ||
|
||
class IsCountableTest extends TestCase | ||
{ | ||
/** @var IsCountable */ | ||
private $sut; | ||
|
||
protected function setUp() | ||
{ | ||
$this->sut = new IsCountable(); | ||
} | ||
|
||
public function testArrayIsValid() | ||
{ | ||
$this->sut->setMin(1); | ||
$this->sut->setMax(10); | ||
|
||
self::assertTrue($this->sut->isValid(['Foo']), json_encode($this->sut->getMessages())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Ocramius thinks something else 😜 |
||
self::assertCount(0, $this->sut->getMessages()); | ||
} | ||
|
||
public function testIteratorIsValid() | ||
{ | ||
self::assertTrue($this->sut->isValid(new \SplQueue()), json_encode($this->sut->getMessages())); | ||
self::assertCount(0, $this->sut->getMessages()); | ||
} | ||
|
||
public function testValidEquals() | ||
{ | ||
$this->sut->setCount(1); | ||
|
||
self::assertTrue($this->sut->isValid(['Foo'])); | ||
self::assertCount(0, $this->sut->getMessages()); | ||
} | ||
|
||
public function testValidMax() | ||
{ | ||
$this->sut->setMax(1); | ||
|
||
self::assertTrue($this->sut->isValid(['Foo'])); | ||
self::assertCount(0, $this->sut->getMessages()); | ||
} | ||
|
||
public function testValidMin() | ||
{ | ||
$this->sut->setMin(1); | ||
|
||
self::assertTrue($this->sut->isValid(['Foo'])); | ||
self::assertCount(0, $this->sut->getMessages()); | ||
} | ||
|
||
public function testInvalidNotEquals() | ||
{ | ||
$this->sut->setCount(2); | ||
|
||
self::assertFalse($this->sut->isValid(['Foo'])); | ||
self::assertCount(1, $this->sut->getMessages()); | ||
} | ||
|
||
/** | ||
* @expectedException \Zend\Validator\Exception\RuntimeException | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use the |
||
*/ | ||
public function testInvalidType() | ||
{ | ||
$this->sut->isValid(new \stdClass()); | ||
} | ||
|
||
public function testInvalidExceedsMax() | ||
{ | ||
$this->sut->setMax(1); | ||
|
||
self::assertFalse($this->sut->isValid(['Foo', 'Bar'])); | ||
self::assertCount(1, $this->sut->getMessages()); | ||
} | ||
|
||
public function testInvalidExceedsMin() | ||
{ | ||
$this->sut->setMin(2); | ||
|
||
self::assertFalse($this->sut->isValid(['Foo'])); | ||
self::assertCount(1, $this->sut->getMessages()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid input is not an exceptional case, and should instead be reported as a validation error. Use the
$this->error
construct and return false in this particular case.