Completed
Push — master ( ae5e03...0447ee )
by Jeroen
10:35 queued 04:37
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('Field "%s" is already defined in the parent class', $name));
447
                    }
448
449
                    // The fields cannot exist already
450
                    if (isset($fields[$name])) {
451
                        throw new \InvalidArgumentException(sprintf('Field "%s" is already defined', $name));
452
                    }
453
454
                    // Check reserved words
455
                    if ($generator->isReservedKeyword($name)) {
456
                        throw new \InvalidArgumentException(sprintf('Name "%s" is a reserved word', $name));
457
                    }
458
459
                    // Only accept a-z
460
                    if (!preg_match('/^[a-zA-Z][a-zA-Z_0-9]+$/', $name) && $name != '') {
461
                        throw new \InvalidArgumentException(sprintf('Name "%s" is invalid', $name));
462
                    }
463
464
                    return $name;
465
                }
466
            );
467
468
            // When <return> is entered
469
            if (!$fieldName) {
470
                break;
471
            }
472
473
            $typeId = $this->assistant->askSelect('Field type', $typeSelect);
474
475
            // If single -or multipe entity reference in chosen, we need to ask for the entity name
476
            if (in_array($typeStrings[$typeId], ['single_ref', 'multi_ref'])) {
477
                $bundleName = $bundle->getName();
478
                $egName = $this->isSymfony4() ? 'App\Entity\FaqItem' : "$bundleName:FaqItem, $bundleName:Blog/Comment";
479
                $question = sprintf('Reference entity name (eg. %s)', $egName);
480
                $name = $this->assistant->askAndValidate(
481
                    $question,
482
                    function ($name) use ($generator, $container) {
483
                        /*
484
                         * Replace slash to backslash. Eg: CmsBundle:Blog/Comment --> CmsBundle:Blog\Comment
485
                         *
486
                         * @see \Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor()
487
                         * @see \Doctrine\ORM\Mapping\ClassMetadataFactory::getFqcnFromAlias()
488
                         */
489
                        if (!$this->isSymfony4()) {
490
                            $name = strtr($name, '/', '\\');
491
492
                            $parts = explode(':', $name);
493
494
                            // Should contain colon
495
                            if (count($parts) != 2) {
496
                                throw new \InvalidArgumentException(sprintf('"%s" is an invalid entity name', $name));
497
                            }
498
                        } else {
499
                            $parts = explode('\\', $name);
500
                        }
501
502
                        // Check reserved words
503
                        if ($generator->isReservedKeyword(end($parts))) {
504
                            throw new \InvalidArgumentException(sprintf('"%s" contains a reserved word', $name));
505
                        }
506
507
                        $em = $container->get('doctrine')->getManager();
508
509
                        try {
510
                            $em->getClassMetadata($name);
511
                        } catch (\Exception $e) {
512
                            throw new \InvalidArgumentException(sprintf('Entity "%s" not found', $name));
513
                        }
514
515
                        return $name;
516
                    },
517
                    null,
518
                    [$bundleName]
519
                );
520
521
                $extra = $name;
522
            } else {
523
                $extra = null;
524
            }
525
526
            // If image type, force image media filter
527
            if ($typeStrings[$typeId] == 'image') {
528
                $extra = 'image';
529
            }
530
531
            // If media type, ask for media filter
532
            if ($typeStrings[$typeId] == 'media') {
533
                $mediaTypeId = $this->assistant->askSelect('Media filter', $mediaTypeSelect);
534
                $extra = strtolower($mediaTypeSelect[$mediaTypeId]);
535
            }
536
537
            if ($typeStrings[$typeId] == 'image' || $typeStrings[$typeId] == 'media') {
538
                // Ask the allowed mimetypes for the media ojbect
539
                $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',
540
                    null
541
                );
542
                if (isset($mimeTypes)) {
543
                    $mimeTypes = explode(',', $mimeTypes);
544
                }
