|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
5
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
6
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
7
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
8
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
9
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
10
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
11
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
12
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
13
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
14
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
15
|
|
|
* |
|
16
|
|
|
* The software is based on the Axon Framework project which is |
|
17
|
|
|
* licensed under the Apache 2.0 license. For more information on the Axon Framework |
|
18
|
|
|
* see <http://www.axonframework.org/>. |
|
19
|
|
|
* |
|
20
|
|
|
* This software consists of voluntary contributions made by many individuals |
|
21
|
|
|
* and is licensed under the MIT license. For more information, see |
|
22
|
|
|
* <http://www.governor-framework.org/>. |
|
23
|
|
|
*/ |
|
24
|
|
|
|
|
25
|
|
|
namespace Governor\Framework\CommandHandling\Distributed; |
|
26
|
|
|
|
|
27
|
|
|
|
|
28
|
|
|
use Governor\Framework\Serializer\SerializerInterface; |
|
29
|
|
|
use Governor\Framework\Serializer\SimpleSerializedObject; |
|
30
|
|
|
use Governor\Framework\Serializer\SimpleSerializedType; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* Holds information about the outcome of a distributed command dispatch operation. |
|
34
|
|
|
* |
|
35
|
|
|
* @author "David Kalosi" <[email protected]> |
|
36
|
|
|
* @license <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a> |
|
37
|
|
|
*/ |
|
38
|
|
|
class ReplyMessage |
|
39
|
|
|
{ |
|
40
|
|
|
const NULL = "_null"; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @var string |
|
44
|
|
|
*/ |
|
45
|
|
|
private $commandIdentifier; |
|
46
|
|
|
/** |
|
47
|
|
|
* @var bool |
|
48
|
|
|
*/ |
|
49
|
|
|
private $success; |
|
50
|
|
|
/** |
|
51
|
|
|
* @var string |
|
52
|
|
|
*/ |
|
53
|
|
|
private $resultType; |
|
54
|
|
|
/** |
|
55
|
|
|
* @var string |
|
56
|
|
|
*/ |
|
57
|
|
|
private $resultRevision; |
|
58
|
|
|
/** |
|
59
|
|
|
* @var string |
|
60
|
|
|
*/ |
|
61
|
|
|
private $serializedResult; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* @var mixed |
|
65
|
|
|
*/ |
|
66
|
|
|
private $result; |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* Constructs a message containing a reply to the command with given <code>commandIdentifier</code>, containing |
|
70
|
|
|
* either given <code>returnValue</code> or <code>error</code>, which uses the given <code>serializer</code> to |
|
71
|
|
|
* deserialize its contents. |
|
72
|
|
|
* |
|
73
|
|
|
* @param string $commandIdentifier The identifier of the command to which the message is a reply |
|
74
|
|
|
* @param SerializerInterface $serializer The serializer to serialize the message contents with |
|
75
|
|
|
* @param mixed $returnValue The return value of command process |
|
76
|
|
|
* @param bool $success <code>true</code> if the returnValue represents the completion of the command <code>false</code> otherwise |
|
77
|
|
|
*/ |
|
78
|
4 |
|
public function __construct( |
|
79
|
|
|
$commandIdentifier, |
|
80
|
|
|
SerializerInterface $serializer, |
|
81
|
|
|
$returnValue, |
|
82
|
|
|
$success = true |
|
83
|
|
|
) { |
|
84
|
4 |
|
$this->success = $success; |
|
85
|
4 |
|
$this->result = null; |
|
86
|
|
|
|
|
87
|
4 |
|
if (null === $returnValue) { |
|
88
|
1 |
|
$this->result = null; |
|
89
|
4 |
|
} elseif ($returnValue instanceof \Exception) { |
|
90
|
1 |
|
$this->result = $serializer->serialize($returnValue->getMessage()); |
|
91
|
1 |
|
} else { |
|
92
|
3 |
|
$this->result = $serializer->serialize($returnValue); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
4 |
|
$this->commandIdentifier = $commandIdentifier; |
|
96
|
|
|
|
|
97
|
4 |
|
if (null !== $this->result) { |
|
98
|
3 |
|
$this->resultType = $this->result->getType()->getName(); |
|
99
|
3 |
|
$this->resultRevision = $this->result->getType()->getRevision(); |
|
100
|
3 |
|
$this->serializedResult = $this->result->getData(); |
|
101
|
3 |
|
} |
|
102
|
4 |
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Returns the returnValue of the command processing. If {@link #isSuccess()} return <code>false</code>, this |
|
106
|
|
|
* method returns <code>null</code>. This method also returns <code>null</code> if response processing returned |
|
107
|
|
|
* a <code>null</code> value. |
|
108
|
|
|
* |
|
109
|
|
|
* @return mixed The return value of command processing |
|
110
|
|
|
*/ |
|
111
|
4 |
|
public function getReturnValue() |
|
112
|
|
|
{ |
|
113
|
4 |
|
if (!$this->success || null === $this->resultType) { |
|
114
|
2 |
|
return null; |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
2 |
|
return $this->result; |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* Returns the error of the command processing. If {@link #isSuccess()} return <code>true</code>, this |
|
122
|
|
|
* method returns <code>null</code>. |
|
123
|
|
|
* |
|
124
|
|
|
* @return \Exception The exception thrown during command processing |
|
125
|
|
|
*/ |
|
126
|
1 |
|
public function getError() |
|
127
|
|
|
{ |
|
128
|
1 |
|
if ($this->success) { |
|
129
|
|
|
return null; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
1 |
|
return $this->result; |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
|
|
136
|
|
|
/** |
|
137
|
|
|
* Whether the reply message represents a successfully executed command. In this case, successful means that the |
|
138
|
|
|
* command's execution did not result in an exception. |
|
139
|
|
|
* |
|
140
|
|
|
* @return boolean <code>true</code> if this reply contains a return value, <code>false</code> if it contains an error. |
|
141
|
|
|
*/ |
|
142
|
4 |
|
public function isSuccess() |
|
143
|
|
|
{ |
|
144
|
4 |
|
return $this->success; |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* @return string |
|
149
|
|
|
*/ |
|
150
|
4 |
|
public function getCommandIdentifier() |
|
151
|
|
|
{ |
|
152
|
4 |
|
return $this->commandIdentifier; |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* @return string |
|
158
|
|
|
*/ |
|
159
|
4 |
|
public function toBytes() |
|
160
|
|
|
{ |
|
161
|
4 |
|
$data = pack('a36n', $this->commandIdentifier, $this->success ? 1 : 0); |
|
162
|
|
|
|
|
163
|
|
|
// TODO payload revision |
|
164
|
4 |
|
if (null === $this->resultType) { |
|
165
|
1 |
|
$data .= pack(sprintf('Na%s', strlen(self::NULL)), strlen(self::NULL), self::NULL); |
|
166
|
1 |
|
} else { |
|
167
|
3 |
|
$data .= pack( |
|
168
|
3 |
|
sprintf('Na%sNa%s', strlen($this->resultType), strlen($this->serializedResult)), |
|
169
|
3 |
|
strlen($this->resultType), |
|
170
|
3 |
|
$this->resultType, |
|
171
|
3 |
|
strlen($this->serializedResult), |
|
172
|
3 |
|
$this->serializedResult |
|
173
|
3 |
|
); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
4 |
|
return $data; |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
/** |
|
180
|
|
|
* @param SerializerInterface $serializer The serialize to deserialize message contents with |
|
181
|
|
|
* @param mixed $data |
|
182
|
|
|
* @return self |
|
183
|
|
|
*/ |
|
184
|
4 |
|
public static function fromBytes( |
|
185
|
|
|
SerializerInterface $serializer, |
|
186
|
|
|
$data |
|
187
|
|
|
) { |
|
188
|
4 |
|
$raw = unpack("a36commandIdentifier/nsuccess", $data); |
|
189
|
4 |
|
$isSuccess = $raw['success'] === 1 ? true : false; |
|
190
|
4 |
|
$offset = 36 + 2; |
|
191
|
|
|
|
|
192
|
4 |
|
self::read($raw, $offset, $data, 'resultType'); |
|
193
|
|
|
|
|
194
|
4 |
|
if (self::NULL === $raw['resultType']) { |
|
195
|
1 |
|
return new self($raw['commandIdentifier'], $serializer, null, $isSuccess); |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
3 |
|
self::read($raw, $offset, $data, 'result'); |
|
199
|
|
|
|
|
200
|
3 |
|
$result = $serializer->deserialize( |
|
201
|
3 |
|
new SimpleSerializedObject($raw['result'], new SimpleSerializedType($raw['resultType'])) |
|
202
|
3 |
|
); |
|
203
|
|
|
|
|
204
|
3 |
|
return new self($raw['commandIdentifier'], $serializer, $result, $isSuccess); |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
/** |
|
208
|
|
|
* @param mixed $raw |
|
209
|
|
|
* @param int $offset |
|
210
|
|
|
* @param mixed $data |
|
211
|
|
|
* @param string $name |
|
212
|
|
|
*/ |
|
213
|
4 |
View Code Duplication |
private static function read(&$raw, &$offset, $data, $name) |
|
|
|
|
|
|
214
|
|
|
{ |
|
215
|
4 |
|
$raw = array_merge( |
|
216
|
4 |
|
$raw, |
|
217
|
4 |
|
unpack(sprintf("N%sLength", $name), substr($data, $offset)) |
|
218
|
4 |
|
); |
|
219
|
4 |
|
$offset += 4; |
|
220
|
|
|
|
|
221
|
4 |
|
$raw = array_merge( |
|
222
|
4 |
|
$raw, |
|
223
|
4 |
|
unpack( |
|
224
|
4 |
|
sprintf("a%s%s", $raw[sprintf("%sLength", $name)], $name), |
|
225
|
4 |
|
substr($data, $offset) |
|
226
|
4 |
|
) |
|
227
|
4 |
|
); |
|
228
|
4 |
|
$offset += $raw[sprintf("%sLength", $name)]; |
|
229
|
|
|
} |
|
230
|
|
|
} |
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.