Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit bc72ba9

Browse files
committed
Throw an InvalidArgumentException when one attempts to create a
DateTime, Date, Month element with 'min' or 'max' string specification(s) that does not conform to the expected \DateTime format for the given element rather than mysteriously fail when given valid data on input.
1 parent b0d470c commit bc72ba9

File tree

11 files changed

+237
-22
lines changed

11 files changed

+237
-22
lines changed

src/Element/Date.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
class Date extends DateTimeElement
1818
{
19+
20+
const DATETIME_FORMAT = 'Y-m-d';
21+
1922
/**
2023
* Seed attributes
2124
*

src/Element/DateTime.php

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use DateInterval;
1313
use DateTime as PhpDateTime;
1414
use Zend\Form\Element;
15+
use Zend\Form\Exception\InvalidArgumentException;
1516
use Zend\InputFilter\InputProviderInterface;
1617
use Zend\Validator\Date as DateValidator;
1718
use Zend\Validator\DateStep as DateStepValidator;
@@ -120,17 +121,60 @@ protected function getValidators()
120121
$validators = [];
121122
$validators[] = $this->getDateValidator();
122123

123-
if (isset($this->attributes['min'])) {
124-
$validators[] = new GreaterThanValidator([
125-
'min' => $this->attributes['min'],
126-
'inclusive' => true,
127-
]);
124+
if (isset($this->attributes['min']) &&
125+
\DateTime::createFromFormat(
126+
static::DATETIME_FORMAT,
127+
$this->attributes['min']
128+
) instanceof \DateTimeInterface
129+
) {
130+
$validators[] = new GreaterThanValidator(
131+
[
132+
'min' => $this->attributes['min'],
133+
'inclusive' => true,
134+
]
135+
);
136+
} elseif (isset($this->attributes['min']) &&
137+
! \DateTime::createFromFormat(
138+
static::DATETIME_FORMAT,
139+
$this->attributes['min']
140+
) instanceof \DateTimeInterface
141+
) {
142+
throw new InvalidArgumentException(
143+
sprintf(
144+
'%1$s expects "min" to conform to %2$s; received "%3$s"',
145+
__METHOD__,
146+
static::DATETIME_FORMAT,
147+
$this->attributes['min']
148+
)
149+
);
128150
}
129-
if (isset($this->attributes['max'])) {
130-
$validators[] = new LessThanValidator([
131-
'max' => $this->attributes['max'],
151+
152+
if (isset($this->attributes['max']) &&
153+
\DateTime::createFromFormat(
154+
static::DATETIME_FORMAT,
155+
$this->attributes['max']
156+
) instanceof \DateTimeInterface
157+
) {
158+
$validators[] = new LessThanValidator(
159+
[
160+
'max' => $this->attributes['max'],
132161
'inclusive' => true,
133-
]);
162+
]
163+
);
164+
} elseif (isset($this->attributes['max']) &&
165+
! \DateTime::createFromFormat(
166+
static::DATETIME_FORMAT,
167+
$this->attributes['max']
168+
) instanceof \DateTimeInterface
169+
) {
170+
throw new InvalidArgumentException(
171+
sprintf(
172+
'%1$s expects "max" to conform to %2$s; received "%3$s"',
173+
__METHOD__,
174+
static::DATETIME_FORMAT,
175+
$this->attributes['max']
176+
)
177+
);
134178
}
135179
if (! isset($this->attributes['step'])
136180
|| 'any' !== $this->attributes['step']
@@ -145,7 +189,7 @@ protected function getValidators()
145189
/**
146190
* Retrieves a Date Validator configured for a DateTime Input type
147191
*
148-
* @return DateTime
192+
* @return DateValidator
149193
*/
150194
protected function getDateValidator()
151195
{
@@ -155,7 +199,7 @@ protected function getDateValidator()
155199
/**
156200
* Retrieves a DateStep Validator configured for a DateTime Input type
157201
*
158-
* @return DateTime
202+
* @return DateStepValidator
159203
*/
160204
protected function getStepValidator()
161205
{

src/Element/DateTimeLocal.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
class DateTimeLocal extends DateTime
1515
{
16+
1617
const DATETIME_LOCAL_FORMAT = 'Y-m-d\TH:i';
1718

19+
const DATETIME_FORMAT = self::DATETIME_LOCAL_FORMAT;
20+
1821
/**
1922
* Seed attributes
2023
*

src/Element/Month.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
class Month extends DateTime
1717
{
18+
19+
const DATETIME_FORMAT = 'Y-m';
20+
1821
/**
1922
* Seed attributes
2023
*

src/Element/Time.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
class Time extends DateTime
1616
{
17+
18+
const DATETIME_FORMAT = 'H:i:s';
19+
1720
/**
1821
* Seed attributes
1922
*

src/Element/Week.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
use Zend\Validator\DateStep as DateStepValidator;
1313
use Zend\Validator\Regex as RegexValidator;
14+
use Zend\Validator\GreaterThan as GreaterThanValidator;
15+
use Zend\Validator\LessThan as LessThanValidator;
1416

1517
class Week extends DateTime
1618
{
@@ -52,4 +54,36 @@ protected function getStepValidator()
5254
'step' => new \DateInterval("P{$stepValue}W"),
5355
]);
5456
}
57+
58+
/**
59+
* @see https://bugs.php.net/bug.php?id=74511
60+
* @return array
61+
*/
62+
protected function getValidators()
63+
{
64+
if ($this->validators) {
65+
return $this->validators;
66+
}
67+
$validators = [];
68+
$validators[] = $this->getDateValidator();
69+
if (isset($this->attributes['min'])) {
70+
$validators[] = new GreaterThanValidator([
71+
'min' => $this->attributes['min'],
72+
'inclusive' => true,
73+
]);
74+
}
75+
if (isset($this->attributes['max'])) {
76+
$validators[] = new LessThanValidator([
77+
'max' => $this->attributes['max'],
78+
'inclusive' => true,
79+
]);
80+
}
81+
if (! isset($this->attributes['step'])
82+
|| 'any' !== $this->attributes['step']
83+
) {
84+
$validators[] = $this->getStepValidator();
85+
}
86+
$this->validators = $validators;
87+
return $this->validators;
88+
}
5589
}

test/Element/DateTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use DateTime;
1313
use PHPUnit\Framework\TestCase;
1414
use Zend\Form\Element\Date as DateElement;
15+
use Zend\Form\Exception\InvalidArgumentException;
1516

1617
/**
1718
* @covers \Zend\Form\Element\Date
@@ -158,4 +159,34 @@ public function testStepValidatorIgnoresDaylightSavings()
158159
}
159160
}
160161
}
162+
163+
public function testFailsWithInvalidMinSpecification()
164+
{
165+
$element = new DateElement('foo');
166+
$element->setAttributes(
167+
[
168+
'inclusive' => true,
169+
'min' => '2000-01-01T00',
170+
'step' => '1',
171+
]
172+
);
173+
174+
$this->expectException(InvalidArgumentException::class);
175+
$element->getInputSpecification();
176+
177+
}
178+
179+
public function testFailsWithInvalidMaxSpecification()
180+
{
181+
$element = new DateElement('foo');
182+
$element->setAttributes(
183+
[
184+
'inclusive' => true,
185+
'max' => '2001-01-01T00',
186+
'step' => '1',
187+
]
188+
);
189+
$this->expectException(InvalidArgumentException::class);
190+
$element->getInputSpecification();
191+
}
161192
}

test/Element/DateTimeLocalTest.php

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use PHPUnit\Framework\TestCase;
1313
use Zend\Form\Element\DateTimeLocal as DateTimeLocalElement;
14+
use Zend\Form\Exception\InvalidArgumentException;
1415

1516
class DateTimeLocalTest extends TestCase
1617
{
@@ -19,8 +20,8 @@ public function testProvidesInputSpecificationThatIncludesValidatorsBasedOnAttri
1920
$element = new DateTimeLocalElement('foo');
2021
$element->setAttributes([
2122
'inclusive' => true,
22-
'min' => '2000-01-01T00:00Z',
23-
'max' => '2001-01-01T00:00Z',
23+
'min' => '2000-01-01T00:00',
24+
'max' => '2001-01-01T00:00',
2425
'step' => '1',
2526
]);
2627

@@ -40,11 +41,11 @@ public function testProvidesInputSpecificationThatIncludesValidatorsBasedOnAttri
4041
switch ($class) {
4142
case 'Zend\Validator\GreaterThan':
4243
$this->assertTrue($validator->getInclusive());
43-
$this->assertEquals('2000-01-01T00:00Z', $validator->getMin());
44+
$this->assertEquals('2000-01-01T00:00', $validator->getMin());
4445
break;
4546
case 'Zend\Validator\LessThan':
4647
$this->assertTrue($validator->getInclusive());
47-
$this->assertEquals('2001-01-01T00:00Z', $validator->getMax());
48+
$this->assertEquals('2001-01-01T00:00', $validator->getMax());
4849
break;
4950
case 'Zend\Validator\DateStep':
5051
$dateInterval = new \DateInterval('PT1M');
@@ -55,4 +56,34 @@ public function testProvidesInputSpecificationThatIncludesValidatorsBasedOnAttri
5556
}
5657
}
5758
}
59+
60+
public function testFailsWithInvalidMinSpecification()
61+
{
62+
$element = new DateTimeLocalElement('foo');
63+
$element->setAttributes(
64+
[
65+
'inclusive' => true,
66+
'min' => '2001-01-01T00:00Z',
67+
'step' => '1',
68+
]
69+
);
70+
71+
$this->expectException(InvalidArgumentException::class);
72+
$element->getInputSpecification();
73+
74+
}
75+
76+
public function testFailsWithInvalidMaxSpecification()
77+
{
78+
$element = new DateTimeLocalElement('foo');
79+
$element->setAttributes(
80+
[
81+
'inclusive' => true,
82+
'max' => '2001-01-01T00:00Z',
83+
'step' => '1',
84+
]
85+
);
86+
$this->expectException(InvalidArgumentException::class);
87+
$element->getInputSpecification();
88+
}
5889
}

test/Element/DateTimeTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use DateTime;
1313
use PHPUnit\Framework\TestCase;
1414
use Zend\Form\Element\DateTime as DateTimeElement;
15+
use Zend\Form\Exception\InvalidArgumentException;
1516

1617
class DateTimeTest extends TestCase
1718
{
@@ -119,4 +120,34 @@ public function testSetFormatWithOptions()
119120

120121
$this->assertSame($format, $element->getFormat());
121122
}
123+
124+
public function testFailsWithInvalidMinSpecification()
125+
{
126+
$element = new DateTimeElement('foo');
127+
$element->setAttributes(
128+
[
129+
'inclusive' => true,
130+
'min' => '2000-01-01T00',
131+
'step' => '1',
132+
]
133+
);
134+
135+
$this->expectException(InvalidArgumentException::class);
136+
$element->getInputSpecification();
137+
138+
}
139+
140+
public function testFailsWithInvalidMaxSpecification()
141+
{
142+
$element = new DateTimeElement('foo');
143+
$element->setAttributes(
144+
[
145+
'inclusive' => true,
146+
'max' => '2001-01-01T00',
147+
'step' => '1',
148+
]
149+
);
150+
$this->expectException(InvalidArgumentException::class);
151+
$element->getInputSpecification();
152+
}
122153
}

test/Element/TimeTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use PHPUnit\Framework\TestCase;
1313
use Zend\Form\Element\Time as TimeElement;
14+
use Zend\Form\Exception\InvalidArgumentException;
1415

1516
class TimeTest extends TestCase
1617
{
@@ -58,4 +59,35 @@ public function testProvidesInputSpecificationThatIncludesValidatorsBasedOnAttri
5859
}
5960
}
6061
}
62+
63+
public function testFailsWithInvalidMinSpecification()
64+
{
65+
$element = new TimeElement('foo');
66+
$element->setAttributes(
67+
[
68+
'inclusive' => true,
69+
'min' => '00:00',
70+
'step' => '1',
71+
]
72+
);
73+
74+
$this->expectException(InvalidArgumentException::class);
75+
$element->getInputSpecification();
76+
77+
}
78+
79+
public function testFailsWithInvalidMaxSpecification()
80+
{
81+
$element = new TimeElement('foo');
82+
$element->setAttributes(
83+
[
84+
'inclusive' => true,
85+
'max' => '00:00',
86+
'step' => '1',
87+
]
88+
);
89+
$this->expectException(InvalidArgumentException::class);
90+
$element->getInputSpecification();
91+
}
92+
6193
}

0 commit comments

Comments
 (0)