Completed
Push — 5.0 ( a48099...63af02 )
by
unknown
11:33
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.
0 ignored issues
show
Should the return type not be null|string|object|integer|double|array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
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) {
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