Completed
Pull Request — 5.6 (#2830)
by Jeroen
14:14
created

Command/KunstmaanGenerateCommand.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\GeneratorBundle\Command;
4
5
use Kunstmaan\AdminBundle\Form\WysiwygType;
6
use Kunstmaan\GeneratorBundle\Helper\CommandAssistant;
7
use Kunstmaan\GeneratorBundle\Helper\GeneratorUtils;
8
use Kunstmaan\GeneratorBundle\Helper\Sf4AppBundle;
9
use Kunstmaan\MediaBundle\Form\Type\MediaType;
10
use Kunstmaan\NodeBundle\Form\Type\URLChooserType;
11
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCommand;
12
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
13
use Symfony\Component\Console\Input\InputInterface;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use Symfony\Component\DependencyInjection\Container;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
18
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
19
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
20
use Symfony\Component\Form\Extension\Core\Type\NumberType;
21
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
22
use Symfony\Component\Form\Extension\Core\Type\TextType;
23
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
24
use Symfony\Component\HttpKernel\Kernel;
25
use Symfony\Component\Yaml\Exception\ParseException;
26
use Symfony\Component\Yaml\Yaml;
27
28
abstract class KunstmaanGenerateCommand extends GenerateDoctrineCommand
29
{
30
    /**
31
     * @var CommandAssistant
32
     */
33
    protected $assistant;
34
35
    /**
36
     * Interacts with the user.
37
     *
38
     * @param InputInterface  $input  An InputInterface instance
39
     * @param OutputInterface $output An OutputInterface instance
40
     */
41
    protected function interact(InputInterface $input, OutputInterface $output)
42
    {
43
        $this->setInputAndOutput($input, $output);
44
45
        $welcomeText = $this->getWelcomeText();
46
        if (!empty($welcomeText)) {
47
            $this->assistant->writeSection($this->getWelcomeText());
48
        }
49
50
        $this->doInteract();
51
    }
52
53
    /**
54
     * @return int|null
55
     */
56
    protected function execute(InputInterface $input, OutputInterface $output)
57
    {
58
        $this->setInputAndOutput($input, $output);
59
60
        return $this->doExecute();
61
    }
62
63
    /**
64
     * Create the CommandAssistant.
65
     */
66 View Code Duplication
    private function setInputAndOutput(InputInterface $input, OutputInterface $output)
67
    {
68
        if (is_null($this->assistant)) {
69
            $this->assistant = new CommandAssistant();
70
            $this->assistant->setQuestionHelper($this->getQuestionHelper());
71
            $this->assistant->setKernel($this->getApplication()->getKernel());
72
        }
73
        $this->assistant->setOutput($output);
74
        $this->assistant->setInput($input);
75
    }
76
77
    /**
78
     * Do the interaction with the end user.
79
     */
80
    abstract protected function doInteract();
81
82
    /**
83
     * This function implements the final execution of the Generator.
84
     * It calls the execute function with the correct parameters.
85
     */
86
    abstract protected function doExecute();
87
88
    /**
89
     * The text to be displayed on top of the generator.
90
     *
91
     * @return string|array
92
     */
93
    abstract protected function getWelcomeText();
94
95
    /**
96
     * Get an array with all the bundles the user has created.
97
     *
98
     * @return array
99
     */
100
    protected function getOwnBundles()
101
    {
102
        $bundles = [];
103
        $counter = 1;
104
        $dir = dirname($this->getContainer()->getParameter('kernel.root_dir') . '/') . '/src/';
105
        $finder = new Finder();
106
        $finder->in($dir)->name('*Bundle.php');
107
108
        foreach ($finder as $file) {
109
            $bundles[$counter++] = [
110
                'name' => basename($file->getFilename(), '.php'),
111
                'namespace' => $file->getRelativePath(),
112
                'dir' => $file->getPath(),
113
            ];
114
        }
115
116
        return $bundles;
117
    }
118
119
    /**
120
     * Check that a bundle is available (loaded in AppKernel)
121
     *
122
     * @param string $bundleName
123
     *
124
     * @return bool
125
     */
126
    protected function isBundleAvailable($bundleName)
127
    {
128
        $allBundles = array_keys($this->assistant->getKernel()->getBundles());
129
130
        return in_array($bundleName, $allBundles);
131
    }
132
133
    /**
134
     * Asks for the prefix and sets it on the InputInterface as the 'prefix' option, if this option is not set yet.
135
     * Will set the default to a snake_cased namespace when the namespace has been set on the InputInterface.
136
     *
137
     * @param array  $text      What you want printed before the prefix is asked. If null is provided it'll write a default text.
138
     * @param string $namespace An optional namespace. If this is set it'll create the default based on this prefix.
139
     *                          If it's not provided it'll check if the InputInterface already has the namespace option.
140
     *
141
     * @return string The prefix. But it's also been set on the InputInterface.
142
     */
143
    protected function askForPrefix(array $text = null, $namespace = null)
144
    {
145
        $prefix = $this->assistant->getOptionOrDefault('prefix', null);
146
147
        if (is_null($text)) {
148
            $text = [
149
                'You can add a prefix to the table names of the generated entities for example: ' .
150
                '<comment>projectname_bundlename_</comment>',
151
                'Enter an underscore \'_\' if you don\'t want a prefix.',
152
                '',
153
            ];
154
        }
155
156
        while (is_null($prefix)) {
157
            if (count($text) > 0) {
158
                $this->assistant->writeLine($text);
159
            }
160
161
            if (is_null($namespace) || empty($namespace)) {
162
                $namespace = $this->assistant->getOption('namespace');
163
            } else {
164
                $namespace = $this->fixNamespace($namespace);
165
            }
166
            $defaultPrefix = GeneratorUtils::cleanPrefix($this->convertNamespaceToSnakeCase($namespace));
167
            $prefix = GeneratorUtils::cleanPrefix($this->assistant->ask('Tablename prefix', $defaultPrefix));
168
169
            if ($prefix == '') {
170
                break;
171
            }
172
173
            $output = $this->assistant->getOutput();
174 View Code Duplication
            if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $prefix)) {
175
                $output->writeln(sprintf('<bg=red> "%s" contains invalid characters</>', $prefix));
176
                $prefix = $text = null;
177
178
                continue;
179
            }
180
181
            $this->assistant->setOption('prefix', $prefix);
182
        }
183
184
        return $prefix;
185
    }
