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