Completed
Pull Request — 5.2 (#857)
by
unknown
01:55
created

DocumentGenerator::generateDocumentDocBlock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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