Completed
Push — master ( 6efea1...0e768a )
by Simonas
04:33 queued 10s
created

validatePropertyVisibility()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
dl 11
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
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\Command;
13
14
use ONGR\ElasticsearchBundle\Mapping\MetadataCollector;
15
use Symfony\Component\Console\Helper\FormatterHelper;
16
use Symfony\Component\Console\Helper\QuestionHelper;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Question\ConfirmationQuestion;
20
use Symfony\Component\Console\Question\Question;
21
use Symfony\Component\HttpKernel\Kernel;
22
23
class DocumentGenerateCommand extends AbstractManagerAwareCommand
24
{
25
    /**
26
     * @var QuestionHelper
27
     */
28
    private $questionHelper;
29
30
    /**
31
     * @var string[]
32
     */
33
    private $propertyAnnotations;
34
35
    /**
36
     * @var string[]
37
     */
38
    private $propertyVisibilities;
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    protected function configure()
44
    {
45
        parent::configure();
46
47
        $this
48
            ->setName('ongr:es:document:generate')
49
            ->setDescription('Generates a new Elasticsearch document inside a bundle');
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function execute(InputInterface $input, OutputInterface $output)
56
    {
57
        if ($input->hasParameterOption(['--no-interaction', '-n'])) {
58
            throw $this->getException('No interaction mode is not allowed!');
59
        }
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    protected function interact(InputInterface $input, OutputInterface $output)
66
    {
67
        /** @var FormatterHelper $formatter */
68
        $formatter = $this->getHelperSet()->get('formatter');
69
        $this->questionHelper = new QuestionHelper();
70
71
        $output->writeln(
72
            [
73
                '',
74
                $formatter->formatBlock('Welcome to the Elasticsearch Bundle document generator', 'bg=blue', true),
75
                '',
76
                'This command helps you generate ONGRElasticsearchBundle documents.',
77
                '',
78
                'First, you need to give the document name you want to generate.',
79
                'You must use the shortcut notation like <comment>AcmeDemoBundle:Post</comment>.',
80
                '',
81
            ]
82
        );
83
84
        /** @var Kernel $kernel */
85
        $kernel = $this->getContainer()->get('kernel');
86
        $bundleNames = array_keys($kernel->getBundles());
87
88
        while (true) {
89
            $document = $this->questionHelper->ask(
90
                $input,
91
                $output,
92
                $this->getQuestion('The Document shortcut name', null, [$this, 'validateDocumentName'], $bundleNames)
93
            );
94
95
            list($bundle, $document) = $this->parseShortcutNotation($document);
96
97
            if (in_array(strtolower($document), $this->getReservedKeywords())) {
98
                $output->writeln($this->getException('"%s" is a reserved word.', [$document])->getMessage());
99
                continue;
100
            }
101
102
            try {
103
                if (!file_exists(
104
                    $kernel->getBundle($bundle)->getPath() . '/Document/' . str_replace('\\', '/', $document) . '.php'
105
                )) {
106
                    break;
107
                }
108
109
                $output->writeln(
110
                    $this->getException('Document "%s:%s" already exists.', [$bundle, $document])->getMessage()
111
                );
112
            } catch (\Exception $e) {
113
                $output->writeln($this->getException('Bundle "%s" does not exist.', [$bundle])->getMessage());
114
            }
115
        }
116
117
        $output->writeln($this->getOptionsLabel($this->getDocumentAnnotations(), 'Available types'));
118
        $annotation = $this->questionHelper->ask(
119
            $input,
120
            $output,
121
            $this->getQuestion(
122
                'Document type',
123
                'document',
124
                [$this, 'validateDocumentAnnotation'],
125
                $this->getDocumentAnnotations()
126
            )
127
        );
128
129
        $this->propertyAnnotations = ['embedded', 'property'];
130
        $documentType = lcfirst($document);
0 ignored issues
show
Bug introduced by
The variable $document does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
131
132
        if ($annotation == 'document') {
133
            $this->propertyAnnotations = ['embedded', 'id', 'parentDocument', 'property', 'ttl'];
134
            $documentType = $this->questionHelper->ask(
135
                $input,
136
                $output,
137
                $this->getQuestion(
138
                    "\n" . 'Elasticsearch Document name',
139
                    lcfirst($document),
140
                    [$this, 'validateFieldName']
141
                )
142
            );
143
        }
144
145
        $properties = [];
146
        $output->writeln(['', $formatter->formatBlock('New Document Property?', 'bg=blue;fg=white', true)]);
147
148
        while (true) {
149
            $property = [];
150
            $question = $this->getQuestion(
151
                'Property name [<comment>press <info><return></info> to stop</comment>]',
152
                false
153
            );
154
155
            if (!$field = $this->questionHelper->ask($input, $output, $question)) {
156
                break;
157
            }
158
159
            foreach ($properties as $previousProperty) {
160
                if ($previousProperty['field_name'] == $field) {
161
                    $output->writeln($this->getException('Duplicate field name "%s"', [$field])->getMessage());
162
                    continue(2);
163
                }
164
            }
165
166
            try {
167
                $this->validateFieldName($field);
168
            } catch (\InvalidArgumentException $e) {
169
                $output->writeln($e->getMessage());
170
                continue;
171
            }
172
173
            $this->propertyVisibilities  = ['private', 'protected', 'public'];
174
            $output->writeln($this->getOptionsLabel($this->propertyVisibilities, 'Available visibilities'));
175
            $property['visibility'] = $this->questionHelper->ask(
176
                $input,
177
                $output,
178
                $this->getQuestion(
179
                    'Property visibility',
180
                    'private',
181
                    [$this, 'validatePropertyVisibility'],
182
                    $this->propertyVisibilities
183
                )
184
            );
185
186
            $output->writeln($this->getOptionsLabel($this->propertyAnnotations, 'Available annotations'));
187
            $property['annotation'] = $this->questionHelper->ask(
188
                $input,
189
                $output,
190
                $this->getQuestion(
191
                    'Property meta field',
192
                    'property',
193
                    [$this, 'validatePropertyAnnotation'],
194
                    $this->propertyAnnotations
195
                )
196
            );
197
198
            $property['field_name'] = $property['property_name'] = $field;
199
200
            switch ($property['annotation']) {
201
                case 'embedded':
202
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
203
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
204
205
                    $question = new ConfirmationQuestion("\n<info>Multiple</info> [<comment>no</comment>]: ", false);
206
                    $question->setAutocompleterValues(['yes', 'no']);
0 ignored issues
show
Documentation introduced by
array('yes', 'no') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a null|object<Symfony\Comp...sole\Question\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
207
                    $property['property_multiple'] = $this->questionHelper->ask($input, $output, $question);
208
209
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
210
                    break;
211 View Code Duplication
                case 'parentDocument':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
212
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
213
                        $output->writeln(
214
                            $this
215
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
216
                                ->getMessage()
217
                        );
218
                        continue(2);
219
                    }
220
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
221
                    break;
222
                case 'property':
223
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
224
225
                    $output->writeln($this->getOptionsLabel($this->getPropertyTypes(), 'Available types'));
226
                    $property['property_type'] = $this->questionHelper->ask(
227
                        $input,
228
                        $output,
229
                        $this->getQuestion(
230
                            'Property type',
231
                            'text',
232
                            [$this, 'validatePropertyType'],
233
                            $this->getPropertyTypes()
234
                        )
235
                    );
236
237
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
238
                    break;
239 View Code Duplication
                case 'ttl':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
240
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
241
                        $output->writeln(
242
                            $this
243
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
244
                                ->getMessage()
245
                        );
246
                        continue(2);
247
                    }
248
                    $property['property_default'] = $this->questionHelper->ask(
249
                        $input,
250
                        $output,
251
                        $this->getQuestion("\n" . 'Default time to live')
252
                    );
253
                    break;
254
                case 'id':
255
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
256
                        $output->writeln(
257
                            $this
258
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
259
                                ->getMessage()
260
                        );
261
                        continue(2);
262
                    }
263
                    break;
264
            }
265
266
            $properties[] = $property;
267
            $output->writeln(['', $formatter->formatBlock('New Document Property', 'bg=blue;fg=white', true)]);
268
        }
269
270
        $this->getContainer()->get('es.generate')->generate(
271
            $this->getContainer()->get('kernel')->getBundle($bundle),
0 ignored issues
show
Bug introduced by
The variable $bundle does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
272
            $document,
273
            $annotation,
274
            $documentType,
275
            $properties
276
        );
277
    }