545
                $data = [
546
                    'name' => $fieldName,
547
                    'type' => $typeStrings[$typeId],
548
                    'extra' => $extra,
549
                    'mimeTypes' => $mimeTypes,
550
                    'minHeight' => null,
551
                    'maxHeight' => null,
552
                    'minWidth' => null,
553
                    'maxWidth' => null,
554
                ];
555
556
                if ($extra == 'image') {
557
                    $minHeight = $maxHeight = $minWidth = $maxWidth = null;
558
                    if ($this->assistant->askConfirmation('Do you want to add validation of the dimensions of the media object? (y/n)',
559
                        'n',
560
                        '?',
561
                        false
562
                    )) {
563
                        // Ask the minimum height allowed for the image
564
                        $lengthValidation = function ($length) {
565
                            if ((is_numeric($length) && $length < 0) || (!is_numeric($length) && !empty($length))) {
566
                                throw new \InvalidArgumentException(sprintf('"%s" is not a valid length', $length));
567
                            } else {
568
                                return $length;
569
                            }
570
                        };
571
572
                        $minHeight = $this->assistant->askAndValidate('What is the minimum height for the media object? (in pixels)',
573
                            $lengthValidation
574
                        );
575
576
                        // Ask the maximum height allowed for the image
577
                        $maxHeight = $this->assistant->askAndValidate('What is the maximum height for the media object? (in pixels)',
578
                            $lengthValidation
579
                        );
580
581
                        // Ask the minimum width allowed for the image
582
                        $minWidth = $this->assistant->askAndValidate('What is the minimum width for the media object? (in pixels)',
583
                            $lengthValidation
584
                        );
585
586
                        //Ask the maximum width allowed for the image
587
                        $maxWidth = $this->assistant->askAndValidate('What is the maximum width for the media object? (in pixels)',
588
                            $lengthValidation
589
                        );
590
                    }
591
                    $data = [
592
                        'name' => $fieldName,
593
                        'type' => 'image',
594
                        'extra' => $extra,
595
                        'minHeight' => $minHeight,
596
                        'maxHeight' => $maxHeight,
597
                        'minWidth' => $minWidth,
598
                        'maxWidth' => $maxWidth,
599
                        'mimeTypes' => $mimeTypes,
600
                    ];
601
                }
602
            } else {
603
                $data = [
604
                    'name' => $fieldName,
605
                    'type' => $typeStrings[$typeId],
606
                    'extra' => $extra,
607
                    'minHeight' => null,
608
                    'maxHeight' => null,
609
                    'minWidth' => null,
610
                    'maxWidth' => null,
611
                    'mimeTypes' => null,
612
                ];
613
            }
614
615
            $fields[$fieldName] = $data;
616
        }
617
618
        return $fields;
619
    }
620
621
    /**
622
     * Get all the available types.
623
     *
624
     * @param bool $niceNames
625
     *
626
     * @return array
627
     */
628
    private function getTypes($niceNames = false)
629
    {
630
        $counter = 1;
631
632
        $types = [];
633
        $types[$counter++] = $niceNames ? 'Single line text' : 'single_line';
634
        $types[$counter++] = $niceNames ? 'Multi line text' : 'multi_line';
635
        $types[$counter++] = $niceNames ? 'Wysiwyg' : 'wysiwyg';
636
        $types[$counter++] = $niceNames ? 'Link (url, text, new window)' : 'link';
637
        if ($this->isBundleAvailable('KunstmaanMediaPagePartBundle')) {
638
            $types[$counter++] = $niceNames ? 'Image (media, alt text)' : 'image';
639
            $types[$counter++] = $niceNames ? 'Media (File or Video or Slideshow)' : 'media';
640
        }
641
        $types[$counter++] = $niceNames ? 'Single entity reference' : 'single_ref';
642
        $types[$counter++] = $niceNames ? 'Multi entity reference' : 'multi_ref';
643
        $types[$counter++] = $niceNames ? 'Boolean' : 'boolean';
644
        $types[$counter++] = $niceNames ? 'Integer' : 'integer';
645
        $types[$counter++] = $niceNames ? 'Decimal number' : 'decimal';
646
        $types[$counter++] = $niceNames ? 'DateTime' : 'datetime';
647
648
        return $types;
649
    }