186
187
    /**
188
     * Converts something like Namespace\BundleNameBundle to namespace_bundlenamebundle.
189
     *
190
     * @param string $namespace
191
     *
192
     * @return string
193
     */
194 View Code Duplication
    private function convertNamespaceToSnakeCase($namespace)
195
    {
196
        if (is_null($namespace)) {
197
            return null;
198
        }
199
200
        return str_replace('/', '_', strtolower($this->fixNamespace($namespace)));
201
    }
202
203
    /**
204
     * Replaces '\' with '/'.
205
     *
206
     * @param $namespace
207
     *
208
     * @return mixed
209
     */
210
    private function fixNamespace($namespace)
211
    {
212
        return str_replace('\\', '/', $namespace);
213
    }
214
215
    /**
216
     * Ask for which bundle we need to generate something. It there is only one custom bundle
217
     * created by the user, we don't ask anything and just use that bundle. If the user provided
218
     * a namespace as input option, we try to get that bundle first.
219
     *
220
     * @param string      $objectName          The thing we are going to create (pagepart, bundle, layout, ...)
221
     * @param string|null $namespace           The namespace provided as input option
222
     * @param string      $questionMoreBundles
223
     * @param string      $questionOneBundle
224
     *
225
     * @return BundleInterface
226
     */
