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

Commit

Permalink
Merge branch 'hotfix/69' into develop
Browse files Browse the repository at this point in the history
Forward port #69
  • Loading branch information
weierophinney committed Nov 19, 2018
2 parents 066771f + 0528640 commit 24efed7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 11 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ All notable changes to this project will be documented in this file, in reverse

### Changed

- Nothing.
- [#69](https://github.com/zendframework/zend-hydrator/pull/69) adds support for special pre/post characters in formats passed to the
`DateTimeFormatterStrategy`. When used, the `DateTime` instances created
during hydration will (generally) omit the time element, allowing for more
accurate comparisons.

### Deprecated

Expand Down
6 changes: 6 additions & 0 deletions docs/book/strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ This is a strategy that allows you to pass in options for:
and DateTime instances. The input and output formats can be provided as
constructor arguments.

As of version 2.4.1, this strategy now allows `DateTime` formats that use `!` to
prepend the format, or `|` or `+` to append it; these ensure that, during
hydration, the new `DateTime` instance created will set the time element
accordingly. As a specific example, `Y-m-d|` will drop the time component,
ensuring comparisons are based on a midnight time value.

### Zend\\Hydrator\\Strategy\\DefaultStrategy

The `DefaultStrategy` simply proxies everything through, without performing any
Expand Down
31 changes: 21 additions & 10 deletions src/Strategy/DateTimeFormatterStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
final class DateTimeFormatterStrategy implements StrategyInterface
{
/**
* Format to use during hydration.
*
* @var string
*/
private $format;
Expand All @@ -25,6 +27,18 @@ final class DateTimeFormatterStrategy implements StrategyInterface
*/
private $timezone;

/**
* Format to use during extraction.
*
* Removes any special anchor characters used to ensure that creation of a
* `DateTime` instance uses the formatted time string (which is useful
* during hydration). These include `!` at the beginning of the string and
* `|` at the end.
*
* @var string
*/
private $extractionFormat;

/**
* Constructor
*
Expand All @@ -33,23 +47,23 @@ final class DateTimeFormatterStrategy implements StrategyInterface
*/
public function __construct($format = DateTime::RFC3339, DateTimeZone $timezone = null)
{
$this->format = (string) $format;
$this->format = (string) $format;
$this->timezone = $timezone;
$this->extractionFormat = preg_replace('/(?<![\\\\])[+|!\*]/', '', $this->format);
}

/**
* {@inheritDoc}
*
* Converts to date time string
*
* @param mixed|DateTime $value
*
* @param mixed|DateTimeInterface $value
* @return mixed|string
*/
public function extract($value)
{
if ($value instanceof DateTimeInterface) {
return $value->format($this->format);
return $value->format($this->extractionFormat);
}

return $value;
Expand All @@ -61,7 +75,6 @@ public function extract($value)
* {@inheritDoc}
*
* @param mixed|string $value
*
* @return mixed|DateTime
*/
public function hydrate($value)
Expand All @@ -70,11 +83,9 @@ public function hydrate($value)
return;
}

if ($this->timezone) {
$hydrated = DateTime::createFromFormat($this->format, $value, $this->timezone);
} else {
$hydrated = DateTime::createFromFormat($this->format, $value);
}
$hydrated = $this->timezone
? DateTime::createFromFormat($this->format, $value, $this->timezone)
: DateTime::createFromFormat($this->format, $value);

return $hydrated ?: $value;
}
Expand Down
46 changes: 46 additions & 0 deletions test/Strategy/DateTimeFormatterStrategyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
class DateTimeFormatterStrategyTest extends TestCase
{

public function testHydrate()
{
$strategy = new DateTimeFormatterStrategy('Y-m-d');
Expand Down Expand Up @@ -100,4 +101,49 @@ public function testCanExtractAnyDateTimeInterface()
$strategy->extract($dateMock);
$strategy->extract($dateImmutableMock);
}

/**
* @dataProvider formatsWithSpecialCharactersProvider
* @param string $format
* @param string $expectedValue
*/
public function testAcceptsCreateFromFormatSpecialCharacters($format, $expectedValue)
{
$strategy = new DateTimeFormatterStrategy($format);
$hydrated = $strategy->hydrate($expectedValue);

$this->assertInstanceOf(DateTime::class, $hydrated);
$this->assertEquals($expectedValue, $hydrated->format('Y-m-d'));
}

/**
* @dataProvider formatsWithSpecialCharactersProvider
* @param string $format
* @param string $expectedValue
*/
public function testCanExtractWithCreateFromFormatSpecialCharacters($format, $expectedValue)
{
$date = DateTime::createFromFormat($format, $expectedValue);
$strategy = new DateTimeFormatterStrategy($format);
$extracted = $strategy->extract($date);

$this->assertEquals($expectedValue, $extracted);
}

public function testCanExtractWithCreateFromFormatEscapedSpecialCharacters()
{
$date = DateTime::createFromFormat('Y-m-d', '2018-02-05');
$strategy = new DateTimeFormatterStrategy('Y-m-d\\+');
$extracted = $strategy->extract($date);
$this->assertEquals('2018-02-05+', $extracted);
}

public function formatsWithSpecialCharactersProvider()
{
return [
'!-prepended' => ['!Y-m-d', '2018-02-05'],
'|-appended' => ['Y-m-d|', '2018-02-05'],
'+-appended' => ['Y-m-d+', '2018-02-05'],
];
}
}

0 comments on commit 24efed7

Please sign in to comment.