650
651
    /**
652
     * Get all available media types.
653
     *
654
     * @return array
655
     */
656
    private function getMediaTypes()
657
    {
658
        $counter = 1;
659
660
        $types = [];
661
        $types[$counter++] = 'None';
662
        $types[$counter++] = 'File';
663
        $types[$counter++] = 'Image';
664
        $types[$counter++] = 'Video';
665
666
        return $types;
667
    }
668
669
    /**
670
     * Get all the entity fields for a specific type.
671
     *
672
     * @param BundleInterface $bundle
673
     * @param                 $objectName
674
     * @param                 $prefix
675
     * @param                 $name
676
     * @param                 $type
677
     * @param null            $extra
678
     * @param bool            $allNullable
679
     * @param null            $minHeight
680
     * @param null            $maxHeight
681
     * @param null            $minWidth
682
     * @param null            $maxWidth
683
     * @param null            $mimeTypes
684
     *
685
     * @return array
686
     */
687
    protected function getEntityFields(
688
        BundleInterface $bundle,
689
        $objectName,
690
        $prefix,
691
        $name,
692
        $type,
693
        $extra = null,
694
        $allNullable = false,
695
        $minHeight = null,
696
        $maxHeight = null,
697
        $minWidth = null,
698
        $maxWidth = null,
699
        $mimeTypes = null
700
    ) {
701
        $fields = [];
702
        switch ($type) {
703 View Code Duplication
            case 'single_line':
704
                $fields[$type][] = [
705
                    'fieldName' => lcfirst(Container::camelize($name)),
706
                    'type' => 'string',
707
                    'length' => '255',
708
                    'formType' => TextType::class,
709
                    'nullable' => $allNullable,
710
                ];
711
712
                break;
713 View Code Duplication
            case 'multi_line':
714
                $fields[$type][] = [
715
                    'fieldName' => lcfirst(Container::camelize($name)),
716
                    'type' => 'text',
717
                    'formType' => TextareaType::class,
718
                    'nullable' => $allNullable,
719
                ];
720
721
                break;
722 View Code Duplication
            case 'wysiwyg':
723
                $fields[$type][] = [
724
                    'fieldName' => lcfirst(Container::camelize($name)),
725
                    'type' => 'text',
726
                    'formType' => WysiwygType::class,
727
                    'nullable' => $allNullable,
728
                ];
729
730
                break;
731
            case 'link':
732
                foreach (['url', 'text'] as $subField) {
733
                    $fields[$type][$subField] = [
734
                        'fieldName' => lcfirst(Container::camelize($name.'_'.$subField)),
735
                        'type' => 'string',
736
                        'formType' => $subField == 'url' ? URLChooserType::class : TextType::class,
737
                        'nullable' => $allNullable,
738
                    ];
739
                }
740
                $fields[$type]['new_window'] = [
741
                    'fieldName' => lcfirst(Container::camelize($name.'_new_window')),
742
                    'type' => 'boolean',
743
                    'nullable' => true,
744
                    'formType' => CheckboxType::class,
745
                ];
746
747
                break;
748
            case 'image':
749
                $fields[$type]['image'] = [
750
                    'fieldName' => lcfirst(Container::camelize($name)),
751
                    'type' => 'image',
752
                    'formType' => MediaType::class,
753
                    'mediaType' => $extra,
754
                    'minHeight' => $minHeight,
755
                    'maxHeight' => $maxHeight,
756
                    'minWidth' => $minWidth,
757
                    'maxWidth' => $maxWidth,
758
                    'mimeTypes' => $mimeTypes,
759
                    'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media',
760
                    'joinColumn' => [
761
                        'name' => str_replace('.', '_', Container::underscore($name.'_id')),
762
                        'referencedColumnName' => 'id',
763
                    ],
764
                    'nullable' => $allNullable,
765
                ];
766
                $fields[$type]['alt_text'] = [
767
                    'fieldName' => lcfirst(Container::camelize($name.'_alt_text')),
768
                    'type' => 'text',
769
                    'nullable' => true,
770
                    'formType' => TextType::class,
771
                ];
772
773
                break;
774
            case 'media':
775
                $fields[$type][] = [
776
                    'fieldName' => lcfirst(Container::camelize($name)),
777
                    'type' => 'media',
778
                    'formType' => MediaType::class,
779
                    'mediaType' => $extra,
780
                    'mimeTypes' => $mimeTypes,
781
                    'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media',
782
                    'joinColumn' => [
783
                        'name' => str_replace('.', '_', Container::underscore($name.'_id')),
784
                        'referencedColumnName' => 'id',
785
                    ],
786
                    'nullable' => $allNullable,
787
                ];
788
789
                break;
790
            case 'single_ref':
791
                $em = $this->getContainer()->get('doctrine')->getManager();
792
                $entityName = $em->getClassMetadata($extra)->getName();
793
                $fields[$type][] = [
794
                    'fieldName' => lcfirst(Container::camelize($name)),
795
                    'type' => 'entity',
796
                    'formType' => EntityType::class,
797
                    'targetEntity' => $entityName,
798
                    'joinColumn' => [
799
                        'name' => str_replace('.', '_', Container::underscore($name.'_id')),
800
                        'referencedColumnName' => 'id',
801
                    ],
802
                    'nullable' => $allNullable,
803
                ];
804
805
                break;
806
            case 'multi_ref':
807
                $em = $this->getContainer()->get('doctrine')->getManager();
808
                $entityName = $em->getClassMetadata($extra)->getName();
809
                $parts = explode('\\', $entityName);
810
                $joinTableName = strtolower(
811
                    $prefix.Container::underscore($objectName).'_'.Container::underscore(
812
                        $parts[count($parts) - 1]
813
                    )
814
                );
815
                $fields[$type][] = [
816
                    'fieldName' => lcfirst(Container::camelize($name)),
817
                    'type' => 'entity',
818
                    'formType' => EntityType::class,
819
                    'targetEntity' => $entityName,
820
                    'joinTable' => [
821
                        'name' => $joinTableName,
822
                        'joinColumns' => [
823
                            [
824
                                'name' => strtolower(Container::underscore($objectName)).'_id',
825
                                'referencedColumnName' => 'id',
826
                            ],
827
                        ],
828
                        'inverseJoinColumns' => [
829
                            [
830
                                'name' => strtolower(
831
                                        Container::underscore($parts[count($parts) - 1])
832
                                    ).'_id',
833
                                'referencedColumnName' => 'id',
834
                                'unique' => true,
835
                            ],
836
                        ],
837
                    ],
838
                    'nullable' => $allNullable,
839
                ];
840
841
                break;
842 View Code Duplication
            case 'boolean':
843
                $fields[$type][] = [
844
                    'fieldName' => lcfirst(Container::camelize($name)),
845
                    'type' => 'boolean',
846
                    'formType' => CheckboxType::class,
847
                    'nullable' => $allNullable,
848
                ];
849
850
                break;
851 View Code Duplication
            case 'integer':
852
                $fields[$type][] = [
853
                    'fieldName' => lcfirst(Container::camelize($name)),
854
                    'type' => 'integer',
855
                    'formType' => IntegerType::class,
856
                    'nullable' => $allNullable,
857
                ];
858
859
                break;
860 View Code Duplication
            case 'decimal':
861
                $fields[$type][] = [
862
                    'fieldName' => lcfirst(Container::camelize($name)),
863
                    'type' => 'decimal',
864
                    'precision' => 10,
865
                    'scale' => 2,
866
                    'formType' => NumberType::class,
867
                    'nullable' => $allNullable,
868
                ];
869
870
                break;
871 View Code Duplication
            case 'datetime':
872
                $fields[$type][] = [
873
                    'fieldName' => lcfirst(Container::camelize($name)),
874
                    'type' => 'datetime',
875
                    'formType' => DateTimeType::class,
876
                    'nullable' => $allNullable,
877
                ];
878
879
                break;
880
        }
881
882
        return $fields;
883
    }