227
    protected function askForBundleName(
228
        $objectName,
229
        $namespace = null,
230
        $questionMoreBundles = "\nIn which bundle do you want to create the %s",
231
        $questionOneBundle = "The %s will be created for the <comment>%s</comment> bundle.\n"
232
    ) {
233
        if (Kernel::VERSION_ID >= 40000) {
234
            return new Sf4AppBundle($this->getContainer()->getParameter('kernel.project_dir'));
235
        }
236
237
        $ownBundles = $this->getOwnBundles();
238
        if (count($ownBundles) <= 0) {
239
            $this->assistant->writeError("Looks like you don't have created any bundles for your project...", true);
240
        }
241
242
        // If the user provided the namespace as input option
243
        if (!is_null($namespace)) {
244
            foreach ($ownBundles as $key => $bundleInfo) {
245
                if (GeneratorUtils::fixNamespace($namespace) == GeneratorUtils::fixNamespace(
246
                        $bundleInfo['namespace']
247
                    )
248
                ) {
249
                    $bundleName = $bundleInfo['name'];
250
251
                    break;
252
                }
253
            }
254
255
            // When the provided namespace was not found, we show an error on the screen and ask the bundle again
256
            if (empty($bundleName)) {
257
                $this->assistant->writeError("The provided bundle namespace '$namespace' was not found...");
258
            }
259
        }
260
261
        if (empty($bundleName)) {
262
            // If we only have 1 bundle, we don't need to ask
263
            if (count($ownBundles) > 1) {
264
                $bundleSelect = [];
265
                foreach ($ownBundles as $key => $bundleInfo) {
266
                    $bundleSelect[$key] = $bundleInfo['name'];
267
                }
268
                $bundleId = $this->assistant->askSelect(
269
                    sprintf($questionMoreBundles, $objectName),
270
                    $bundleSelect
271
                );
272
                $bundleName = $ownBundles[$bundleId]['name'];
273
274
                $this->assistant->writeLine('');
275
            } else {
276
                $bundleName = $ownBundles[1]['name'];
277
                $this->assistant->writeLine(
278
                    [sprintf($questionOneBundle, $objectName, $bundleName)]
279
                );
280
            }
281
        }
282
283
        $bundle = $this->assistant->getKernel()->getBundle($bundleName);
284
285
        return $bundle;
286
    }
287
288
    /**
289
     * Ask the end user to select one (or more) section configuration(s).
290
     *
291
     * @param string      $question
292
     * @param bool        $multiple
293
     * @param string|null $context
294
     * @param array       $defaultSections
295
     *
296
     * @return array|null
297
     */
298
    protected function askForSections(
299
        $question,
300
        BundleInterface $bundle,
301
        $multiple = false,
302
        $context = null,
303
        $defaultSections = []
304
    ) {
305
        $allSections = $this->getAvailableSections($bundle, $context, $defaultSections);
306
        $sections = [];
307
308
        // If there are more options to choose from, we ask the end user
309
        if (count($allSections) > 0) {
310
            $sectionSelect = [];
311
            foreach ($allSections as $key => $sectionInfo) {
312
                $sectionSelect[$key] = $sectionInfo['name'] . ' (' . $sectionInfo['file'] . ')';
313
            }
314
            $this->assistant->writeLine('');
315
            $sectionIds = $this->assistant->askSelect($question, $sectionSelect, null, $multiple);
316
            if (is_array($sectionIds)) {
317
                foreach ($sectionIds as $id) {
318
                    $sections[] = $allSections[$id]['file'];
319
                }
320
            } else {
321
                $sections[] = $allSections[$sectionIds]['file'];
322
            }
323
        }
324
325
        if ($multiple) {
326
            return $sections;
327
        } else {
328
            return count($sections) > 0 ? $sections[0] : null;
329
        }
330
    }
331
332
    /**
333
     * Get an array with the available page sections. We also parse the yaml files to get more information about
334
     * the sections.
335
     *
336
     * @param BundleInterface $bundle          The bundle for which we want to get the section configuration
337
     * @param string|null     $context         If provided, only return configurations with this context
338
     * @param array           $defaultSections The default section configurations that are always available
339
     *
340
     * @return array
341
     */
342
    protected function getAvailableSections(BundleInterface $bundle, $context = null, $defaultSections = [])
343
    {
344
        $configs = [];
345
        $counter = 1;
346
347
        // Get the available sections from disc
348
        $dir = Kernel::VERSION_ID >= 40000 ?
349
            $this->getContainer()->getParameter('kernel.project_dir') . '/config/kunstmaancms/pageparts/' :
350
            $bundle->getPath() . '/Resources/config/pageparts/'
351
        ;
352
        if (file_exists($dir) && is_dir($dir)) {
353
            $finder = new Finder();
354
            $finder->files()->in($dir)->depth('== 0');
355
            foreach ($finder as $file) {
356
                $info = $this->getSectionInfo($dir, $file->getFileName());
357
358
                if (is_array($info) && (is_null($context) || $info['context'] == $context)) {
359
                    $configs[$counter++] = $info;
360
                    if (array_key_exists($info['file'], $defaultSections)) {
361
                        unset($defaultSections[$info['file']]);
362
                    }
363
                }
364
            }
365
        }
366
367
        // Add the default sections
368
        foreach ($defaultSections as $file => $info) {
369
            if (is_null($context) || $info['context'] == $context) {
370
                $configs[$counter++] = $info;
371
            }
372
        }
373
374
        return $configs;
375
    }
