Completed
Push — master ( 0310f8...7cc681 )
by Frank
02:04
created

CodeDumper::dumpTestHelpers()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 47
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 3

Importance

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