278
279
    /**
280
     * @param array  $properties
281
     * @param string $annotation
282
     *
283
     * @return string
284
     */
285
    private function isUniqueAnnotation($properties, $annotation)
286
    {
287
        foreach ($properties as $property) {
288
            if ($property['annotation'] == $annotation) {
289
                return false;
290
            }
291
        }
292
293
        return true;
294
    }
295
296
    /**
297
     * Asks for property name
298
     *
299
     * @param InputInterface  $input
300
     * @param OutputInterface $output
301
     * @param string          $default
302
     *
303
     * @return string
304
     */
305
    private function askForPropertyName(InputInterface $input, OutputInterface $output, $default = null)
306
    {
307
        return $this->questionHelper->ask(
308
            $input,
309
            $output,
310
            $this->getQuestion("\n" . 'Property name in Elasticsearch', $default, [$this, 'validateFieldName'])
311
        );
312
    }
313
314
    /**
315
     * Asks for property options
316
     *
317
     * @param InputInterface  $input
318
     * @param OutputInterface $output
319
     *
320
     * @return string
321
     */
322
    private function askForPropertyOptions(InputInterface $input, OutputInterface $output)
323
    {
324
        $output->writeln(
325
            "\n"
326
                . '<info>Enter property options, for example <comment>"index"="not_analyzed"</comment>'
327
                . ' allows mapper to index this field, so it is searchable, but value will be not analyzed.</info>'
328
        );
329
330
        return $this->questionHelper->ask(
331
            $input,
332
            $output,
333
            $this->getQuestion(
334
                'Property options [<comment>press <info><return></info> to stop</comment>]',
335
                false,
336
                null,
337
                ['"index"="not_analyzed"', '"analyzer"="standard"']
338
            )
339
        );
340
    }
