Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
operating-system: [ ubuntu-latest ]
php-versions: [ '8.2', '8.3', '8.4', '8.5' ]
php-versions: [ '8.4', '8.5' ]
name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }}

steps:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A strictly typed array reader for PHP.

## Requirements

* PHP 8.2 - 8.5
* PHP 8.4 - 8.5

## Installation

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"homepage": "https://github.com/selective-php/array-reader",
"require": {
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
"php": "~8.4.0 || ~8.5.0"
},
"require-dev": {
"cakephp/chronos": "^2 || ^3",
Expand Down
73 changes: 73 additions & 0 deletions src/ArrayReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Selective\ArrayReader;

use Cake\Chronos\Chronos;
use DateTimeImmutable;
use DateTimeInterface;
use InvalidArgumentException;

/**
Expand Down Expand Up @@ -237,6 +239,46 @@ public function findBool(string $key, ?bool $default = null): ?bool
return (bool)$value;
}

/**
* Get value as DateTimeImmutable.
*
* @param string $key The key
* @param DateTimeImmutable|null $default The default value
*
* @throws InvalidArgumentException
*
* @return DateTimeImmutable The value
*/
public function getDateTime(string $key, ?DateTimeImmutable $default = null): DateTimeImmutable
{
$value = $this->find($key, $default);

if ($this->isNullOrBlank($value)) {
throw new InvalidArgumentException(sprintf('No value found for key "%s"', $key));
}

return $this->toDateTimeImmutable($key, $value);
}

/**
* Get value as DateTimeImmutable or null.
*
* @param string $key The key
* @param DateTimeImmutable|null $default The default value
*
* @return DateTimeImmutable|null The value
*/
public function findDateTime(string $key, ?DateTimeImmutable $default = null): ?DateTimeImmutable
{
$value = $this->find($key, $default);

if ($this->isNullOrBlank($value)) {
return null;
}

return $this->toDateTimeImmutable($key, $value);
}

/**
* Get value as Chronos.
*
Expand Down Expand Up @@ -377,4 +419,35 @@ private function isNullOrBlank(mixed $value): bool
{
return $value === null || $value === '';
}

/**
* Cast a value to DateTimeImmutable.
*
* @param string $key The key
* @param mixed $value The value
*
* @throws InvalidArgumentException
*
* @return DateTimeImmutable The date
*/
private function toDateTimeImmutable(string $key, mixed $value): DateTimeImmutable
{
if ($value instanceof DateTimeImmutable) {
return $value;
}

if ($value instanceof DateTimeInterface) {
return DateTimeImmutable::createFromInterface($value);
}

if (is_int($value) || (is_float($value) && is_finite($value))) {
return DateTimeImmutable::createFromTimestamp($value);
}

if (!is_string($value)) {
throw new InvalidArgumentException(sprintf('Invalid date value for key "%s"', $key));
}

return new DateTimeImmutable($value);
}
}
123 changes: 123 additions & 0 deletions tests/ArrayReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Selective\ArrayReader\Test;

use Cake\Chronos\Chronos;
use DateTime;
use DateTimeImmutable;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -429,4 +432,124 @@ public static function providerFindArray(): array
[[['key' => 'value'], ['key2' => 'value2']], 2, null, null],
];
}

/**
* Test.
*
* @param mixed $data The data
* @param string $key The lookup key
* @param mixed $default The default value
* @param mixed $expected The expected value
*
* @return void
*/
#[DataProvider('providerGetDateTime')]
public function testGetDateTime($data, string $key, $default, $expected): void
{
$reader = new ArrayReader($data);

$this->assertEquals($expected, $reader->findDateTime($key, $default));
$this->assertEquals($expected, $reader->getDateTime($key, $default));
}

/**
* Provider.
*
* @return array[] The test data
*/
public static function providerGetDateTime(): array
{
$date = new DateTimeImmutable('2020-01-02T03:04:05+00:00');
$fraction = new DateTimeImmutable('2020-01-02T03:04:05.500000+00:00');
$chronos = new Chronos('2020-01-02T03:04:05+00:00');

return [
[['created' => '2020-01-02T03:04:05+00:00'], 'created', null, $date],
[['created' => $date], 'created', null, $date],
[['created' => new DateTime('2020-01-02T03:04:05+00:00')], 'created', null, $date],
[['created' => 1577934245], 'created', null, $date],
[['created' => 1577934245.5], 'created', null, $fraction],
[['user' => ['created' => '2020-01-02T03:04:05+00:00']], 'user.created', null, $date],
[['created' => $chronos], 'created', null, $chronos],
[[], 'missing', $date, $date],
[['created' => null], 'created', $date, $date],
];
}

/**
* Test.
*
* @param mixed $data The data
* @param string $key The lookup key
* @param mixed $default The default value
*
* @return void
*/
#[DataProvider('providerGetDateTimeError')]
public function testGetDateTimeError($data, string $key, $default): void
{
$reader = new ArrayReader($data);

$this->expectException(InvalidArgumentException::class);

$reader->getDateTime($key, $default);
}

/**
* Provider.
*
* @return array[] The test data
*/
public static function providerGetDateTimeError(): array
{
return [
[['created' => null], 'created', null],
[['created' => ''], 'created', null],
[[], 'missing', null],
[['created' => ['not-a-date']], 'created', null],
[['created' => INF], 'created', null],
[['created' => NAN], 'created', null],
[['user' => ['created' => null]], 'user.created', null],
];
}

/**
* Test.
*
* @param mixed $data The data
* @param string $key The lookup key
* @param mixed $default The default value
* @param mixed $expected The expected value
*
* @return void
*/
#[DataProvider('providerFindDateTime')]
public function testFindDateTime($data, string $key, $default, $expected): void
{
$reader = new ArrayReader($data);

$this->assertEquals($expected, $reader->findDateTime($key, $default));
}

/**
* Provider.
*
* @return array[] The test data
*/
public static function providerFindDateTime(): array
{
$date = new DateTimeImmutable('2020-01-02T03:04:05+00:00');

return [
[['created' => '2020-01-02T03:04:05+00:00'], 'created', null, $date],
[['created' => null], 'created', null, null],
[['created' => ''], 'created', null, null],
[['created' => ''], 'created', $date, null],
[[], 'missing', null, null],
[[], 'missing', $date, $date],
[['created' => null], 'created', $date, $date],
[['user' => ['created' => '2020-01-02T03:04:05+00:00']], 'user.created', null, $date],
[['user' => ['created' => null]], 'user.created', null, null],
];
}
}
Loading