1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace EventSauce\EventSourcing\CodeGeneration; |
4
|
|
|
|
5
|
|
|
use EventSauce\EventSourcing\PointInTime; |
6
|
|
|
|
7
|
|
|
final class DefinitionGroup |
8
|
|
|
{ |
9
|
|
|
/** |
10
|
|
|
* @var string |
11
|
|
|
*/ |
12
|
|
|
private $namespace; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* @var EventDefinition[] |
16
|
|
|
*/ |
17
|
|
|
private $events = []; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @var array |
21
|
|
|
*/ |
22
|
|
|
private $defaults = []; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var array <type, template> |
26
|
|
|
*/ |
27
|
|
|
private $typeSerializer = [ |
28
|
|
|
'string' => '({type}) {param}', |
29
|
|
|
'array' => '({type}) {param}', |
30
|
|
|
'integer' => '({type}) {param}', |
31
|
|
|
'int' => '({type}) {param}', |
32
|
|
|
'bool' => '({type}) {param}', |
33
|
|
|
'float' => '({type}) {param}', |
34
|
|
|
]; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var array <type, template> |
38
|
|
|
*/ |
39
|
|
|
private $typeDeserializer = [ |
40
|
|
|
'string' => '({type}) {param}', |
41
|
|
|
'array' => '({type}) {param}', |
42
|
|
|
'integer' => '({type}) {param}', |
43
|
|
|
'int' => '({type}) {param}', |
44
|
|
|
'bool' => '({type}) {param}', |
45
|
|
|
'float' => '({type}) {param}', |
46
|
|
|
]; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var array <field, template> |
50
|
|
|
*/ |
51
|
|
|
private $fieldSerializer = []; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var array <field, template> |
55
|
|
|
*/ |
56
|
|
|
private $fieldDeserializer = []; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var CommandDefinition[] |
60
|
|
|
*/ |
61
|
|
|
private $commands = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var string[] |
65
|
|
|
*/ |
66
|
|
|
private $typeAliases = []; |
67
|
|
|
|
68
|
3 |
|
public function __construct() |
69
|
|
|
{ |
70
|
3 |
|
$this->typeSerializer(PointInTime::class, '{param}->toString()'); |
71
|
3 |
|
$this->typeDeserializer(PointInTime::class, '{type}::fromString({param})'); |
72
|
3 |
|
} |
73
|
|
|
|
74
|
1 |
|
public static function create(string $namespace): DefinitionGroup |
75
|
|
|
{ |
76
|
1 |
|
return (new DefinitionGroup($namespace))->withNamespace($namespace); |
|
|
|
|
77
|
|
|
} |
78
|
|
|
|
79
|
3 |
|
public function withNamespace(string $namespace): DefinitionGroup |
80
|
|
|
{ |
81
|
3 |
|
$this->namespace = $namespace; |
82
|
|
|
|
83
|
3 |
|
return $this; |
84
|
|
|
} |
85
|
|
|
|
86
|
3 |
|
public function typeSerializer(string $type, string $template) |
87
|
|
|
{ |
88
|
3 |
|
$type = $this->resolveTypeAlias($type); |
89
|
|
|
|
90
|
3 |
|
$this->typeSerializer[TypeNormalizer::normalize($type)] = $template; |
91
|
3 |
|
} |
92
|
|
|
|
93
|
3 |
|
public function serializerForType($type) |
94
|
|
|
{ |
95
|
3 |
|
$type = $this->resolveTypeAlias($type); |
96
|
|
|
|
97
|
3 |
|
return $this->typeSerializer[$type] ?? "new {type}({param})"; |
98
|
|
|
} |
99
|
|
|
|
100
|
3 |
|
public function typeDeserializer(string $type, string $template) |
101
|
|
|
{ |
102
|
3 |
|
$this->typeDeserializer[TypeNormalizer::normalize($type)] = $template; |
103
|
3 |
|
} |
104
|
|
|
|
105
|
3 |
|
public function deserializerForType($type) |
106
|
|
|
{ |
107
|
3 |
|
$type = $this->resolveTypeAlias($type); |
108
|
|
|
|
109
|
3 |
|
return $this->typeDeserializer[$type] ?? "new {type}({param})"; |
110
|
|
|
} |
111
|
|
|
|
112
|
2 |
|
public function fieldSerializer(string $field, string $template) |
113
|
|
|
{ |
114
|
2 |
|
$this->fieldSerializer[$field] = $template; |
115
|
2 |
|
} |
116
|
|
|
|
117
|
3 |
|
public function serializerForField($field) |
118
|
|
|
{ |
119
|
3 |
|
return $this->fieldSerializer[$field] ?? null; |
120
|
|
|
} |
121
|
|
|
|
122
|
2 |
|
public function fieldDeserializer(string $field, string $template) |
123
|
|
|
{ |
124
|
2 |
|
$this->fieldDeserializer[$field] = $template; |
125
|
2 |
|
} |
126
|
|
|
|
127
|
3 |
|
public function deserializerForField($field) |
128
|
|
|
{ |
129
|
3 |
|
return $this->fieldDeserializer[$field] ?? null; |
130
|
|
|
} |
131
|
|
|
|
132
|
2 |
|
public function fieldDefault(string $name, string $type, string $example = null) |
133
|
|
|
{ |
134
|
2 |
|
$type = $this->resolveTypeAlias($type); |
135
|
2 |
|
$this->defaults[$name] = compact('type', 'example'); |
136
|
2 |
|
} |
137
|
|
|
|
138
|
1 |
|
public function aliasType(string $alias, string $type) |
139
|
|
|
{ |
140
|
1 |
|
$this->typeAliases[$alias] = TypeNormalizer::normalize($type); |
141
|
1 |
|
} |
142
|
|
|
|
143
|
3 |
|
public function resolveTypeAlias(string $alias = null) |
144
|
|
|
{ |
145
|
3 |
|
while (isset($this->typeAliases[$alias])) { |
146
|
1 |
|
$alias = $this->typeAliases[$alias]; |
147
|
|
|
} |
148
|
|
|
|
149
|
3 |
|
return $alias; |
150
|
|
|
} |
151
|
|
|
|
152
|
3 |
|
public function event(string $name): EventDefinition |
153
|
|
|
{ |
154
|
3 |
|
return $this->events[] = new EventDefinition($this, $name); |
155
|
|
|
} |
156
|
|
|
|
157
|
3 |
|
public function command(string $name) |
158
|
|
|
{ |
159
|
3 |
|
return $this->commands[] = new CommandDefinition($this, $name); |
160
|
|
|
} |
161
|
|
|
|
162
|
2 |
|
public function typeForField(string $field): string |
163
|
|
|
{ |
164
|
2 |
|
return $this->defaults[$field]['type'] ?? 'string'; |
165
|
|
|
} |
166
|
|
|
|
167
|
2 |
|
public function exampleForField(string $field) |
168
|
|
|
{ |
169
|
2 |
|
return $this->defaults[$field]['example'] ?? null; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @return EventDefinition[] |
174
|
|
|
*/ |
175
|
3 |
|
public function events(): array |
176
|
|
|
{ |
177
|
3 |
|
return $this->events; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* @return CommandDefinition[] |
182
|
|
|
*/ |
183
|
3 |
|
public function commands(): array |
184
|
|
|
{ |
185
|
3 |
|
return $this->commands; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
public function namespace(): string |
|
|
|
|
189
|
|
|
{ |
190
|
|
|
return $this->namespace; |
191
|
|
|
} |
192
|
|
|
} |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.