376
377
    /**
378
     * Get the information about a pagepart section configuration file.
379
     *
380
     * @param string $dir
381
     * @param string $file
382
     *
383
     * @return array|null
384
     */
385
    private function getSectionInfo($dir, $file)
386
    {
387
        $info = null;
388
389
        try {
390
            $data = Yaml::parse(file_get_contents($dir . $file));
391
392 View Code Duplication
            if (array_key_exists('kunstmaan_page_part', $data)) {
393
                //Get rid of the bundle config lines
394
                $data = array_values(array_values(array_values($data)[0])[0])[0];
395
            }
396
397
            $info = [
398
                'name' => $data['name'],
399
                'context' => $data['context'],
400
                'file' => $file,
401
                //'file_clean' => substr($file, 0, strlen($file)-4)
402
            ];
403
        } catch (ParseException $e) {
404
        }
405
406
        return $info;
407
    }
408
409
    /**
410
     * Get an array of fields that need to be added to the entity.
411
     *
412
     * @return array
413
     */
414
    protected function askEntityFields(BundleInterface $bundle, array $reservedFields = ['id'])
415
    {
416
        $this->assistant->writeLine('<info>Available field types:</info> ');
417
        $typeSelect = $this->getTypes(true);
418
        foreach ($typeSelect as $type) {
419
            $this->assistant->writeLine(sprintf('<comment>- %s</comment>', $type));
420
        }
421
422
        $fields = [];
423
        $typeStrings = $this->getTypes();
424
        $mediaTypeSelect = $this->getMediaTypes();
425
        $generator = $this->getGenerator();
426
        $container = $this->getContainer();
427
428
        while (true) {
429
            $this->assistant->writeLine('');
430
431
            $fieldName = $this->assistant->askAndValidate(
432
                'New field name (press <return> to stop adding fields)',
433
                function ($name) use ($fields, $reservedFields, $generator) {
434
                    // The fields cannot exist in the reserved field list
435
                    if (in_array($name, $reservedFields)) {
436
                        throw new \InvalidArgumentException(sprintf('Field "%s" is already defined in the parent class', $name));
437
                    }
438
439
                    // The fields cannot exist already
440
                    if (isset($fields[$name])) {
441
                        throw new \InvalidArgumentException(sprintf('Field "%s" is already defined', $name));
442
                    }
443
444
                    // Check reserved words
445
                    if ($generator->isReservedKeyword($name)) {
446
                        throw new \InvalidArgumentException(sprintf('Name "%s" is a reserved word', $name));
447
                    }
448
449
                    // Only accept a-z
450
                    if (!preg_match('/^[a-zA-Z][a-zA-Z_0-9]+$/', $name) && $name != '') {
451
                        throw new \InvalidArgumentException(sprintf('Name "%s" is invalid', $name));
452
                    }
453
454
                    return $name;
455
                }
456
            );
457
458
            // When <return> is entered
459
            if (!$fieldName) {
460
                break;
461
            }
462
463
            $typeId = $this->assistant->askSelect('Field type', $typeSelect);
464
465
            // If single -or multipe entity reference in chosen, we need to ask for the entity name
466
            if (in_array($typeStrings[$typeId], ['single_ref', 'multi_ref'])) {
467
                $bundleName = $bundle->getName();
468
                $egName = $this->isSymfony4() ? 'App\Entity\FaqItem' : "$bundleName:FaqItem, $bundleName:Blog/Comment";
469
                $question = sprintf('Reference entity name (eg. %s)', $egName);
470
                $name = $this->assistant->askAndValidate(
471
                    $question,
472
                    function ($name) use ($generator, $container) {
473
                        /*
474
                         * Replace slash to backslash. Eg: CmsBundle:Blog/Comment --> CmsBundle:Blog\Comment
475
                         *
476
                         * @see \Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor()
477
                         * @see \Doctrine\ORM\Mapping\ClassMetadataFactory::getFqcnFromAlias()
478
                         */
479
                        if (!$this->isSymfony4()) {
480
                            $name = strtr($name, '/', '\\');
481
482
                            $parts = explode(':', $name);
483
484
                            // Should contain colon
485
                            if (count($parts) != 2) {
486
                                throw new \InvalidArgumentException(sprintf('"%s" is an invalid entity name', $name));
487
                            }
488
                        } else {
489
                            $parts = explode('\\', $name);
490
                        }
491
492
                        // Check reserved words
493
                        if ($generator->isReservedKeyword(end($parts))) {
494
                            throw new \InvalidArgumentException(sprintf('"%s" contains a reserved word', $name));
495
                        }
496
497
                        $em = $container->get('doctrine')->getManager();
498
499
                        try {
500
                            $em->getClassMetadata($name);
501
                        } catch (\Exception $e) {
502
                            throw new \InvalidArgumentException(sprintf('Entity "%s" not found', $name));
503
                        }
504
505
                        return $name;
506
                    },
507
                    null,
508
                    [$bundleName]
509
                );
510
511
                $extra = $name;
512
            } else {
513
                $extra = null;
514
            }
515
516
            // If image type, force image media filter
517
            if ($typeStrings[$typeId] == 'image') {
518
                $extra = 'image';
519
            }
520
521
            // If media type, ask for media filter
522
            if ($typeStrings[$typeId] == 'media') {
523
                $mediaTypeId = $this->assistant->askSelect('Media filter', $mediaTypeSelect);
524
                $extra = strtolower($mediaTypeSelect[$mediaTypeId]);
525
            }
526
527
            if ($typeStrings[$typeId] == 'image' || $typeStrings[$typeId] == 'media') {
528
                // Ask the allowed mimetypes for the media ojbect
529
                $mimeTypes = $this->assistant->ask('Do you want to limit the possible file types? Then specify a comma-seperated list of types (example: image/png,image/svg+xml), otherwise press ENTER',
530
                    null
531
                );
532
                if (isset($mimeTypes)) {
533
                    $mimeTypes = explode(',', $mimeTypes);
534
                }
535
                $data = [
536
                    'name' => $fieldName,
537
                    'type' => $typeStrings[$typeId],
538
                    'extra' => $extra,
539
                    'mimeTypes' => $mimeTypes,
540
                    'minHeight' => null,
541
                    'maxHeight' => null,
542
                    'minWidth' => null,
543
                    'maxWidth' => null,
544
                ];
545
546
                if ($extra == 'image') {
547
                    $minHeight = $maxHeight = $minWidth = $maxWidth = null;
548
                    if ($this->assistant->askConfirmation('Do you want to add validation of the dimensions of the media object? (y/n)',
549
                        'n',
550
                        '?',
551
                        false
552
                    )) {
553
                        // Ask the minimum height allowed for the image
554
                        $lengthValidation = function ($length) {
555
                            if ((is_numeric($length) && $length < 0) || (!is_numeric($length) && !empty($length))) {
556
                                throw new \InvalidArgumentException(sprintf('"%s" is not a valid length', $length));
557
                            } else {
558
                                return $length;
559
                            }
560
                        };
561
562
                        $minHeight = $this->assistant->askAndValidate('What is the minimum height for the media object? (in pixels)',
563
                            $lengthValidation
564
                        );
565
566
                        // Ask the maximum height allowed for the image
567
                        $maxHeight = $this->assistant->askAndValidate('What is the maximum height for the media object? (in pixels)',
568
                            $lengthValidation
569
                        );
570
571
                        // Ask the minimum width allowed for the image
572
                        $minWidth = $this->assistant->askAndValidate('What is the minimum width for the media object? (in pixels)',
573
                            $lengthValidation
574
                        );
575
576
                        //Ask the maximum width allowed for the image
577
                        $maxWidth = $this->assistant->askAndValidate('What is the maximum width for the media object? (in pixels)',
578
                            $lengthValidation
579
                        );
580
                    }
581
                    $data = [
582
                        'name' => $fieldName,
583
                        'type' => 'image',
584
                        'extra' => $extra,
585
                        'minHeight' => $minHeight,
586
                        'maxHeight' => $maxHeight,
587
                        'minWidth' => $minWidth,
588
                        'maxWidth' => $maxWidth,
589
                        'mimeTypes' => $mimeTypes,
590
                    ];
591
                }
592
            } else {
593
                $data = [
594
                    'name' => $fieldName,
595
                    'type' => $typeStrings[$typeId],
596
                    'extra' => $extra,
597
                    'minHeight' => null,
598
                    'maxHeight' => null,
599
                    'minWidth' => null,
600
                    'maxWidth' => null,
601
                    'mimeTypes' => null,
602
                ];
603
            }
604
605
            $fields[$fieldName] = $data;
606
        }
607
608
        return $fields;
609
    }