884
885
    /**
886
     * Get an array with the available page templates.
887
     *
888
     * @param BundleInterface $bundle The bundle for which we want to get the template configurations
889
     *
890
     * @return array
891
     */
892
    protected function getAvailableTemplates(BundleInterface $bundle)
893
    {
894
        $configs = [];
895
        $counter = 1;
896
897
        // Get the available sections from disc
898
        if (Kernel::VERSION_ID >= 40000) {
899
            $dir = $this->getContainer()->getParameter('kernel.project_dir').'/config/kunstmaancms/pagetemplates/';
900
        } else {
901
            $dir = $bundle->getPath().'/Resources/config/pagetemplates/';
902
        }
903
904
        if (file_exists($dir) && is_dir($dir)) {
905
            $finder = new Finder();
906
            $finder->files()->in($dir)->depth('== 0');
907
            foreach ($finder as $file) {
908
                $info = $this->getTemplateInfo($dir, $file->getFileName());
909
                if (is_array($info)) {
910
                    $configs[$counter++] = $info;
911
                }
912
            }
913
        }
914
915
        return $configs;
916
    }
917
918
    /**
919
     * Get the information about a pagepart section configuration file.
920
     *
921
     * @param string $dir
922
     * @param string $file
923
     *
924
     * @return array|null
925
     */
