1 | <?php |
||
15 | class CodeDumper |
||
16 | { |
||
17 | /** |
||
18 | * @var DefinitionGroup |
||
19 | */ |
||
20 | private $definitionGroup; |
||
21 | |||
22 | 5 | public function dump(DefinitionGroup $definitionGroup, bool $withHelpers = true, bool $withSerialization = true): string |
|
23 | { |
||
24 | 5 | $this->definitionGroup = $definitionGroup; |
|
25 | 5 | $eventsCode = $this->dumpEvents($definitionGroup->events(), $withHelpers, $withSerialization); |
|
26 | 5 | $commandCode = $this->dumpCommands($definitionGroup->commands()); |
|
27 | 4 | $namespace = $definitionGroup->namespace(); |
|
28 | 4 | $allCode = join(array_filter([$eventsCode, $commandCode]), "\n\n"); |
|
29 | |||
30 | 4 | if ($withSerialization) { |
|
31 | 4 | $namespace .= "; |
|
32 | |||
33 | use EventSauce\EventSourcing\Serialization\SerializableEvent"; |
||
34 | |||
35 | } |
||
36 | |||
37 | return <<<EOF |
||
38 | <?php |
||
39 | |||
40 | 4 | namespace $namespace; |
|
41 | |||
42 | 4 | $allCode |
|
43 | |||
44 | EOF; |
||
45 | } |
||
46 | |||
47 | 5 | private function dumpEvents(array $events, bool $withHelpers, bool $withSerialization): string |
|
48 | { |
||
49 | 5 | $code = []; |
|
50 | |||
51 | 5 | if (empty($events)) { |
|
52 | 2 | return ''; |
|
53 | } |
||
54 | |||
55 | 4 | foreach ($events as $event) { |
|
56 | 4 | $name = $event->name(); |
|
57 | 4 | $fields = $this->dumpFields($event); |
|
58 | 4 | $constructor = $this->dumpConstructor($event); |
|
59 | 4 | $methods = $this->dumpMethods($event); |
|
60 | 4 | $deserializer = $this->dumpSerializationMethods($event); |
|
61 | 4 | $testHelpers = $withHelpers ? $this->dumpTestHelpers($event) : ''; |
|
62 | 4 | $implements = $withSerialization ? ' implements SerializableEvent' : ''; |
|
63 | |||
64 | 4 | $code[] = <<<EOF |
|
65 | 4 | final class $name$implements |
|
66 | { |
||
67 | 4 | $fields$constructor$methods$deserializer |
|
68 | |||
69 | 4 | $testHelpers} |
|
70 | |||
71 | |||
72 | EOF; |
||
73 | } |
||
74 | |||
75 | 4 | return rtrim(join('', $code)); |
|
76 | } |
||
77 | |||
78 | 5 | private function dumpFields(DefinitionWithFields $definition): string |
|
79 | { |
||
80 | 5 | $fields = $this->fieldsFromDefinition($definition); |
|
81 | 4 | $code = []; |
|
82 | 4 | $code[] = <<<EOF |
|
83 | |||
84 | EOF; |
||
85 | |||
86 | 4 | foreach ($fields as $field) { |
|
87 | 4 | $name = $field['name']; |
|
88 | 4 | $type = $field['type']; |
|
89 | |||
90 | 4 | $code[] = <<<EOF |
|
91 | /** |
||
92 | 4 | * @var $type |
|
93 | */ |
||
94 | 4 | private \$$name; |
|
95 | |||
96 | |||
97 | EOF; |
||
98 | } |
||
99 | |||
100 | 4 | return join('', $code); |
|
101 | } |
||
102 | |||
103 | 4 | private function dumpConstructor(DefinitionWithFields $definition): string |
|
104 | { |
||
105 | 4 | $arguments = []; |
|
106 | 4 | $assignments = []; |
|
107 | 4 | $fields = $this->fieldsFromDefinition($definition); |
|
108 | |||
109 | 4 | if (empty($fields)) { |
|
110 | 1 | return ''; |
|
111 | } |
||
112 | |||
113 | 4 | foreach ($fields as $field) { |
|
114 | 4 | $arguments[] = sprintf(' %s $%s', $field['type'], $field['name']); |
|
115 | 4 | $assignments[] = sprintf(' $this->%s = $%s;', $field['name'], $field['name']); |
|
116 | } |
||
117 | |||
118 | 4 | $arguments = join(",\n", $arguments); |
|
119 | 4 | $assignments = join("\n", $assignments); |
|
120 | |||
121 | return <<<EOF |
||
122 | public function __construct( |
||
123 | 4 | $arguments |
|
124 | ) { |
||
125 | 4 | $assignments |
|
126 | } |
||
127 | |||
128 | |||
129 | EOF; |
||
130 | } |
||
131 | |||
132 | 4 | private function dumpMethods(DefinitionWithFields $command): string |
|
133 | { |
||
134 | 4 | $methods = []; |
|
135 | |||
136 | 4 | foreach ($this->fieldsFromDefinition($command) as $field) { |
|
137 | 4 | $methods[] = <<<EOF |
|
138 | 4 | public function {$field['name']}(): {$field['type']} |
|
139 | { |
||
140 | 4 | return \$this->{$field['name']}; |
|
141 | } |
||
142 | |||
143 | |||
144 | EOF; |
||
145 | } |
||
146 | |||
147 | 4 | return empty($methods) ? '' : rtrim(join('', $methods)) . "\n"; |
|
148 | } |
||
149 | |||
150 | 4 | private function dumpSerializationMethods(EventDefinition $event) |
|
151 | { |
||
152 | 4 | $name = $event->name(); |
|
153 | 4 | $arguments = []; |
|
154 | 4 | $serializers = []; |
|
155 | |||
156 | 4 | foreach ($this->fieldsFromDefinition($event) as $field) { |
|
157 | 4 | $parameter = sprintf('$payload[\'%s\']', $field['name']); |
|
158 | 4 | $template = $event->deserializerForField($field['name']) |
|
159 | 4 | ?: $event->deserializerForType($field['type']); |
|
160 | 4 | $arguments[] = trim(strtr($template, ['{type}' => $field['type'], '{param}' => $parameter])); |
|
161 | |||
162 | 4 | $property = sprintf('$this->%s', $field['name']); |
|
163 | 4 | $template = $event->serializerForField($field['name']) |
|
164 | 4 | ?: $event->serializerForType($field['type']); |
|
165 | 4 | $template = sprintf("'%s' => %s", $field['name'], $template); |
|
166 | 4 | $serializers[] = trim(strtr($template, ['{type}' => $field['type'], '{param}' => $property])); |
|
167 | } |
||
168 | |||
169 | 4 | $arguments = preg_replace('/^.{2,}$/m', ' $0', join(",\n", $arguments)); |
|
170 | |||
171 | 4 | if ( ! empty($arguments)) { |
|
172 | 4 | $arguments = "\n$arguments"; |
|
173 | } |
||
174 | |||
175 | 4 | $serializers = preg_replace('/^.{2,}$/m', ' $0', join(",\n", $serializers)); |
|
176 | |||
177 | 4 | if ( ! empty($serializers)) { |
|
178 | 4 | $serializers = "\n$serializers,\n "; |
|
179 | } |
||
180 | |||
181 | return <<<EOF |
||
182 | public static function fromPayload(array \$payload): SerializableEvent |
||
183 | { |
||
184 | 4 | return new $name($arguments); |
|
185 | } |
||
186 | |||
187 | public function toPayload(): array |
||
188 | { |
||
189 | 4 | return [$serializers]; |
|
190 | } |
||
191 | EOF; |
||
192 | } |
||
193 | |||
194 | 2 | private function dumpTestHelpers(EventDefinition $event): string |
|
195 | { |
||
196 | 2 | $constructor = []; |
|
197 | 2 | $constructorArguments = ''; |
|
198 | 2 | $constructorValues = []; |
|
199 | 2 | $helpers = []; |
|
200 | |||
201 | 2 | foreach ($this->fieldsFromDefinition($event) as $field) { |
|
202 | 2 | if (null === $field['example']) { |
|
203 | 2 | $constructor[] = ucfirst($field['name']); |
|
204 | |||
205 | 2 | if ('' !== $constructorArguments) { |
|
206 | 1 | $constructorArguments .= ', '; |
|
207 | } |
||
208 | |||
209 | 2 | $constructorArguments .= sprintf('%s $%s', $field['type'], $field['name']); |
|
210 | 2 | $constructorValues[] = sprintf('$%s', $field['name']); |
|
211 | } else { |
||
212 | 2 | $constructorValues[] = $this->dumpConstructorValue($field, $event); |
|
213 | 2 | $method = sprintf('with%s', ucfirst($field['name'])); |
|
214 | 2 | $helpers[] = <<<EOF |
|
215 | /** |
||
216 | * @codeCoverageIgnore |
||
217 | */ |
||
218 | 2 | public function $method({$field['type']} \${$field['name']}): {$event->name()} |
|
219 | { |
||
220 | 2 | \$this->{$field['name']} = \${$field['name']}; |
|
221 | |||
222 | return \$this; |
||
223 | } |
||
224 | |||
225 | |||
226 | EOF; |
||
227 | } |
||
228 | } |
||
229 | |||
230 | 2 | $constructor = sprintf('with%s', join('And', $constructor)); |
|
231 | 2 | $constructorValues = join(",\n ", $constructorValues); |
|
232 | |||
233 | 2 | if ('' !== $constructorValues) { |
|
234 | 2 | $constructorValues = "\n $constructorValues\n "; |
|
235 | } |
||
236 | |||
237 | 2 | $helpers[] = <<<EOF |
|
238 | /** |
||
239 | * @codeCoverageIgnore |
||
240 | */ |
||
241 | 2 | public static function $constructor($constructorArguments): {$event->name()} |
|
242 | { |
||
243 | 2 | return new {$event->name()}($constructorValues); |
|
244 | } |
||
245 | |||
246 | |||
247 | EOF; |
||
248 | |||
249 | 2 | return rtrim(join('', $helpers)) . "\n"; |
|
250 | } |
||
251 | |||
252 | 2 | private function dumpConstructorValue(array $field, EventDefinition $event): string |
|
265 | |||
266 | /** |
||
267 | * @param CommandDefinition[] $commands |
||
268 | * |
||
269 | * @return string |
||
270 | */ |
||
271 | 5 | private function dumpCommands(array $commands): string |
|
272 | { |
||
273 | 5 | $code = []; |
|
274 | |||
275 | 5 | foreach ($commands as $command) { |
|
276 | 4 | $code[] = <<<EOF |
|
277 | 5 | final class {$command->name()} |
|
278 | { |
||
279 | 5 | {$this->dumpFields($command)}{$this->dumpConstructor($command)}{$this->dumpMethods($command)}} |
|
280 | |||
281 | |||
282 | EOF; |
||
283 | } |
||
284 | |||
285 | 4 | return rtrim(join('', $code)); |
|
286 | } |
||
287 | |||
288 | /** |
||
289 | * @param DefinitionWithFields $definition |
||
290 | * |
||
291 | * @return array |
||
292 | */ |
||
293 | 5 | private function fieldsFromDefinition(DefinitionWithFields $definition): array |
|
303 | |||
304 | 5 | private function fieldsFrom(string $fieldsFrom): array |
|
305 | { |
||
306 | 5 | if (empty($fieldsFrom)) { |
|
307 | 4 | return []; |
|
308 | } |
||
324 | } |
||
325 |