610
611
    /**
612
     * Get all the available types.
613
     *
614
     * @param bool $niceNames
615
     *
616
     * @return array
617
     */
618
    private function getTypes($niceNames = false)
619
    {
620
        $counter = 1;
621
622
        $types = [];
623
        $types[$counter++] = $niceNames ? 'Single line text' : 'single_line';
624
        $types[$counter++] = $niceNames ? 'Multi line text' : 'multi_line';
625
        $types[$counter++] = $niceNames ? 'Wysiwyg' : 'wysiwyg';
626
        $types[$counter++] = $niceNames ? 'Link (url, text, new window)' : 'link';
627
        if ($this->isBundleAvailable('KunstmaanMediaPagePartBundle')) {
628
            $types[$counter++] = $niceNames ? 'Image (media, alt text)' : 'image';
629
            $types[$counter++] = $niceNames ? 'Media (File or Video or Slideshow)' : 'media';
630
        }
631
        $types[$counter++] = $niceNames ? 'Single entity reference' : 'single_ref';
632
        $types[$counter++] = $niceNames ? 'Multi entity reference' : 'multi_ref';
633
        $types[$counter++] = $niceNames ? 'Boolean' : 'boolean';
634
        $types[$counter++] = $niceNames ? 'Integer' : 'integer';
635
        $types[$counter++] = $niceNames ? 'Decimal number' : 'decimal';
636
        $types[$counter++] = $niceNames ? 'DateTime' : 'datetime';
637
638
        return $types;
639
    }
