Skip to content

Commit a5a09a5

Browse files
authored
Object serialization (#2)
* Add DateRange serialziation * Requere JSON PHP extension in composer
1 parent 375403b commit a5a09a5

File tree

5 files changed

+250
-34
lines changed

5 files changed

+250
-34
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
}
1313
],
1414
"require": {
15-
"php": "^7.1"
15+
"php": "^7.1",
16+
"ext-json": "*"
1617
},
1718
"require-dev": {
1819
"phpunit/phpunit": "~6.4.4"

src/DateRange.php

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212

1313
use DateTimeImmutable;
1414
use DateTimeInterface;
15+
use JsonSerializable;
16+
use Serializable;
1517

1618
/**
1719
* Date range implementation.
1820
*/
19-
final class DateRange implements DateRangeInterface
21+
final class DateRange implements DateRangeInterface, Serializable, JsonSerializable
2022
{
2123
/**
2224
* @var DateTimeInterface
@@ -40,6 +42,27 @@ public function __construct(DateTimeInterface $begin, DateTimeInterface $end = n
4042
$this->end = $end;
4143
}
4244

45+
/**
46+
* {@inheritdoc}
47+
*/
48+
public function __toString()
49+
{
50+
return $this->serialize();
51+
}
52+
53+
/**
54+
* {@inheritdoc}
55+
*/
56+
public function __debugInfo()
57+
{
58+
return [
59+
'begin' => $this->getBegin()->format('c'),
60+
'end' => $this->isFinite()
61+
? $this->getEnd()->format('c')
62+
: '-',
63+
];
64+
}
65+
4366
/**
4467
* {@inheritdoc}
4568
*/
@@ -120,6 +143,46 @@ public function endAt(DateTimeInterface $time): DateRangeInterface
120143
return $this;
121144
}
122145

146+
/**
147+
* {@inheritdoc}
148+
*/
149+
public function serialize()
150+
{
151+
return sprintf(
152+
'%s/%s',
153+
$this->getBegin()->format('c'),
154+
$this->isFinite()
155+
? $this->getEnd()->format('c')
156+
: '-'
157+
);
158+
}
159+
160+
/**
161+
* {@inheritdoc}
162+
*/
163+
public function unserialize($serialized)
164+
{
165+
$times = explode('/', $serialized, 2);
166+
167+
if (count($times) !== 2) {
168+
throw new DateRangeException('Invalid range format');
169+
}
170+
171+
$this->begin = new DateTimeImmutable($times[0]);
172+
173+
if ($times[1] !== '-') {
174+
$this->end = new DateTimeImmutable($times[1]);
175+
}
176+
}
177+
178+
/**
179+
* {@inheritdoc}
180+
*/
181+
public function jsonSerialize()
182+
{
183+
return $this->serialize();
184+
}
185+
123186
/**
124187
* @param DateTimeInterface $begin
125188
* @param DateTimeInterface|null $end

src/DateRangeImmutable.php

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@
1010

1111
namespace Zee\DateRange;
1212

13+
use DateTimeImmutable;
1314
use DateTimeInterface;
15+
use JsonSerializable;
16+
use Serializable;
1417

1518
/**
1619
* Immutable implementation of date range.
1720
*
1821
* This class behaves the same as `{@see DateRange}`
1922
* except it never modifies itself but returns a new object instead.
2023
*/
21-
final class DateRangeImmutable implements DateRangeInterface
24+
final class DateRangeImmutable implements DateRangeInterface, Serializable, JsonSerializable
2225
{
2326
/**
2427
* @var DateRange
@@ -34,6 +37,22 @@ public function __construct(DateTimeInterface $begin, DateTimeInterface $end = n
3437
$this->storage = new DateRange($begin, $end);
3538
}
3639

40+
/**
41+
* {@inheritdoc}
42+
*/
43+
public function __toString()
44+
{
45+
return $this->storage->__toString();
46+
}
47+
48+
/**
49+
* {@inheritdoc}
50+
*/
51+
public function __debugInfo()
52+
{
53+
return $this->storage->__debugInfo();
54+
}
55+
3756
/**
3857
* Clones internal storage.
3958
*/
@@ -119,4 +138,39 @@ public function endAt(DateTimeInterface $time): DateRangeInterface
119138

120139
return $clone;
121140
}
141+
142+
/**
143+
* {@inheritdoc}
144+
*/
145+
public function serialize()
146+
{
147+
return $this->storage->serialize();
148+
}
149+
150+
/**
151+
* {@inheritdoc}
152+
*/
153+
public function unserialize($serialized)
154+
{
155+
$times = explode('/', $serialized, 2);
156+
157+
if (count($times) !== 2) {
158+
throw new DateRangeException('Invalid range format');
159+
}
160+
161+
$this->storage = new DateRange(
162+
new DateTimeImmutable($times[0]),
163+
$times[1] !== '-'
164+
? new DateTimeImmutable($times[1])
165+
: null
166+
);
167+
}
168+
169+
/**
170+
* {@inheritdoc}
171+
*/
172+
public function jsonSerialize()
173+
{
174+
return $this->storage->jsonSerialize();
175+
}
122176
}

tests/DateRangeImmutableTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use DateTime;
1414
use DateTimeImmutable;
15+
use DomainException;
1516
use PHPUnit\Framework\TestCase;
1617

1718
/**
@@ -49,4 +50,39 @@ public function checkImmutability()
4950
self::assertNotSame($initial, $actual);
5051
self::assertSame($soon, $actual->getEnd());
5152
}
53+
54+
/**
55+
* @test
56+
*/
57+
public function checkImmutableCopyMutableObjectBehaviors()
58+
{
59+
$yesterday = new DateTime('-1 day');
60+
$tomorrow = new DateTime('+1 day');
61+
62+
$immutable = new DateRangeImmutable($yesterday, $tomorrow);
63+
$mutable = new DateRange($yesterday, $tomorrow);
64+
65+
self::assertSame((string) $mutable, (string) $immutable);
66+
self::assertSame(json_encode($mutable), json_encode($immutable));
67+
self::assertSame($mutable->__debugInfo(), $immutable->__debugInfo());
68+
69+
$immutable = unserialize(serialize($immutable));
70+
$mutable = unserialize(serialize($mutable));
71+
72+
self::assertEquals($mutable->getBegin(), $immutable->getBegin());
73+
self::assertEquals($mutable->getEnd(), $immutable->getEnd());
74+
}
75+
76+
/**
77+
* @test
78+
*/
79+
public function handleInvalidSerializedValue()
80+
{
81+
$range = new DateRangeImmutable(new DateTime());
82+
83+
$this->expectException(DomainException::class);
84+
$this->expectExceptionMessage('Invalid range format');
85+
86+
$range->unserialize('');
87+
}
5288
}

0 commit comments

Comments
 (0)