926
    protected function getTemplateInfo($dir, $file)
927
    {
928
        $info = null;
929
930
        try {
931
            $data = Yaml::parse(file_get_contents($dir.$file));
932
933 View Code Duplication
            if (array_key_exists('kunstmaan_page_part', $data)) {
934
                //Get rid of the bundle config lines
935
                $data = array_values(array_values(array_values($data)[0])[0])[0];
936
            }
937
938
            // Parse contexts
939
            $contexts = [];
940
            foreach ($data['rows'] as $row) {
941
                foreach ($row['regions'] as $region) {
942
                    $contexts[] = $region['name'];
943
                }
944
            }
945
            $info = [
946
                'name' => $data['name'],
947
                'contexts' => $contexts,
948
                'file' => $file,
949
            ];
950
        } catch (ParseException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
951
        }
952
953
        return $info;
954
    }
955
956
    /**
957
     * Get an array with the available page templates.
958
     *
959
     * @param BundleInterface $bundle The bundle for which we want to get the template configurations
960
     *
961
     * @return array
962
     */
963
    protected function getAvailablePages(BundleInterface $bundle)
964
    {
965
        $pages = [];
966
        $counter = 1;
967
968
        // Get the available pages from disc
969
        $dir = $bundle->getPath().'/Entity/Pages/';
970
        if (file_exists($dir) && is_dir($dir)) {
971
            $finder = new Finder();
972
            $finder->files()->in($dir)->depth('== 0');
973
            foreach ($finder as $file) {
974
                $pages[$counter++] = [
975
                    'name' => substr($file->getFileName(), 0, strlen($file->getFileName()) - 4),
976
                    'path' => $file->getPathName(),
977
                ];
978
            }
979
        }
980
981
        return $pages;
982
    }
983
984
    /**
985
     * Check that it is possible to generate the behat tests.
986
     *
987
     * @param BundleInterface $bundle
988
     *
989
     * @return bool
990
     */
991
    protected function canGenerateBehatTests(BundleInterface $bundle)
992
    {
993
        $behatFile = dirname($this->getContainer()->getParameter('kernel.root_dir').'/').'/behat.yml';
994
        $pagePartContext = $bundle->getPath().'/Features/Context/PagePartContext.php';
995
        $behatTestPage = $bundle->getPath().'/Entity/Pages/BehatTestPage.php';
996
997
        // Make sure behat is configured and the PagePartContext and BehatTestPage exits
998
        return file_exists($behatFile) && file_exists($pagePartContext) && file_exists($behatTestPage);
999
    }
1000
1001
    /**
1002
     * @internal
1003
     */
1004
    protected function isSymfony4()
1005
    {
1006
        return Kernel::VERSION_ID >= 40000;
1007
    }
1008
}
1009