640
641
    /**
642
     * Get all available media types.
643
     *
644
     * @return array
645
     */
646
    private function getMediaTypes()
647
    {
648
        $counter = 1;
649
650
        $types = [];
651
        $types[$counter++] = 'None';
652
        $types[$counter++] = 'File';
653
        $types[$counter++] = 'Image';
654
        $types[$counter++] = 'Video';
655
656
        return $types;
657
    }
658
659
    /**
660
     * Get all the entity fields for a specific type.
661
     *
662
     * @param      $objectName
663
     * @param      $prefix
664
     * @param      $name
665
     * @param      $type
666
     * @param null $extra
667
     * @param bool $allNullable
668
     * @param null $minHeight
669
     * @param null $maxHeight
670
     * @param null $minWidth
671
     * @param null $maxWidth
672
     * @param null $mimeTypes
673
     *
674
     * @return array
675
     */
676
    protected function getEntityFields(
677
        BundleInterface $bundle,
678
        $objectName,
679
        $prefix,
680
        $name,
681
        $type,
682
        $extra = null,
683
        $allNullable = false,
684
        $minHeight = null,
685
        $maxHeight = null,
686
        $minWidth = null,
687
        $maxWidth = null,
688
        $mimeTypes = null
689
    ) {
690
        $fields = [];
691
        switch ($type) {
692 View Code Duplication
            case 'single_line':
693
                $fields[$type][] = [
694
                    'fieldName' => lcfirst(Container::camelize($name)),
695
                    'type' => 'string',
696
                    'length' => '255',
697
                    'formType' => TextType::class,
698
                    'nullable' => $allNullable,
699
                ];
700
701
                break;
702 View Code Duplication
            case 'multi_line':
703
                $fields[$type][] = [
704
                    'fieldName' => lcfirst(Container::camelize($name)),
705
                    'type' => 'text',
706
                    'formType' => TextareaType::class,
707
                    'nullable' => $allNullable,
708
                ];
709
710
                break;
711 View Code Duplication
            case 'wysiwyg':
712
                $fields[$type][] = [
713
                    'fieldName' => lcfirst(Container::camelize($name)),
714
                    'type' => 'text',
715
                    'formType' => WysiwygType::class,
716
                    'nullable' => $allNullable,
717
                ];
718
719
                break;
720
            case 'link':
721
                foreach (['url', 'text'] as $subField) {
722
                    $fields[$type][$subField] = [
723
                        'fieldName' => lcfirst(Container::camelize($name . '_' . $subField)),
724
                        'type' => 'string',
725
                        'formType' => $subField == 'url' ? URLChooserType::class : TextType::class,
726
                        'nullable' => $allNullable,
727
                    ];
728
                }
729
                $fields[$type]['new_window'] = [
730
                    'fieldName' => lcfirst(Container::camelize($name . '_new_window')),
731
                    'type' => 'boolean',
732
                    'nullable' => true,
733
                    'formType' => CheckboxType::class,
734
                ];
735
736
                break;
737
            case 'image':
738
                $fields[$type]['image'] = [
739
                    'fieldName' => lcfirst(Container::camelize($name)),
740
                    'type' => 'image',
741
                    'formType' => MediaType::class,
742
                    'mediaType' => $extra,
743
                    'minHeight' => $minHeight,
744
                    'maxHeight' => $maxHeight,
745
                    'minWidth' => $minWidth,
746
                    'maxWidth' => $maxWidth,
747
                    'mimeTypes' => $mimeTypes,
748
                    'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media',
749
                    'joinColumn' => [
750
                        'name' => str_replace('.', '_', Container::underscore($name . '_id')),
751
                        'referencedColumnName' => 'id',
752
                    ],
753
                    'nullable' => $allNullable,
754
                ];
755
                $fields[$type]['alt_text'] = [
756
                    'fieldName' => lcfirst(Container::camelize($name . '_alt_text')),
757
                    'type' => 'text',
758
                    'nullable' => true,
759
                    'formType' => TextType::class,
760
                ];
761
762
                break;
763
            case 'media':
764
                $fields[$type][] = [
765
                    'fieldName' => lcfirst(Container::camelize($name)),
766
                    'type' => 'media',
767
                    'formType' => MediaType::class,
768
                    'mediaType' => $extra,
769
                    'mimeTypes' => $mimeTypes,
770
                    'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media',
771
                    'joinColumn' => [
772
                        'name' => str_replace('.', '_', Container::underscore($name . '_id')),
773
                        'referencedColumnName' => 'id',
774
                    ],
775
                    'nullable' => $allNullable,
776
                ];
777
778
                break;
779
            case 'single_ref':
780
                $em = $this->getContainer()->get('doctrine')->getManager();
781
                $entityName = $em->getClassMetadata($extra)->getName();
782
                $fields[$type][] = [
783
                    'fieldName' => lcfirst(Container::camelize($name)),
784
                    'type' => 'entity',
785
                    'formType' => EntityType::class,
786
                    'targetEntity' => $entityName,
787
                    'joinColumn' => [
788
                        'name' => str_replace('.', '_', Container::underscore($name . '_id')),
789
                        'referencedColumnName' => 'id',
790
                    ],
791
                    'nullable' => $allNullable,
792
                ];
793
794
                break;
795
            case 'multi_ref':
796
                $em = $this->getContainer()->get('doctrine')->getManager();
797
                $entityName = $em->getClassMetadata($extra)->getName();
798
                $parts = explode('\\', $entityName);
799
                $joinTableName = strtolower(
800
                    $prefix . Container::underscore($objectName) . '_' . Container::underscore(
801
                        $parts[count($parts) - 1]
802
                    )
803
                );
804
                $fields[$type][] = [
805
                    'fieldName' => lcfirst(Container::camelize($name)),
806
                    'type' => 'entity',
807
                    'formType' => EntityType::class,
808
                    'targetEntity' => $entityName,
809
                    'joinTable' => [
810
                        'name' => $joinTableName,
811
                        'joinColumns' => [
812
                            [
813
                                'name' => strtolower(Container::underscore($objectName)) . '_id',
814
                                'referencedColumnName' => 'id',
815
                            ],
816
                        ],
817
                        'inverseJoinColumns' => [
818
                            [
819
                                'name' => strtolower(
820
                                        Container::underscore($parts[count($parts) - 1])
821
                                    ) . '_id',
822
                                'referencedColumnName' => 'id',
823
                                'unique' => true,
824
                            ],
825
                        ],
826
                    ],
827
                    'nullable' => $allNullable,
828
                ];
829
830
                break;
831 View Code Duplication
            case 'boolean':
832
                $fields[$type][] = [
833
                    'fieldName' => lcfirst(Container::camelize($name)),
834
                    'type' => 'boolean',
835
                    'formType' => CheckboxType::class,
836
                    'nullable' => $allNullable,
837
                ];
838
839
                break;
840 View Code Duplication
            case 'integer':
841
                $fields[$type][] = [
842
                    'fieldName' => lcfirst(Container::camelize($name)),
843
                    'type' => 'integer',
844
                    'formType' => IntegerType::class,
845
                    'nullable' => $allNullable,
846
                ];
847
848
                break;
849 View Code Duplication
            case 'decimal':
850
                $fields[$type][] = [
851
                    'fieldName' => lcfirst(Container::camelize($name)),
852
                    'type' => 'decimal',
853
                    'precision' => 10,
854
                    'scale' => 2,
855
                    'formType' => NumberType::class,
856
                    'nullable' => $allNullable,
857
                ];
858
859
                break;
860 View Code Duplication
            case 'datetime':
861
                $fields[$type][] = [
862
                    'fieldName' => lcfirst(Container::camelize($name)),
863
                    'type' => 'datetime',
864
                    'formType' => DateTimeType::class,
865
                    'nullable' => $allNullable,
866
                ];
867
868
                break;
869
        }
870
871
        return $fields;
872
    }
