From 1989c6e516462305ef8be1a6882f9acb943dd2d4 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Wed, 24 Apr 2019 14:38:00 +0200 Subject: [PATCH 1/2] A DateTime filter This is a new filter that returns DateTime or (if desired) DateTimeImmutable instances. --- docs/book/standard-filters.md | 24 ++++++++ src/DateTime.php | 101 ++++++++++++++++++++++++++++++++++ test/DateTimeTest.php | 91 ++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 src/DateTime.php create mode 100644 test/DateTimeTest.php diff --git a/docs/book/standard-filters.md b/docs/book/standard-filters.md index 32b95633..a711c99d 100644 --- a/docs/book/standard-filters.md +++ b/docs/book/standard-filters.md @@ -713,6 +713,30 @@ All options can be set at instantiation or by using a related method. For exampl methods for `target` are `getTarget()` and `setTarget()`. You can also use the `setOptions()` method which accepts an array of all options. +## DateTime + +Converts `$value` to a `DateTime` or `DateTimeImmutable` instance. + +### Supported Options + +The following options are supported for `Zend\Filter\DateTime`: + +- `immutable`: `true` if a `DateTimeImmutable` instance should be returned, + `false` (the default) if `DateTime` is expected. Methods for getting/setting + this option are available: `isImmutable()` and `setImmutable(bool)`. + +### Basic usage + +```php +$filter = new Zend\Filter\DateTime(); +$dt = $filter->filter('2019-04-24T14:33:12+02:00'); +// $dt is a DateTime instance with the above date, time and timezone + +$filter = new Zend\Filter\DateTime(true); +$dt = $filter->filter('2019-04-24T14:34:34+02:00'); +// $dt is a DateTimeImmutable instance with the above date, time and timezone +``` + ## Digits Returns the string `$value`, removing all but digits. diff --git a/src/DateTime.php b/src/DateTime.php new file mode 100644 index 00000000..fc811eb6 --- /dev/null +++ b/src/DateTime.php @@ -0,0 +1,101 @@ + false, + ]; + + /** @param array|bool|null|Traversable $immutableOrOptions */ + public function __construct($immutableOrOptions = null) + { + if ($immutableOrOptions !== null) { + if ($immutableOrOptions instanceof Traversable) { + $immutableOrOptions = iterator_to_array($immutableOrOptions); + } + + if (is_array($immutableOrOptions)) { + if (isset($immutableOrOptions['immutable'])) { + $this->setOptions($immutableOrOptions); + } else { + $this->setImmutable($immutableOrOptions); + } + } else { + $this->setImmutable($immutableOrOptions); + } + } + } + + /** + * Defined by Zend\Filter\FilterInterface + * + * Returns (DateTimeInterface) $value + * + * @param mixed $value + * @return \DateTimeInterface + */ + public function filter($value) + { + $immutable = $this->isImmutable(); + + if (($value instanceof DateTimeImmutable && $immutable) + || ($value instanceof PhpDateTime && ! $immutable)) { + // no conversion + return $value; + } + + if ($value instanceof DateTimeImmutable && ! $immutable) { + // create mutable DateTime from DateTimeImmutable + $mutableDateTime = new PhpDateTime('@0'); + $mutableDateTime = $mutableDateTime->sub($value->diff($mutableDateTime)); + $mutableDateTime->setTimezone($value->getTimezone()); + return $mutableDateTime; + } + + if ($value instanceof PhpDateTime && $immutable) { + // create DateTimeImmutable from mutable DateTime + return DateTimeImmutable::createFromMutable($value); + } + + if ($immutable) { + return new DateTimeImmutable($value); + } + + return new PhpDateTime($value); + } + + /** @return bool */ + public function isImmutable() + { + return $this->options['immutable']; + } + + /** + * @param bool $immutable + * @return self + * @throws Exception\InvalidArgumentException + */ + public function setImmutable($immutable) + { + if (! is_bool($immutable)) { + throw new Exception\InvalidArgumentException('Expected $immutable to be a boolean'); + } + + $this->options['immutable'] = $immutable; + return $this; + } +} diff --git a/test/DateTimeTest.php b/test/DateTimeTest.php new file mode 100644 index 00000000..5e058bdd --- /dev/null +++ b/test/DateTimeTest.php @@ -0,0 +1,91 @@ +assertEquals(false, $filter->isImmutable()); + } + + public function testConstructorOptions() + { + $filter = new DateTimeFilter(['immutable' => true]); + + $this->assertEquals(true, $filter->isImmutable()); + } + + public function testConstructorParams() + { + $filter = new DateTimeFilter(true); + + $this->assertEquals(true, $filter->isImmutable()); + } + + public function testNoConversion() + { + $dateTime = new DateTime(); + + $filter = new DateTimeFilter(); + $this->assertSame($dateTime, $filter->filter($dateTime)); + + $dateTime = new DateTimeImmutable(); + + $filter = new DateTimeFilter(true); + $this->assertSame($dateTime, $filter->filter($dateTime)); + } + + public function testRealConversion() + { + $dateTime = '2019-04-24T14:25:55.123+02:00'; + $filter = new DateTimeFilter(true); + + $filtered = $filter->filter($dateTime); + + $this->assertInstanceOf(DateTimeImmutable::class, $filtered); + $this->assertEquals(new DateTimeImmutable($dateTime), $filtered); + + $dateTime = '2019-04-24T14:26:22.456+02:00'; + $filter = new DateTimeFilter(); + + $filtered = $filter->filter($dateTime); + + $this->assertInstanceOf(DateTime::class, $filtered); + $this->assertEquals(new DateTime($dateTime), $filter->filter($dateTime)); + } + + public function testSimpleConversion() + { + $dateTime = new DateTime(); + $filter = new DateTimeFilter(true); + + $filtered = $filter->filter($dateTime); + + $this->assertInstanceOf(DateTimeImmutable::class, $filtered); + $this->assertEquals($dateTime, $filtered); + + $dateTime = new DateTimeImmutable(); + $filter = new DateTimeFilter(); + + $filtered = $filter->filter($dateTime); + + $this->assertInstanceOf(DateTime::class, $filtered); + $this->assertEquals($dateTime, $filter->filter($dateTime)); + } +} From 48e2d7627de76608b0f58175bec3c876dad07900 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Thu, 25 Apr 2019 08:22:08 +0200 Subject: [PATCH 2/2] Only filter DateTimeInterface|string --- src/DateTime.php | 17 ++++++++++++----- test/DateTimeTest.php | 32 ++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/DateTime.php b/src/DateTime.php index fc811eb6..956356ba 100644 --- a/src/DateTime.php +++ b/src/DateTime.php @@ -45,20 +45,27 @@ public function __construct($immutableOrOptions = null) * * Returns (DateTimeInterface) $value * + * If the value provided is neither a string nor instance of + * DateTimeInterface, it will remain unfiltered + * * @param mixed $value - * @return \DateTimeInterface + * @return mixed */ public function filter($value) { $immutable = $this->isImmutable(); - if (($value instanceof DateTimeImmutable && $immutable) - || ($value instanceof PhpDateTime && ! $immutable)) { + $isDateTime = $value instanceof PhpDateTime; + $isDateTimeImmutable = $value instanceof DateTimeImmutable; + + if (($isDateTimeImmutable && $immutable) + || ($isDateTime && ! $immutable) + || ! ($isDateTime || $isDateTimeImmutable || is_string($value))) { // no conversion return $value; } - if ($value instanceof DateTimeImmutable && ! $immutable) { + if ($isDateTimeImmutable && ! $immutable) { // create mutable DateTime from DateTimeImmutable $mutableDateTime = new PhpDateTime('@0'); $mutableDateTime = $mutableDateTime->sub($value->diff($mutableDateTime)); @@ -66,7 +73,7 @@ public function filter($value) return $mutableDateTime; } - if ($value instanceof PhpDateTime && $immutable) { + if ($isDateTime && $immutable) { // create DateTimeImmutable from mutable DateTime return DateTimeImmutable::createFromMutable($value); } diff --git a/test/DateTimeTest.php b/test/DateTimeTest.php index 5e058bdd..f0d59e88 100644 --- a/test/DateTimeTest.php +++ b/test/DateTimeTest.php @@ -38,17 +38,15 @@ public function testConstructorParams() $this->assertEquals(true, $filter->isImmutable()); } - public function testNoConversion() + /** + * @param bool $immutable + * @param mixed $value + * @dataProvider noConversionProvider + */ + public function testNoConversion($immutable, $value) { - $dateTime = new DateTime(); - - $filter = new DateTimeFilter(); - $this->assertSame($dateTime, $filter->filter($dateTime)); - - $dateTime = new DateTimeImmutable(); - - $filter = new DateTimeFilter(true); - $this->assertSame($dateTime, $filter->filter($dateTime)); + $filter = new DateTimeFilter($immutable); + $this->assertSame($value, $filter->filter($value)); } public function testRealConversion() @@ -88,4 +86,18 @@ public function testSimpleConversion() $this->assertInstanceOf(DateTime::class, $filtered); $this->assertEquals($dateTime, $filter->filter($dateTime)); } + + public function noConversionProvider() + { + return [ + [false, new DateTime()], + [false, null], + [false, 42], + [false, 3.14], + [true, new DateTimeImmutable()], + [true, null], + [true, 42], + [true, 3.14], + ]; + } }