Completed
Push — 6.0-dev ( ceea66...191b00 )
by Simonas
03:10 queued 01:39
created

DocumentGenerator::getAnnotationOptions()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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