873
874
    /**
875
     * Get an array with the available page templates.
876
     *
877
     * @param BundleInterface $bundle The bundle for which we want to get the template configurations
878
     *
879
     * @return array
880
     */
881
    protected function getAvailableTemplates(BundleInterface $bundle)
882
    {
883
        $configs = [];
884
        $counter = 1;
885
886
        // Get the available sections from disc
887
        if (Kernel::VERSION_ID >= 40000) {
888
            $dir = $this->getContainer()->getParameter('kernel.project_dir') . '/config/kunstmaancms/pagetemplates/';
889
        } else {
890
            $dir = $bundle->getPath() . '/Resources/config/pagetemplates/';
891
        }
892
893
        if (file_exists($dir) && is_dir($dir)) {
894
            $finder = new Finder();
895
            $finder->files()->in($dir)->depth('== 0');
896
            foreach ($finder as $file) {
897
                $info = $this->getTemplateInfo($dir, $file->getFileName());
898
                if (is_array($info)) {
899
                    $configs[$counter++] = $info;
900
                }
901
            }
902
        }
903
904
        return $configs;
905
    }
906
907
    /**
908
     * Get the information about a pagepart section configuration file.
909
     *
910
     * @param string $dir
911
     * @param string $file
912
     *
913
     * @return array|null
914
     */
