1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Shared Kernel library. |
5
|
|
|
* |
6
|
|
|
* Copyright (c) 2016-present LIN3S <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
declare(strict_types=1); |
13
|
|
|
|
14
|
|
|
namespace LIN3S\SharedKernel\Event; |
15
|
|
|
|
16
|
|
|
use LIN3S\SharedKernel\Domain\Model\DomainEvent; |
17
|
|
|
use LIN3S\SharedKernel\Exception\InvalidArgumentException; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @author Beñat Espiña <[email protected]> |
21
|
|
|
*/ |
22
|
|
|
class StoredEvent implements \JsonSerializable |
23
|
|
|
{ |
24
|
|
|
private $order; |
25
|
|
|
private $type; |
26
|
|
|
private $payload; |
27
|
|
|
private $serializedEvent; |
28
|
|
|
private $occurredOn; |
29
|
|
|
private $streamName; |
30
|
|
|
private $streamVersion; |
31
|
|
|
|
32
|
|
|
public function __construct(DomainEvent $event, StreamName $name, StreamVersion $version) |
33
|
|
|
{ |
34
|
|
|
$this->type = get_class($event); |
35
|
|
|
$this->setOccurredOn($event->occurredOn()); |
36
|
|
|
$this->streamName = $name->name(); |
37
|
|
|
$this->streamVersion = $version->version(); |
38
|
|
|
|
39
|
|
|
$this->setPayload($event); |
40
|
|
|
$this->setSerializedEvent($event); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function normalizeToAppend() : array |
44
|
|
|
{ |
45
|
|
|
return [ |
46
|
|
|
'type' => $this->type, |
47
|
|
|
'occurred_on' => $this->occurredOn, |
48
|
|
|
'payload' => $this->payload, |
49
|
|
|
'stream_name' => $this->streamName, |
50
|
|
|
'stream_version' => $this->streamVersion, |
51
|
|
|
]; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
public function jsonSerialize() : array |
55
|
|
|
{ |
56
|
|
|
return [ |
57
|
|
|
'order' => $this->order, |
58
|
|
|
'type' => $this->formatType(), |
59
|
|
|
'occurred_on' => $this->occurredOn, |
60
|
|
|
'payload' => $this->serializedEvent, |
61
|
|
|
'stream_name' => $this->streamName, |
62
|
|
|
'stream_version' => $this->streamVersion, |
63
|
|
|
]; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
View Code Duplication |
private function setPayload(DomainEvent $event) : void |
|
|
|
|
67
|
|
|
{ |
68
|
|
|
$this->payload = []; |
69
|
|
|
$eventReflection = new \ReflectionClass($event); |
70
|
|
|
foreach ($eventReflection->getProperties() as $property) { |
71
|
|
|
if ('occurredOn' === $property->getName()) { |
72
|
|
|
continue; |
73
|
|
|
} |
74
|
|
|
$property->setAccessible(true); |
75
|
|
|
$this->payload[$property->getName()] = $this->serializePayload($property, $event); |
76
|
|
|
} |
77
|
|
|
$this->payload = json_encode($this->payload); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
View Code Duplication |
private function setSerializedEvent(DomainEvent $event) : void |
|
|
|
|
81
|
|
|
{ |
82
|
|
|
$this->serializedEvent = []; |
83
|
|
|
$eventReflection = new \ReflectionClass($event); |
84
|
|
|
foreach ($eventReflection->getProperties() as $property) { |
85
|
|
|
if ('occurredOn' === $property->getName()) { |
86
|
|
|
continue; |
87
|
|
|
} |
88
|
|
|
$property->setAccessible(true); |
89
|
|
|
$this->serializedEvent[$property->getName()] = $this->serializeEvent($property, $event); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
$this->serializedEvent = json_encode($this->serializedEvent); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
private function setOccurredOn(\DateTimeInterface $occurredOn) : void |
96
|
|
|
{ |
97
|
|
|
$this->checkDateTimeIsValid($occurredOn); |
98
|
|
|
$occurredOn->setTimezone(new \DateTimeZone('UTC')); |
99
|
|
|
$this->occurredOn = $occurredOn->getTimestamp(); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
private function checkDateTimeIsValid(\DateTimeInterface $occurredOn) : void |
103
|
|
|
{ |
104
|
|
|
if (!($occurredOn instanceof \DateTimeImmutable) && !($occurredOn instanceof \DateTime)) { |
105
|
|
|
throw new InvalidArgumentException('Given occurredOn is not a \DateTime or \DateTimeImmutable instance'); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
private function serializePayload(\ReflectionProperty $property, $object, array $result = []) |
110
|
|
|
{ |
111
|
|
|
$property->setAccessible(true); |
112
|
|
|
$value = $property->getValue($object); |
113
|
|
|
if (is_scalar($value)) { |
114
|
|
|
return $value; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
$className = get_class($value); |
118
|
|
|
$reflectionClass = new \ReflectionClass($value); |
119
|
|
|
$properties = $reflectionClass->getProperties(); |
120
|
|
|
|
121
|
|
|
foreach ($properties as $property) { |
122
|
|
|
$result[$className][$property->getName()] = $this->serializePayload($property, $value); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
return $result; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
private function serializeEvent(\ReflectionProperty $property, $object, array $result = []) |
129
|
|
|
{ |
130
|
|
|
$property->setAccessible(true); |
131
|
|
|
$value = $property->getValue($object); |
132
|
|
|
if (is_scalar($value)) { |
133
|
|
|
return $value; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
$reflectionClass = new \ReflectionClass($value); |
137
|
|
|
$properties = $reflectionClass->getProperties(); |
138
|
|
|
|
139
|
|
|
foreach ($properties as $property) { |
140
|
|
|
$result[] = $this->serializeEvent($property, $value, $result); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
return $result; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
private function formatType() : string |
147
|
|
|
{ |
148
|
|
|
return mb_strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', array_reverse(explode('\\', $this->type))[0])); |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.