341
342
    /**
343
     * Asks for property class
344
     *
345
     * @param InputInterface  $input
346
     * @param OutputInterface $output
347
     *
348
     * @return string
349
     */
350
    private function askForPropertyClass(InputInterface $input, OutputInterface $output)
351
    {
352
        return $this->questionHelper->ask(
353
            $input,
354
            $output,
355
            $this->getQuestion(
356
                "\n" . 'Property class',
357
                null,
358
                [$this, 'validatePropertyClass'],
359
                array_merge($this->getDocumentClasses(), array_keys($this->getContainer()->get('kernel')->getBundles()))
360
            )
361
        );
362
    }
363
364
    /**
365
     * Returns available document classes
366
     *
367
     * @return array
368
     */
369
    private function getDocumentClasses()
370
    {
371
        /** @var MetadataCollector $metadataCollector */
372
        $metadataCollector = $this->getContainer()->get('es.metadata_collector');
373
        $classes = [];
374
375
        foreach ($this->getContainer()->getParameter('es.managers') as $manager) {
376
            $documents = $metadataCollector->getMappings($manager['mappings']);
377
            foreach ($documents as $document) {
378
                $classes[] = sprintf('%s:%s', $document['bundle'], $document['class']);
379
            }
380
        }
381
382
        return $classes;
383
    }
384
385
    /**
386
     * Parses shortcut notation
387
     *
388
     * @param string $shortcut
389
     *
390
     * @return string[]
391
     * @throws \InvalidArgumentException
392
     */
393
    private function parseShortcutNotation($shortcut)
394
    {
395
        $shortcut = str_replace('/', '\\', $shortcut);
396
397
        if (false === $pos = strpos($shortcut, ':')) {
398
            throw $this->getException(
399
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
400
                [$shortcut]
401
            );
402
        }
403
404
        return [substr($shortcut, 0, $pos), substr($shortcut, $pos + 1)];
405
    }
406
407
    /**
408
     * Validates property class
409
     *
410
     * @param string $input
411
     *
412
     * @return string
413
     * @throws \InvalidArgumentException
414
     */
415
    public function validatePropertyClass($input)
