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