Skip to content

Commit 0c6c000

Browse files
authored
Add DateTimeFilter (#1)
Added DateTime filter Added serialize methods to a trait to avoid code duplications across multiple models Added filter test cases
1 parent 66b2ef5 commit 0c6c000

File tree

7 files changed

+305
-3
lines changed

7 files changed

+305
-3
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
}
1212
],
1313
"require": {
14-
"php": ">=7.2"
14+
"php": ">=7.2",
15+
"ext-json": "*"
1516
},
1617
"require-dev": {
1718
"phpunit/phpunit": "^8.0"

src/Filter/DateTime.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace PHPModelGenerator\Filter;
6+
7+
use Exception;
8+
use PHPModelGenerator\Exception\ValidationException;
9+
10+
/**
11+
* Class DateTime
12+
*
13+
* @package PHPModelGenerator\Filter
14+
*/
15+
class DateTime
16+
{
17+
/**
18+
* @param string|null $value
19+
* @param array $options
20+
*
21+
* @return \DateTime|null
22+
*
23+
* @throws ValidationException
24+
*/
25+
public static function filter(?string $value, array $options = []): ?\DateTime
26+
{
27+
try {
28+
if (($options['convertNullToNow'] ?? false) && $value === null) {
29+
return new \DateTime();
30+
}
31+
32+
if (($options['denyEmptyValue'] ?? false) && $value === '') {
33+
throw new ValidationException("Can't process an empty date value");
34+
}
35+
36+
if (($options['convertEmptyValueToNull'] ?? false) && $value === '') {
37+
return null;
38+
}
39+
40+
if (($options['createFromFormat'] ?? false) && $value !== null) {
41+
return \DateTime::createFromFormat($options['createFromFormat'], $value);
42+
}
43+
44+
return $value !== null ? new \DateTime($value) : null;
45+
} catch (Exception $e) {
46+
throw new ValidationException("Invalid Date Time value \"$value\"");
47+
}
48+
}
49+
50+
/**
51+
* @param \DateTime|null $value
52+
* @param array $options
53+
*
54+
* @return string|null
55+
*/
56+
public static function serialize(?\DateTime $value, array $options = []): ?string
57+
{
58+
return ($value instanceof \DateTime)
59+
? $value->format($options['outputFormat'] ?? $options['createFromFormat'] ?? DATE_ISO8601)
60+
: null;
61+
}
62+
}

src/Traits/SerializableTrait.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace PHPModelGenerator\Traits;
6+
7+
/**
8+
* Provide methods to serialize generated models
9+
*
10+
* Trait SerializableTrait
11+
*
12+
* @package PHPModelGenerator\Traits
13+
*/
14+
trait SerializableTrait
15+
{
16+
/**
17+
* Get a JSON representation of the current state
18+
*
19+
* @param int $options Bitmask for json_encode
20+
* @param int $depth the maximum level of object nesting. Must be greater than 0
21+
*
22+
* @return string|false
23+
*/
24+
public function toJSON(int $options = 0, int $depth = 512)
25+
{
26+
if ($depth < 1) {
27+
return false;
28+
}
29+
30+
return json_encode($this->toArray($depth), $options, $depth);
31+
}
32+
33+
/**
34+
* Get an array representation of the current state
35+
*
36+
* @param int $depth the maximum level of object nesting. Must be greater than 0
37+
*
38+
* @return array|false
39+
*/
40+
public function toArray(int $depth = 512)
41+
{
42+
if ($depth < 1) {
43+
return false;
44+
}
45+
46+
$depth--;
47+
$modelData = [];
48+
49+
foreach (get_object_vars($this) as $key => $value) {
50+
if (in_array($key, ['rawModelDataInput', 'errorRegistry'])) {
51+
continue;
52+
}
53+
54+
if (is_array($value)) {
55+
$subData = [];
56+
foreach ($value as $subKey => $element) {
57+
$subData[$subKey] = $this->evaluateAttribute($key, $element, $depth);
58+
}
59+
$modelData[$key] = $subData;
60+
} else {
61+
$modelData[$key] = $this->evaluateAttribute($key, $value, $depth);
62+
}
63+
}
64+
65+
return $modelData;
66+
}
67+
68+
private function evaluateAttribute(string $property, $attribute, int $depth)
69+
{
70+
$customSerializer = 'serialize' . ucfirst($property);
71+
if (method_exists($this, $customSerializer)) {
72+
return $this->{$customSerializer}();
73+
}
74+
75+
if (!is_object($attribute)) {
76+
return $attribute;
77+
}
78+
79+
if ($depth === 0 && method_exists($attribute, '__toString')) {
80+
return (string) $attribute;
81+
}
82+
83+
return (0 >= $depth)
84+
? null
85+
: (
86+
method_exists($attribute, 'toArray')
87+
? $attribute->toArray($depth - 1)
88+
: get_object_vars($attribute)
89+
);
90+
}
91+
}

tests/Exception/ErrorRegistryExceptionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace PHPModelGenerator\Tests;
3+
namespace PHPModelGenerator\Tests\Exception;
44

55
use PHPModelGenerator\Exception\ErrorRegistryException;
66
use PHPUnit\Framework\TestCase;

tests/Exception/ValidationExceptionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace PHPModelGenerator\Tests;
3+
namespace PHPModelGenerator\Tests\Exception;
44

55
use PHPModelGenerator\Exception\ValidationException;
66
use PHPUnit\Framework\TestCase;

tests/Filter/DateTimeTest.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace PHPModelGenerator\Tests\Filter;
4+
5+
use DateTime;
6+
use PHPModelGenerator\Exception\ValidationException;
7+
use PHPModelGenerator\Filter\DateTime as DateTimeFilter;
8+
use PHPUnit\Framework\TestCase;
9+
10+
/**
11+
* Class TrimTest
12+
*
13+
* @package PHPModelGenerator\Tests\Filter
14+
*/
15+
class DateTimeTest extends TestCase
16+
{
17+
/**
18+
* @dataProvider dateTimeDataProvider
19+
*
20+
* @param string|null $input
21+
* @param string|null $output
22+
*/
23+
public function testDateTimeFilter(?string $input, ?string $output): void
24+
{
25+
$result = DateTimeFilter::filter($input);
26+
27+
if ($output === null) {
28+
$this->assertNull($result);
29+
} else {
30+
$this->assertSame((new DateTime($output))->format(DATE_ATOM), $result->format(DATE_ATOM));
31+
}
32+
}
33+
34+
public function dateTimeDataProvider(): array
35+
{
36+
return [
37+
'null' => [null, null],
38+
'Empty string' => ['', 'now'],
39+
'DateTime compatible string' => ['+1 day', '+1 day'],
40+
'DateTime' => ['2020-12-12', '2020-12-12'],
41+
];
42+
}
43+
44+
public function testInvalidDateTimeThrowsAnException(): void
45+
{
46+
$this->expectException(ValidationException::class);
47+
$this->expectExceptionMessage('Invalid Date Time value "Hello"');
48+
49+
DateTimeFilter::filter("Hello");
50+
}
51+
52+
public function testConvertNullToNowOption(): void
53+
{
54+
$this->assertSame(
55+
(new DateTime('now'))->format(DATE_ATOM),
56+
DateTimeFilter::filter(null, ['convertNullToNow' => true])->format(DATE_ATOM)
57+
);
58+
}
59+
60+
public function testConvertEmptyValueToNull(): void
61+
{
62+
$this->assertNull(DateTimeFilter::filter('', ['convertEmptyValueToNull' => true]));
63+
}
64+
65+
public function testDenyEmptyValueOption(): void
66+
{
67+
// check if null is accepted if the option is set
68+
$this->assertNull(DateTimeFilter::filter(null, ['denyEmptyValue' => true]));
69+
70+
$this->expectException(ValidationException::class);
71+
$this->expectExceptionMessage('Invalid Date Time value ""');
72+
73+
DateTimeFilter::filter('', ['denyEmptyValue' => true]);
74+
}
75+
76+
public function testCreateFromFormatOption(): void
77+
{
78+
$this->assertSame(
79+
(new DateTime('2020-12-12'))->format(DATE_ATOM),
80+
DateTimeFilter::filter('12122020', ['createFromFormat' => '!mdY'])->format(DATE_ATOM)
81+
);
82+
}
83+
84+
public function testSerializeDefaultFormat(): void
85+
{
86+
$this->assertNull(DateTimeFilter::serialize(null));
87+
88+
$dateTime = new DateTime();
89+
$this->assertSame($dateTime->format(DATE_ISO8601), DateTimeFilter::serialize($dateTime));
90+
}
91+
92+
public function testSerializeWithCreateFromFormat(): void
93+
{
94+
$dateTime = new DateTime();
95+
96+
$this->assertSame(
97+
$dateTime->format('mdY'),
98+
DateTimeFilter::serialize($dateTime, ['createFromFormat' => 'mdY'])
99+
);
100+
}
101+
102+
public function testSerializeWithOutputFormat(): void
103+
{
104+
$dateTime = new DateTime();
105+
106+
$this->assertSame(
107+
$dateTime->format('Ymd'),
108+
DateTimeFilter::serialize($dateTime, ['createFromFormat' => 'mdY', 'outputFormat' => 'Ymd'])
109+
);
110+
}
111+
}

tests/Filter/TrimTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace PHPModelGenerator\Tests\Filter;
4+
5+
use PHPModelGenerator\Filter\Trim;
6+
use PHPUnit\Framework\TestCase;
7+
8+
/**
9+
* Class TrimTest
10+
*
11+
* @package PHPModelGenerator\Tests\Filter
12+
*/
13+
class TrimTest extends TestCase
14+
{
15+
/**
16+
* @dataProvider trimDataProvider
17+
*
18+
* @param string|null $input
19+
* @param string|null $output
20+
*/
21+
public function testTrimFilter(?string $input, ?string $output): void
22+
{
23+
$this->assertSame($output, Trim::filter($input));
24+
}
25+
26+
public function trimDataProvider(): array
27+
{
28+
return [
29+
'null' => [null, null],
30+
'empty string' => ['', ''],
31+
'String with whitespaces only' => [" \n \r \t ", ''],
32+
'Numeric string' => [' 123 ', '123'],
33+
'Sentence' => [' Hello World ', 'Hello World'],
34+
'Nothing to do' => ['Hi there', 'Hi there'],
35+
];
36+
}
37+
}

0 commit comments

Comments
 (0)