1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the ONGR package. |
5
|
|
|
* |
6
|
|
|
* (c) NFQ Technologies UAB <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace ONGR\ElasticsearchBundle\Generator; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Document Generator |
16
|
|
|
*/ |
17
|
|
|
class DocumentGenerator |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @var string |
21
|
|
|
*/ |
22
|
|
|
private $spaces = ' '; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
private $getMethodTemplate = |
28
|
|
|
'/** |
29
|
|
|
* Returns <fieldName> |
30
|
|
|
* |
31
|
|
|
* @return string |
32
|
|
|
*/ |
33
|
|
|
public function get<methodName>() |
34
|
|
|
{ |
35
|
|
|
<spaces>return $this-><fieldName>; |
36
|
|
|
}'; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
private $setMethodTemplate = |
42
|
|
|
'/** |
43
|
|
|
* Sets <fieldName> |
44
|
|
|
* |
45
|
|
|
* @param string $<fieldName> |
46
|
|
|
*/ |
47
|
|
|
public function set<methodName>($<fieldName>) |
48
|
|
|
{ |
49
|
|
|
<spaces>$this-><fieldName> = $<fieldName>; |
50
|
|
|
}'; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
private $constructorTemplate = |
56
|
|
|
'/** |
57
|
|
|
* Constructor |
58
|
|
|
*/ |
59
|
|
|
public function __construct() |
60
|
|
|
{ |
61
|
|
|
<fields> |
62
|
|
|
}'; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @param array $metadata |
66
|
|
|
* |
67
|
|
|
* @return string |
68
|
|
|
*/ |
69
|
|
|
public function generateDocumentClass(array $metadata) |
70
|
|
|
{ |
71
|
|
|
return implode( |
72
|
|
|
"\n", |
73
|
|
|
[ |
74
|
|
|
"<?php\n", |
75
|
|
|
sprintf('namespace %s;', substr($metadata['name'], 0, strrpos($metadata['name'], '\\'))) . "\n", |
76
|
|
|
$this->generateDocumentUse($metadata), |
77
|
|
|
$this->generateDocumentDocBlock($metadata), |
78
|
|
|
'class ' . $this->getClassName($metadata), |
79
|
|
|
"{", |
80
|
|
|
str_replace('<spaces>', $this->spaces, $this->generateDocumentBody($metadata)), |
81
|
|
|
"}\n" |
82
|
|
|
] |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Generates document body |
88
|
|
|
* |
89
|
|
|
* @param array $metadata |
90
|
|
|
* |
91
|
|
|
* @return string |
92
|
|
|
*/ |
93
|
|
|
private function generateDocumentBody(array $metadata) |
94
|
|
|
{ |
95
|
|
|
$lines = []; |
96
|
|
|
|
97
|
|
|
if ($properties = $this->generateDocumentProperties($metadata)) { |
98
|
|
|
$lines[] = $properties; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
if ($this->hasMultipleEmbedded($metadata)) { |
102
|
|
|
$lines[] = $this->generateDocumentConstructor($metadata); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
if ($methods = $this->generateDocumentMethods($metadata)) { |
106
|
|
|
$lines[] = $methods; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
return rtrim(implode("\n", $lines)); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Generates document properties |
114
|
|
|
* |
115
|
|
|
* @param array $metadata |
116
|
|
|
* |
117
|
|
|
* @return string |
118
|
|
|
*/ |
119
|
|
View Code Duplication |
private function generateDocumentProperties(array $metadata) |
|
|
|
|
120
|
|
|
{ |
121
|
|
|
$lines = []; |
122
|
|
|
|
123
|
|
|
foreach ($metadata['properties'] as $property) { |
124
|
|
|
$lines[] = $this->generatePropertyDocBlock($property); |
125
|
|
|
$lines[] = $this->spaces . 'private $' . $property['field_name'] . ";\n"; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
return implode("\n", $lines); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Generates document methods |
133
|
|
|
* |
134
|
|
|
* @param array $metadata |
135
|
|
|
* |
136
|
|
|
* @return string |
137
|
|
|
*/ |
138
|
|
View Code Duplication |
private function generateDocumentMethods(array $metadata) |
|
|
|
|
139
|
|
|
{ |
140
|
|
|
$lines = []; |
141
|
|
|
|
142
|
|
|
foreach ($metadata['properties'] as $property) { |
143
|
|
|
$lines[] = $this->generateDocumentMethod($property, $this->setMethodTemplate) . "\n"; |
144
|
|
|
$lines[] = $this->generateDocumentMethod($property, $this->getMethodTemplate) . "\n"; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
return implode("\n", $lines); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Generates document constructor |
152
|
|
|
* |
153
|
|
|
* @param array $metadata |
154
|
|
|
* |
155
|
|
|
* @return string |
156
|
|
|
*/ |
157
|
|
|
private function generateDocumentConstructor(array $metadata) |
158
|
|
|
{ |
159
|
|
|
$fields = []; |
160
|
|
|
|
161
|
|
|
foreach ($metadata['properties'] as $prop) { |
162
|
|
|
if ($prop['annotation'] == 'embedded' && isset($prop['property_multiple']) && $prop['property_multiple']) { |
163
|
|
|
$fields[] = sprintf('%s$this->%s = new Collection();', $this->spaces, $prop['field_name']); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return $this->prefixWithSpaces( |
168
|
|
|
str_replace('<fields>', implode("\n", $fields), $this->constructorTemplate) |
169
|
|
|
) . "\n"; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Generates document method |
174
|
|
|
* |
175
|
|
|
* @param array $metadata |
176
|
|
|
* @param string $template |
177
|
|
|
* |
178
|
|
|
* @return string |
179
|
|
|
*/ |
180
|
|
|
private function generateDocumentMethod(array $metadata, $template) |
181
|
|
|
{ |
182
|
|
|
return $this->prefixWithSpaces( |
183
|
|
|
str_replace( |
184
|
|
|
['<methodName>', '<fieldName>'], |
185
|
|
|
[ucfirst($metadata['field_name']), $metadata['field_name']], |
186
|
|
|
$template |
187
|
|
|
) |
188
|
|
|
); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Returns property doc block |
193
|
|
|
* |
194
|
|
|
* @param array $metadata |
195
|
|
|
* |
196
|
|
|
* @return string |
197
|
|
|
*/ |
198
|
|
|
private function generatePropertyDocBlock(array $metadata) |
199
|
|
|
{ |
200
|
|
|
$lines = [ |
201
|
|
|
$this->spaces . '/**', |
202
|
|
|
$this->spaces . ' * @var string', |
203
|
|
|
$this->spaces . ' *', |
204
|
|
|
]; |
205
|
|
|
|
206
|
|
|
$column = []; |
207
|
|
|
if (isset($metadata['property_name']) && $metadata['property_name'] != $metadata['field_name']) { |
208
|
|
|
$column[] = 'name="' . $metadata['property_name'] . '"'; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
if (isset($metadata['property_class'])) { |
212
|
|
|
$column[] = 'class="' . $metadata['property_class'] . '"'; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
if (isset($metadata['property_multiple']) && $metadata['property_multiple']) { |
216
|
|
|
$column[] = 'multiple=true'; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
if (isset($metadata['property_type']) && $metadata['annotation'] == 'property') { |
220
|
|
|
$column[] = 'type="' . $metadata['property_type'] . '"'; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
if (isset($metadata['property_default'])) { |
224
|
|
|
$column[] = 'default="' . $metadata['property_default'] . '"'; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
if (isset($metadata['property_options']) && $metadata['property_options']) { |
228
|
|
|
$column[] = 'options={' . $metadata['property_options'] . '}'; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
$lines[] = $this->spaces . ' * @ES\\' . ucfirst($metadata['annotation']) . '(' . implode(', ', $column) . ')'; |
232
|
|
|
|
233
|
|
|
$lines[] = $this->spaces . ' */'; |
234
|
|
|
|
235
|
|
|
return implode("\n", $lines); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Generates document doc block |
240
|
|
|
* |
241
|
|
|
* @param array $metadata |
242
|
|
|
* |
243
|
|
|
* @return string |
244
|
|
|
*/ |
245
|
|
|
private function generateDocumentDocBlock(array $metadata) |
246
|
|
|
{ |
247
|
|
|
return str_replace( |
248
|
|
|
['<className>', '<annotation>', '<options>'], |
249
|
|
|
[ |
250
|
|
|
$this->getClassName($metadata), |
251
|
|
|
ucfirst($metadata['annotation']), |
252
|
|
|
$metadata['type'] != lcfirst($this->getClassName($metadata)) |
253
|
|
|
? sprintf('type="%s"', $metadata['type']) : '', |
254
|
|
|
], |
255
|
|
|
'/** |
256
|
|
|
* <className> |
257
|
|
|
* |
258
|
|
|
* @ES\<annotation>(<options>) |
259
|
|
|
*/' |
260
|
|
|
); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* @param string $code |
265
|
|
|
* |
266
|
|
|
* @return string |
267
|
|
|
*/ |
268
|
|
|
private function prefixWithSpaces($code) |
269
|
|
|
{ |
270
|
|
|
$lines = explode("\n", $code); |
271
|
|
|
|
272
|
|
|
foreach ($lines as $key => $value) { |
273
|
|
|
if ($value) { |
274
|
|
|
$lines[$key] = $this->spaces . $lines[$key]; |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
return implode("\n", $lines); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Returns class name |
283
|
|
|
* |
284
|
|
|
* @param array $metadata |
285
|
|
|
* |
286
|
|
|
* @return string |
287
|
|
|
*/ |
288
|
|
|
private function getClassName(array $metadata) |
289
|
|
|
{ |
290
|
|
|
return ($pos = strrpos($metadata['name'], '\\')) |
291
|
|
|
? substr($metadata['name'], $pos + 1, strlen($metadata['name'])) : $metadata['name']; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Generates document use statements |
296
|
|
|
* |
297
|
|
|
* @param array $metadata |
298
|
|
|
* |
299
|
|
|
* @return string |
300
|
|
|
*/ |
301
|
|
|
private function generateDocumentUse(array $metadata) |
302
|
|
|
{ |
303
|
|
|
$uses = ['use ONGR\ElasticsearchBundle\Annotation as ES;']; |
304
|
|
|
|
305
|
|
|
if ($this->hasMultipleEmbedded($metadata)) { |
306
|
|
|
$uses[] = 'use ONGR\ElasticsearchBundle\Collection\Collection;'; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
return implode("\n", $uses) . "\n"; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
/** |
313
|
|
|
* @param array $metadata |
314
|
|
|
* |
315
|
|
|
* @return bool |
316
|
|
|
*/ |
317
|
|
|
private function hasMultipleEmbedded(array $metadata) |
318
|
|
|
{ |
319
|
|
|
foreach ($metadata['properties'] as $prop) { |
320
|
|
|
if ($prop['annotation'] == 'embedded' && isset($prop['property_multiple']) && $prop['property_multiple']) { |
321
|
|
|
return true; |
322
|
|
|
} |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
return false; |
326
|
|
|
} |
327
|
|
|
} |
328
|
|
|
|
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.