416
    {
417
        list($bundle, $document) = $this->parseShortcutNotation($input);
418
419
        try {
420
            $bundlePath = $this->getContainer()->get('kernel')->getBundle($bundle)->getPath();
421
        } catch (\Exception $e) {
422
            throw $this->getException('Bundle "%s" does not exist.', [$bundle]);
423
        }
424
425
        if (!file_exists($bundlePath . '/Document/' . str_replace('\\', '/', $document) . '.php')) {
426
            throw $this->getException('Document "%s:%s" does not exist.', [$bundle, $document]);
427
        }
428
429
        return $input;
430
    }
431
432
    /**
433
     * Performs basic checks in document name
434
     *
435
     * @param string $document
436
     *
437
     * @return string
438
     * @throws \InvalidArgumentException
439
     */
440
    public function validateDocumentName($document)
441
    {
442
        if (!preg_match('{^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*:[a-zA-Z0-9_\x7f-\xff\\\/]+$}', $document)) {
443
            throw $this->getException(
444
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
445
                [$document]
446
            );
447
        }
448
449
        return $document;
450
    }
451
452
    /**
453
     * Validates field name
454
     *
455
     * @param string $field
456
     *
457
     * @return string
458
     * @throws \InvalidArgumentException
459
     */
460
    public function validateFieldName($field)
461
    {
462
        if (!$field || $field != lcfirst(preg_replace('/[^a-zA-Z]+/', '', $field))) {
463
            throw $this->getException(
464
                'The parameter isn\'t valid ("%s" given, expecting camelcase separated words)',
465
                [$field]
466
            );
467
        }
468
469
        if (in_array(strtolower($field), $this->getReservedKeywords())) {
470
            throw $this->getException('"%s" is a reserved word.', [$field]);
471
        }
472
473
        return $field;
474
    }
475
476
    /**
477
     * Validates property type
478
     *
479
     * @param string $type
480
     *
481
     * @return string
482
     * @throws \InvalidArgumentException
483
     */
