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