915
    protected function getTemplateInfo($dir, $file)
916
    {
917
        $info = null;
918
919
        try {
920
            $data = Yaml::parse(file_get_contents($dir . $file));
921
922 View Code Duplication
            if (array_key_exists('kunstmaan_page_part', $data)) {
923
                //Get rid of the bundle config lines
924
                $data = array_values(array_values(array_values($data)[0])[0])[0];
925
            }
926
927
            // Parse contexts
928
            $contexts = [];
929
            foreach ($data['rows'] as $row) {
930
                foreach ($row['regions'] as $region) {
931
                    $contexts[] = $region['name'];
932
                }
933
            }
934
            $info = [
935
                'name' => $data['name'],
936
                'contexts' => $contexts,
937
                'file' => $file,
938
            ];
939
        } catch (ParseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
940
        }
941
942
        return $info;
943
    }
944
945
    /**
946
     * Get an array with the available page templates.
947
     *
948
     * @param BundleInterface $bundle The bundle for which we want to get the template configurations
949
     *
950
     * @return array
951
     */
952
    protected function getAvailablePages(BundleInterface $bundle)
953
    {
954
        $pages = [];
955
        $counter = 1;
956
957
        // Get the available pages from disc
958
        $dir = $bundle->getPath() . '/Entity/Pages/';
959
        if (file_exists($dir) && is_dir($dir)) {
960
            $finder = new Finder();
961
            $finder->files()->in($dir)->depth('== 0');
962
            foreach ($finder as $file) {
963
                $pages[$counter++] = [
964
                    'name' => substr($file->getFileName(), 0, strlen($file->getFileName()) - 4),
965
                    'path' => $file->getPathName(),
966
                ];
967
            }
968
        }
969
970
        return $pages;
971
    }
972
973
    /**
974
     * Check that it is possible to generate the behat tests.
975
     *
976
     * @return bool
977
     */
978
    protected function canGenerateBehatTests(BundleInterface $bundle)
979
    {
980
        $behatFile = dirname($this->getContainer()->getParameter('kernel.root_dir') . '/') . '/behat.yml';
981
        $pagePartContext = $bundle->getPath() . '/Features/Context/PagePartContext.php';
982
        $behatTestPage = $bundle->getPath() . '/Entity/Pages/BehatTestPage.php';
983
984
        // Make sure behat is configured and the PagePartContext and BehatTestPage exits
985
        return file_exists($behatFile) && file_exists($pagePartContext) && file_exists($behatTestPage);
986
    }
987
988
    /**
989
     * @internal
990
     */
991
    protected function isSymfony4()
992
    {
993
        return Kernel::VERSION_ID >= 40000;
994
    }
995
}
996