Completed
Pull Request — master (#601)
by
unknown
02:28
created

validatePropertyAnnotation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 11
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 11
loc 11
rs 9.4285
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
     * {@inheritdoc}
32
     */
33
    protected function configure()
34
    {
35
        parent::configure();
36
37
        $this
38
            ->setName('ongr:es:document:generate')
39
            ->setDescription('Generates a new Elasticsearch document inside a bundle');
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    protected function execute(InputInterface $input, OutputInterface $output)
46
    {
47
        if ($input->hasParameterOption(['--no-interaction', '-n'])) {
48
            throw $this->getException('No interaction mode is not allowed!');
49
        }
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function interact(InputInterface $input, OutputInterface $output)
56
    {
57
        /** @var FormatterHelper $formatter */
58
        $formatter = $this->getHelperSet()->get('formatter');
59
        $this->questionHelper = new QuestionHelper();
60
61
        $output->writeln(
62
            [
63
                '',
64
                $formatter->formatBlock('Welcome to the ONGRElasticsearchBundle document generator', 'bg=blue', true),
65
                '',
66
                'This command helps you generate ONGRElasticsearchBundle documents.',
67
                '',
68
                'First, you need to give the document name you want to generate.',
69
                'You must use the shortcut notation like <comment>AcmeDemoBundle:Post</comment>.',
70
                '',
71
            ]
72
        );
73
74
        /** @var Kernel $kernel */
75
        $kernel = $this->getContainer()->get('kernel');
76
        $bundleNames = array_keys($kernel->getBundles());
77
78
        while (true) {
79
            $document = $this->questionHelper->ask(
80
                $input,
81
                $output,
82
                $this->getQuestion('The Document shortcut name', null, [$this, 'validateDocumentName'], $bundleNames)
83
            );
84
85
            list($bundle, $document) = $this->parseShortcutNotation($document);
86
87
            if (in_array(strtolower($document), $this->getReservedKeywords())) {
88
                $output->writeln($this->getException('"%s" is a reserved word.', [$document])->getMessage());
89
                continue;
90
            }
91
92
            try {
93
                if (!file_exists(
94
                    $kernel->getBundle($bundle)->getPath() . '/Document/' . str_replace('\\', '/', $document) . '.php'
95
                )) {
96
                    break;
97
                }
98
99
                $output->writeln(
100
                    $this->getException('Document "%s:%s" already exists.', [$bundle, $document])->getMessage()
101
                );
102
            } catch (\Exception $e) {
103
                $output->writeln($this->getException('Bundle "%s" does not exist.', [$bundle])->getMessage());
104
            }
105
        }
106
107
        $output->writeln($this->getOptionsLabel($this->getDocumentAnnotations(), 'Available types'));
108
        $annotation = $this->questionHelper->ask(
109
            $input,
110
            $output,
111
            $this->getQuestion(
112
                'Document type',
113
                'Document',
114
                [$this, 'validateDocumentAnnotation'],
115
                $this->getDocumentAnnotations()
116
            )
117
        );
118
119
        $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...
120
        if ($annotation == 'Document') {
121
            $documentType = $this->questionHelper->ask(
122
                $input,
123
                $output,
124
                $this->getQuestion(
125
                    "\n" . 'Elasticsearch Document name',
126
                    lcfirst($document),
127
                    [$this, 'validateFieldName']
128
                )
129
            );
130
        }
131
132
        $properties = [];
133
        $output->writeln(['', $formatter->formatBlock('New Document Property', 'bg=blue;fg=white', true)]);
134
135
        while (true) {
136
            $property = [];
137
            $question = $this->getQuestion(
138
                'Property name [<comment>press <info><return></info> to stop</comment>]',
139
                false
140
            );
141
142
            if (!$field = $this->questionHelper->ask($input, $output, $question)) {
143
                break;
144
            }
145
146
            foreach ($properties as $previousProperty) {
147
                if ($previousProperty['field_name'] == $field) {
148
                    $output->writeln($this->getException('Duplicate field name "%s"', [$field])->getMessage());
149
                    continue(2);
150
                }
151
            }
152
153
            try {
154
                $this->validateFieldName($field);
155
            } catch (\InvalidArgumentException $e) {
156
                $output->writeln($e->getMessage());
157
                continue;
158
            }
159
160
            $output->writeln($this->getOptionsLabel($this->getPropertyAnnotations(), 'Available annotations'));
161
            $property['annotation'] = $this->questionHelper->ask(
162
                $input,
163
                $output,
164
                $this->getQuestion(
165
                    'Property annotation',
166
                    'Property',
167
                    [$this, 'validatePropertyAnnotation'],
168
                    $this->getPropertyAnnotations()
169
                )
170
            );
171
172
            $property['field_name'] = $property['property_name'] = $field;
173
174
            switch ($property['annotation']) {
175
                case 'Embedded':
176
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
177
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
178
179
                    $question = new ConfirmationQuestion("\n<info>Multiple</info> [<comment>no</comment>]: ", false);
180
                    $question->setAutocompleterValues(['yes', 'no']);
181
                    $property['property_multiple'] = $this->questionHelper->ask($input, $output, $question);
182
183
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
184
                    break;
185 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...
186
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
187
                        $output->writeln(
188
                            $this
189
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
190
                                ->getMessage()
191
                        );
192
                        continue(2);
193
                    }
194
                    $property['property_class'] = $this->askForPropertyClass($input, $output);
195
                    break;
196
                case 'Property':
197
                    $property['property_name'] = $this->askForPropertyName($input, $output, $property['field_name']);
198
199
                    $output->writeln($this->getOptionsLabel($this->getPropertyTypes(), 'Available types'));
200
                    $property['property_type'] = $this->questionHelper->ask(
201
                        $input,
202
                        $output,
203
                        $this->getQuestion(
204
                            'Property type',
205
                            'string',
206
                            [$this, 'validatePropertyType'],
207
                            $this->getPropertyTypes()
208
                        )
209
                    );
210
211
                    $property['property_options'] = $this->askForPropertyOptions($input, $output);
212
                    break;
213 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...
214
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
215
                        $output->writeln(
216
                            $this
217
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
218
                                ->getMessage()
219
                        );
220
                        continue(2);
221
                    }
222
                    $property['property_default'] = $this->questionHelper->ask(
223
                        $input,
224
                        $output,
225
                        $this->getQuestion("\n" . 'Default time to live')
226
                    );
227
                    break;
228
                case 'Id':
229
                    if (!$this->isUniqueAnnotation($properties, $property['annotation'])) {
230
                        $output->writeln(
231
                            $this
232
                                ->getException('Only one "%s" field can be added', [$property['annotation']])
233
                                ->getMessage()
234
                        );
235
                        continue(2);
236
                    }
237
                    break;
238
            }
239
240
            $properties[] = $property;
241
            $output->writeln(['', $formatter->formatBlock('New Document Property', 'bg=blue;fg=white', true)]);
242
        }
243
244
        $this->getContainer()->get('es.generate')->generate(
245
            $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...
246
            $document,
247
            $annotation,
248
            $documentType,
249
            $properties
250
        );
251
    }
252
253
    /**
254
     * @param array  $properties
255
     * @param string $annotation
256
     *
257
     * @return string
258
     */
259
    private function isUniqueAnnotation($properties, $annotation)
260
    {
261
        foreach ($properties as $property) {
262
            if ($property['annotation'] == $annotation) {
263
                return false;
264
            }
265
        }
266
267
        return true;
268
    }
269
270
    /**
271
     * Asks for property name
272
     *
273
     * @param InputInterface  $input
274
     * @param OutputInterface $output
275
     * @param string          $default
276
     *
277
     * @return string
278
     */
279 View Code Duplication
    private function askForPropertyName(InputInterface $input, OutputInterface $output, $default = null)
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...
280
    {
281
        return $this->questionHelper->ask(
282
            $input,
283
            $output,
284
            $this->getQuestion("\n" . 'Property name in Elasticsearch', $default, [$this, 'validateFieldName'])
285
        );
286
    }
287
288
    /**
289
     * Asks for property options
290
     *
291
     * @param InputInterface  $input
292
     * @param OutputInterface $output
293
     *
294
     * @return string
295
     */
296 View Code Duplication
    private function askForPropertyOptions(InputInterface $input, OutputInterface $output)
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...
297
    {
298
        return $this->questionHelper->ask(
299
            $input,
300
            $output,
301
            $this->getQuestion(
302
                "\n" . 'Property options [<comment>press <info><return></info> to stop</comment>]',
303
                false,
304
                null,
305
                ['"index"="not_analyzed"', '"analyzer"="standard"']
306
            )
307
        );
308
    }
309
310
    /**
311
     * Asks for property class
312
     *
313
     * @param InputInterface  $input
314
     * @param OutputInterface $output
315
     *
316
     * @return string
317
     */
318 View Code Duplication
    private function askForPropertyClass(InputInterface $input, OutputInterface $output)
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...
319
    {
320
        return $this->questionHelper->ask(
321
            $input,
322
            $output,
323
            $this->getQuestion(
324
                "\n" . 'Property class',
325
                null,
326
                [$this, 'validatePropertyClass'],
327
                $this->getDocumentClasses()
328
            )
329
        );
330
    }
331
332
    /**
333
     * Returns available document classes
334
     *
335
     * @return array
336
     */
337
    private function getDocumentClasses()
338
    {
339
        /** @var MetadataCollector $metadataCollector */
340
        $metadataCollector = $this->getContainer()->get('es.metadata_collector');
341
        $classes = [];
342
343
        foreach ($this->getContainer()->getParameter('es.managers') as $manager) {
344
            $documents = $metadataCollector->getMappings($manager['mappings']);
345
            foreach ($documents as $document) {
346
                $classes[] = sprintf('%s:%s', $document['bundle'], $document['class']);
347
            }
348
        }
349
350
        return $classes;
351
    }
352
353
    /**
354
     * Parses shortcut notation
355
     *
356
     * @param string $shortcut
357
     *
358
     * @return string[]
359
     * @throws \InvalidArgumentException
360
     */
361
    private function parseShortcutNotation($shortcut)
362
    {
363
        $shortcut = str_replace('/', '\\', $shortcut);
364
365
        if (false === $pos = strpos($shortcut, ':')) {
366
            throw $this->getException(
367
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
368
                [$shortcut]
369
            );
370
        }
371
372
        return [substr($shortcut, 0, $pos), substr($shortcut, $pos + 1)];
373
    }
374
375
    /**
376
     * Validates property class
377
     *
378
     * @param string $input
379
     *
380
     * @return string
381
     * @throws \InvalidArgumentException
382
     */
383
    public function validatePropertyClass($input)
384
    {
385
        list($bundle, $document) = $this->parseShortcutNotation($input);
386
387
        try {
388
            if (!file_exists(
389
                $this
390
                    ->getContainer()
391
                    ->get('kernel')
392
                    ->getBundle($bundle)
393
                    ->getPath() . '/Document/' . str_replace('\\', '/', $document) . '.php'
394
            )) {
395
                throw $this->getException('Document "%s:%s" does not exist.', [$bundle, $document]);
396
            }
397
        } catch (\Exception $e) {
398
            throw $this->getException('Bundle "%s" does not exist.', [$bundle]);
399
        }
400
401
        return $input;
402
    }
403
404
    /**
405
     * Performs basic checks in document name
406
     *
407
     * @param string $document
408
     *
409
     * @return string
410
     * @throws \InvalidArgumentException
411
     */
412
    public function validateDocumentName($document)
413
    {
414
        if (!preg_match('{^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*:[a-zA-Z0-9_\x7f-\xff\\\/]+$}', $document)) {
415
            throw $this->getException(
416
                'The document name isn\'t valid ("%s" given, expecting something like AcmeBundle:Post)',
417
                [$document]
418
            );
419
        }
420
421
        return $document;
422
    }
423
424
    /**
425
     * Validates field name
426
     *
427
     * @param string $field
428
     *
429
     * @return string
430
     * @throws \InvalidArgumentException
431
     */
432
    public function validateFieldName($field)
433
    {
434
        if (!$field || $field != lcfirst(preg_replace('/[^a-zA-Z]+/', '', $field))) {
435
            throw $this->getException(
436
                'The parameter isn\'t valid ("%s" given, expecting camelcase separated words)',
437
                [$field]
438
            );
439
        }
440
441
        if (in_array(strtolower($field), $this->getReservedKeywords())) {
442
            throw $this->getException('"%s" is a reserved word.', [$field]);
443
        }
444
445
        return $field;
446
    }
447
448
    /**
449
     * Validates property type
450
     *
451
     * @param string $type
452
     *
453
     * @return string
454
     * @throws \InvalidArgumentException
455
     */
456 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...
457
    {
458
        if (!in_array($type, $this->getPropertyTypes())) {
459
            throw $this->getException(
460
                'The property type isn\'t valid ("%s" given, expecting one of following: %s)',
461
                [$type, implode(', ', $this->getPropertyTypes())]
462
            );
463
        }
464
465
        return $type;
466
    }
467
468
    /**
469
     * Validates document annotation
470
     *
471
     * @param string $annotation
472
     *
473
     * @return string
474
     * @throws \InvalidArgumentException
475
     */
476 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...
477
    {
478
        if (!in_array($annotation, $this->getDocumentAnnotations())) {
479
            throw $this->getException(
480
                'The document annotation isn\'t valid ("%s" given, expecting one of following: %s)',
481
                [$annotation, implode(', ', $this->getDocumentAnnotations())]
482
            );
483
        }
484
485
        return $annotation;
486
    }
487
488
    /**
489
     * Validates property annotation
490
     *
491
     * @param string $annotation
492
     *
493
     * @return string
494
     * @throws \InvalidArgumentException
495
     */
496 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...
497
    {
498
        if (!in_array($annotation, $this->getPropertyAnnotations())) {
499
            throw $this->getException(
500
                'The property annotation isn\'t valid ("%s" given, expecting one of following: %s)',
501
                [$annotation, implode(', ', $this->getPropertyAnnotations())]
502
            );
503
        }
504
505
        return $annotation;
506
    }
507
508
    /**
509
     * Returns formatted question
510
     *
511
     * @param string        $question
512
     * @param mixed         $default
513
     * @param callable|null $validator
514
     * @param array|null    $values
515
     *
516
     * @return Question
517
     */
518
    private function getQuestion($question, $default = null, callable $validator = null, array $values = null)
519
    {
520
        $question = new Question(
521
            sprintf('<info>%s</info>%s: ', $question, $default ? sprintf(' [<comment>%s</comment>]', $default) : ''),
522
            $default
523
        );
524
525
        $question
526
            ->setValidator($validator)
527
            ->setAutocompleterValues($values);
528
529
        return $question;
530
    }
531
532
    /**
533
     * Returns options label
534
     *
535
     * @param array  $options
536
     * @param string $suffix
537
     *
538
     * @return string[]
539
     */
540
    private function getOptionsLabel(array $options, $suffix)
541
    {
542
        $label = sprintf('<info>%s:</info> ', $suffix);
543
544
        foreach ($options as &$option) {
545
            $option = sprintf('<comment>%s</comment>', $option);
546
        }
547
548
        return ['', $label . implode(', ', $options) . '.'];
549
    }
550
551
    /**
552
     * Returns formatted exception
553
     *
554
     * @param string $format
555
     * @param array  $args
556
     *
557
     * @return \InvalidArgumentException
558
     */
559
    private function getException($format, $args = [])
560
    {
561
        /** @var FormatterHelper $formatter */
562
        $formatter = $this->getHelperSet()->get('formatter');
563
        return new \InvalidArgumentException($formatter->formatBlock(vsprintf($format, $args), 'bg=red', true));
564
    }
565
566
    /**
567
     * Returns available property types
568
     *
569
     * @return array
570
     */
571
    private function getPropertyTypes()
572
    {
573
        $reflection = new \ReflectionClass('ONGR\ElasticsearchBundle\Annotation\Property');
574
575
        return $this
576
            ->getContainer()
577
            ->get('annotations.cached_reader')
578
            ->getPropertyAnnotation($reflection->getProperty('type'), 'Doctrine\Common\Annotations\Annotation\Enum')
579
            ->value;
580
    }
581
582
    /**
583
     * Returns property annotations
584
     *
585
     * @return string[]
586
     */
587
    private function getPropertyAnnotations()
588
    {
589
        return ['Embedded', 'Id', 'ParentDocument', 'Property', 'Ttl'];
590
    }
591
592
    /**
593
     * Returns document annotations
594
     *
595
     * @return string[]
596
     */
597
    private function getDocumentAnnotations()
598
    {
599
        return ['Document', 'Nested', 'Object'];
600
    }
601
602
    /**
603
     * Returns reserved keywords
604
     *
605
     * @return string[]
606
     */
607
    private function getReservedKeywords()
608
    {
609
        return [
610
            'abstract',
611
            'and',
612
            'array',
613
            'as',
614
            'break',
615
            'callable',
616
            'case',
617
            'catch',
618
            'class',
619
            'clone',
620
            'const',
621
            'continue',
622
            'declare',
623
            'default',
624
            'do',
625
            'else',
626
            'elseif',
627
            'enddeclare',
628
            'endfor',
629
            'endforeach',
630
            'endif',
631
            'endswitch',
632
            'endwhile',
633
            'extends',
634
            'final',
635
            'finally',
636
            'for',
637
            'foreach',
638
            'function',
639
            'global',
640
            'goto',
641
            'if',
642
            'implements',
643
            'interface',
644
            'instanceof',
645
            'insteadof',
646
            'namespace',
647
            'new',
648
            'or',
649
            'private',
650
            'protected',
651
            'public',
652
            'static',
653
            'switch',
654
            'throw',
655
            'trait',
656
            'try',
657
            'use',
658
            'var',
659
            'while',
660
            'xor',
661
            'yield',
662
            'die',
663
            'echo',
664
            'empty',
665
            'exit',
666
            'eval',
667
            'include',
668
            'include_once',
669
            'isset',
670
            'list',
671
            'require',
672
            'require_once',
673
            'return',
674
            'print',
675
            'unset',
676
        ];
677
    }
678
}
679