484 View Code Duplication
    public function validatePropertyType($type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
485
    {
486
        if (!in_array($type, $this->getPropertyTypes())) {
487
            throw $this->getException(
488
                'The property type isn\'t valid ("%s" given, expecting one of following: %s)',
489
                [$type, implode(', ', $this->getPropertyTypes())]
490
            );
491
        }
492
493
        return $type;
494
    }
495
496
    /**
497
     * Validates document annotation
498
     *
499
     * @param string $annotation
500
     *
501
     * @return string
502
     * @throws \InvalidArgumentException
503
     */
504 View Code Duplication
    public function validateDocumentAnnotation($annotation)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
505
    {
506
        if (!in_array($annotation, $this->getDocumentAnnotations())) {
507
            throw $this->getException(
508
                'The document annotation isn\'t valid ("%s" given, expecting one of following: %s)',
509
                [$annotation, implode(', ', $this->getDocumentAnnotations())]
510
            );
511
        }
512
513
        return $annotation;
514
    }
515
516
    /**
517
     * Validates property annotation
518
     *
519
     * @param string $annotation
520
     *
521
     * @return string
522
     * @throws \InvalidArgumentException
523
     */
524 View Code Duplication
    public function validatePropertyAnnotation($annotation)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
525
    {
526
        if (!in_array($annotation, $this->propertyAnnotations)) {
527
            throw $this->getException(
528
                'The property annotation isn\'t valid ("%s" given, expecting one of following: %s)',
529
                [$annotation, implode(', ', $this->propertyAnnotations)]
530
            );
531
        }
532
533
        return $annotation;
534
    }
535
536
    /**
537
     * Validates property visibility
538
     *
539
     * @param string $visibility
540
     *
541
     * @return string
542
     * @throws \InvalidArgumentException When the visibility is not found in the list of allowed ones.
543
     */
544 View Code Duplication
    public function validatePropertyVisibility($visibility)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
545
    {
546
        if (!in_array($visibility, $this->propertyVisibilities)) {
547
            throw $this->getException(
548
                'The property visibility isn\'t valid ("%s" given, expecting one of following: %s)',
549
                [$visibility, implode(', ', $this->propertyVisibilities)]
550
            );
551
        }
552
553
        return $visibility;
554
    }
555
556
    /**
557
     * Returns formatted question
558
     *
559
     * @param string        $question
560
     * @param mixed         $default
561
     * @param callable|null $validator
562
     * @param array|null    $values
563
     *
564
     * @return Question
565
     */
566
    private function getQuestion($question, $default = null, callable $validator = null, array $values = null)
567
    {
568
        $question = new Question(
569
            sprintf('<info>%s</info>%s: ', $question, $default ? sprintf(' [<comment>%s</comment>]', $default) : ''),
570
            $default
571
        );
572
573
        $question
574
            ->setValidator($validator)
575
            ->setAutocompleterValues($values);
0 ignored issues
show
Bug introduced by
It seems like $values defined by parameter $values on line 566 can also be of type array; however, Symfony\Component\Consol...etAutocompleterValues() does only seem to accept null|object<Symfony\Comp...sole\Question\iterable>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
576
577
        return $question;
578
    }
579
580
    /**
581
     * Returns options label
582
     *
583
     * @param array  $options
584
     * @param string $suffix
585
     *
586
     * @return string[]
587
     */
588
    private function getOptionsLabel(array $options, $suffix)
589
    {
590
        $label = sprintf('<info>%s:</info> ', $suffix);
591
592
        foreach ($options as &$option) {
593
            $option = sprintf('<comment>%s</comment>', $option);
594
        }
595
596
        return ['', $label . implode(', ', $options) . '.'];
597
    }
598
599
    /**
600
     * Returns formatted exception
601
     *
602
     * @param string $format
603
     * @param array  $args
604
     *
605
     * @return \InvalidArgumentException
606
     */
607
    private function getException($format, $args = [])
608
    {
609
        /** @var FormatterHelper $formatter */
610
        $formatter = $this->getHelperSet()->get('formatter');
611
        return new \InvalidArgumentException($formatter->formatBlock(vsprintf($format, $args), 'bg=red', true));
612
    }
613
614
    /**
615
     * Returns available property types
616
     *
617
     * @return array
618
     */
619
    private function getPropertyTypes()
620
    {
621
        $reflection = new \ReflectionClass('ONGR\ElasticsearchBundle\Annotation\Property');
622
623
        return $this
624
            ->getContainer()
625
            ->get('es.annotations.cached_reader')
626
            ->getPropertyAnnotation($reflection->getProperty('type'), 'Doctrine\Common\Annotations\Annotation\Enum')
627
            ->value;
628
    }
629
630
    /**
631
     * Returns document annotations
632
     *
633
     * @return string[]
634
     */
635
    private function getDocumentAnnotations()
636
    {
637
        return ['document', 'nested', 'object'];
638
    }
639
640
    /**
641
     * Returns reserved keywords
642
     *
643
     * @return string[]
644
     */
645
    private function getReservedKeywords()
646
    {
647
        return [
648
            'abstract',
649
            'and',
650
            'array',
651
            'as',
652
            'break',
653
            'callable',
654
            'case',
655
            'catch',
656
            'class',
657
            'clone',
658
            'const',
659
            'continue',
660
            'declare',
661
            'default',
662
            'do',
663
            'else',
664
            'elseif',
665
            'enddeclare',
666
            'endfor',
667
            'endforeach',
668
            'endif',
669
            'endswitch',
670
            'endwhile',
671
            'extends',
672
            'final',
673
            'finally',
674
            'for',
675
            'foreach',
676
            'function',
677
            'global',
678
            'goto',
679
            'if',
680
            'implements',
681
            'interface',
682
            'instanceof',
683
            'insteadof',
684
            'namespace',
685
            'new',
686
            'or',
687
            'private',
688
            'protected',
689
            'public',
690
            'static',
691
            'switch',
692
            'throw',
693
            'trait',
694
            'try',
695
            'use',
696
            'var',
697
            'while',
698
            'xor',
699
            'yield',
700
            'die',
701
            'echo',
702
            'empty',
703
            'exit',
704
            'eval',
705
            'include',
706
            'include_once',
707
            'isset',
708
            'list',
709
            'require',
710
            'require_once',
711
            'return',
712
            'print',
713
            'unset',
714
        ];
715
    }
716
}
717