Completed
Pull Request — master (#90)
by Arnaud
02:00
created

ActionConfiguration::getDefaultTitle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 7
cts 8
cp 0.875
rs 9.2
c 0
b 0
f 0
cc 2
eloc 12
nc 2
nop 0
crap 2.0078
1
<?php
2
3
namespace LAG\AdminBundle\Action\Configuration;
4
5
use Closure;
6
use JK\Configuration\Configuration;
7
use LAG\AdminBundle\Admin\AdminInterface;
8
use LAG\AdminBundle\Admin\Behaviors\TranslationKeyTrait;
9
use LAG\AdminBundle\Admin\Configuration\AdminConfiguration;
10
use LAG\AdminBundle\Filter\Configuration\FilterConfiguration;
11
use LAG\AdminBundle\Form\Type\DeleteType;
12
use LAG\AdminBundle\Form\Type\ListType;
13
use LAG\AdminBundle\LAGAdminBundle;
14
use LAG\AdminBundle\Menu\Configuration\MenuConfiguration;
15
use LAG\AdminBundle\Routing\RouteNameGenerator;
16
use Symfony\Component\DependencyInjection\Container;
17
use Symfony\Component\OptionsResolver\Options;
18
use Symfony\Component\OptionsResolver\OptionsResolver;
19
20
class ActionConfiguration extends Configuration
21
{
22
    use TranslationKeyTrait;
23
    
24
    /**
25
     * Related Action name.
26
     *
27
     * @var string
28
     */
29
    private $actionName;
30
    
31
    /**
32
     * @var AdminConfiguration
33
     */
34
    private $adminConfiguration;
35
    
36
    /**
37
     * @var string
38
     */
39
    private $adminName;
40
    
41 1
    /**
42
     * ActionConfiguration constructor.
43 1
     *
44
     * @param string             $actionName
45 1
     * @param                    $adminName
46 1
     * @param AdminConfiguration $adminConfiguration
47 1
     */
48
    public function __construct($actionName, $adminName, AdminConfiguration $adminConfiguration)
49
    {
50
        parent::__construct();
51
        
52
        $this->actionName = $actionName;
53
        $this->adminConfiguration = $adminConfiguration;
54 1
        $this->adminName = $adminName;
55
    }
56 1
    
57 1
    /**
58
     * Define allowed parameters and values for this configuration, using optionsResolver component.
59 1
     *
60 1
     * @param OptionsResolver $resolver
61 1
     */
62
    public function configureOptions(OptionsResolver $resolver)
63
    {
64
        $this->configureDefaultOptions($resolver);
65
        $this->configureNormalizers($resolver);
66
        
67
        $this->setAllowedTypes($resolver);
68 1
        $this->setAllowedValues($resolver);
69
    }
70
    
71 1
    /**
72
     * Configure the default options for an Action.
73 1
     *
74 1
     * @param OptionsResolver $resolver
75
     */
76
    private function configureDefaultOptions(OptionsResolver $resolver)
77
    {
78
        $resolver
79
            ->setDefaults([
80
                // the default action title is a translation key using the translation pattern and the action name
81
                'title' => $this->getDefaultTitle(),
82
                'service' => $this->getDefaultServiceId(),
83
                'fields' => [
84
                    'id' => [],
85
                ],
86
                // by default, only administrator can access the admin
87
                'permissions' => [
88
                    'ROLE_ADMIN',
89
                ],
90
                // all export are activated
91
                'export' => [
92 1
                    'json',
93
                    'html',
94
                    'csv',
95 1
                    'xls',
96 1
                ],
97 1
                // no order
98
                'order' => [],
99 1
                // route will be generated if empty string or null or false is provided
100
                'route' => '',
101
                // route parameters will be used when using the route (for links...)
102
                'route_parameters' => [],
103 1
                'route_path' => $this->getDefaultRoutePath(),
104 1
                'route_defaults' => $this->getDefaultRouteDefaults(),
105
                'route_requirements' => $this->getDefaultRouteRequirements(),
106
                // icon in the menu
107
                'icon' => '',
108
                // entities loading strategy
109
                'load_strategy' => null,
110
                // pager interface, only null or pagerfanta are allowed
111
                'pager' => 'pagerfanta',
112 1
                'max_per_page' => $this->adminConfiguration->getParameter('max_per_page'),
113 1
                // default criteria used to load entities
114 1
                'criteria' => [],
115
                // filters, should be an array of string (field name => filter options)
116 1
                'filters' => [],
117 1
                'menus' => [],
118
                'batch' => false,
119 1
                // form configuration
120
                'form_handler' => $this->getDefaultFormHandler(),
121
                'form' => $this->getDefaultForm(),
122
                'form_options' => $this->getDefaultFormOptions(),
123
                // twig template
124
                'template' => $this->getDefaultTemplate(),
125
                'sortable' => $this->getDefaultSortable(),
126 1
                // responder
127
                'responder' => $this->getDefaultResponder(),
128
            ]);
129 1
    }
130 1
    
131 1
    /**
132 1
     * Define the allowed values.
133
     *
134
     * @param OptionsResolver $resolver
135 1
     */
136 1
    private function setAllowedValues(OptionsResolver $resolver)
137
    {
138
        $resolver
139
            ->setAllowedValues('load_strategy', [
140 1
                AdminInterface::LOAD_STRATEGY_NONE,
141
                AdminInterface::LOAD_STRATEGY_UNIQUE,
142
                AdminInterface::LOAD_STRATEGY_MULTIPLE,
143
                null,
144
            ])
145
            ->setAllowedValues('pager', [
146
                'pagerfanta',
147 1
                false,
148
            ])
149
        ;
150 1
    }
151 1
    
152 1
    /**
153 1
     * Define the allowed types.
154 1
     *
155 1
     * @param OptionsResolver $resolver
156 1
     */
157 1
    private function setAllowedTypes(OptionsResolver $resolver)
158 1
    {
159 1
        $resolver
160
            ->setAllowedTypes('title', 'string')
161
            ->setAllowedTypes('fields', 'array')
162 1
            ->setAllowedTypes('order', 'array')
163 1
            ->setAllowedTypes('route', 'string')
164 1
            ->setAllowedTypes('route_parameters', 'array')
165 1
            ->setAllowedTypes('icon', 'string')
166 1
            ->setAllowedTypes('criteria', 'array')
167
            ->setAllowedTypes('filters', 'array')
168 1
            ->setAllowedTypes('menus', [
169
                'array',
170
                'boolean',
171
            ])
172
            ->setAllowedTypes('route_path', 'string')
173
            ->setAllowedTypes('route_defaults', 'array')
174
            ->setAllowedTypes('route_requirements', 'array')
175 1
            ->setAllowedTypes('form', 'string')
176
            ->setAllowedTypes('form_options', 'array')
177
        ;
178 1
    }
179 1
    
180 1
    /**
181 1
     * Configure the normalizers.
182 1
     *
183 1
     * @param OptionsResolver $resolver
184 1
     */
185 1
    private function configureNormalizers(OptionsResolver $resolver)
186
    {
187 1
        $resolver
188
            ->setNormalizer('fields', $this->getFieldsNormalizer())
189
            ->setNormalizer('order', $this->getOrderNormalizer())
190
            ->setNormalizer('route', $this->getRouteNormalizer())
191
            ->setNormalizer('load_strategy', $this->getLoadStrategyNormalizer())
192
            ->setNormalizer('criteria', $this->getCriteriaNormalizer())
193
            ->setNormalizer('menus', $this->getMenuNormalizer())
194
            ->setNormalizer('batch', $this->getBatchNormalizer())
195 1
            ->setNormalizer('filters', $this->getFiltersNormalizer())
196
            ->setNormalizer('route_defaults', $this->getRouteDefaultNormalizer())
197
        ;
198 1
    }
199
    
200 1
    /**
201
     * Return the field normalizer. It will transform null configuration into array to allow field type guessing
202 1
     * working.
203
     *
204
     * @return Closure
205
     */
206 1
    private function getFieldsNormalizer()
207
    {
208
        return function(Options $options, $fields) {
209 1
            $normalizedFields = [];
210 1
            
211
            foreach ($fields as $name => $field) {
212
                
213
                if ($field === null) {
214
                    $field = [];
215
                }
216
                
217
                $normalizedFields[$name] = $field;
218 1
            }
219
            
220
            return $normalizedFields;
221 1
        };
222
    }
223
    
224
    /**
225
     * Return the order normalizer. It will check if the order value passed are valid.
226
     *
227
     * @return Closure
228
     */
229
    private function getOrderNormalizer()
230
    {
231
        return function(Options $options, $order) {
232 1
            foreach ($order as $field => $sort) {
233 1
                
234
                if (!is_string($sort) || !is_string($field) || !in_array(strtolower($sort), ['asc', 'desc'])) {
235
                    throw new ConfigurationException(
236
                        'Order value should be an array of string (["field" => $key]), got '.gettype($sort),
237
                        $this->actionName,
238
                        $this->adminName
239
                    );
240
                }
241 1
            }
242
            
243
            return $order;
244 1
        };
245
    }
246
    
247 1
    /**
248 1
     * Return the route normalizer. If an empty value or null or false, it will generate the route using the Admin.
249
     *
250
     * @return Closure
251
     */
252 1
    private function getRouteNormalizer()
253
    {
254
        return function(Options $options, $value) {
255
            $generator = new RouteNameGenerator();
256
            
257
            if (!$value) {
258
                // generate default route from admin
259
                return $generator->generate($this->actionName, $this->adminName, $this->adminConfiguration);
260
            }
261 1
            
262
            return $value;
263
        };
264 1
    }
265 1
    
266
    /**
267 1
     * Return the load strategy normalizer. It will set the default strategy according to the action name, if no value
268 1
     * is provided.
269
     *
270
     * @return Closure
271
     */
272
    private function getLoadStrategyNormalizer()
273
    {
274 1
        return function(Options $options, $value) {
275 1
            if (!$value) {
276
                if ($this->actionName == 'create') {
277
                    $value = AdminInterface::LOAD_STRATEGY_NONE;
278
                } else if ($this->actionName == 'list') {
279
                    $value = AdminInterface::LOAD_STRATEGY_MULTIPLE;
280
                } else {
281
                    $value = AdminInterface::LOAD_STRATEGY_UNIQUE;
282
                }
283
            }
284 1
            
285
            return $value;
286
        };
287
    }
288 1
    
289
    /**
290
     * Return the menu normalizer. It will transform false values into an empty array to allow default menu
291
     * configuration working.
292 1
     *
293 1
     * @return Closure
294
     */
295
    private function getMenuNormalizer()
296
    {
297
        return function(Options $options, $menus) {
298
            // set default to an array
299
            if ($menus === false) {
300
                $menus = [];
301
            }
302 1
            
303
            return $menus;
304
        };
305 1
    }
306
    
307 1
    /**
308
     * Return the criteria normalizer. It will add the id parameters for the edit and delete actions if no value is
309
     * provided.
310
     *
311 1
     * @return Closure
312
     */
313
    private function getCriteriaNormalizer()
314
    {
315
        return function(Options $options, $value) {
316
            if (!$value) {
317
                $idActions = [
318 1
                    'edit',
319 1
                    'delete',
320
                ];
321
                
322
                if (in_array($this->actionName, $idActions)) {
323
                    $value = [
324
                        'id',
325
                    ];
326
                }
327
            }
328 1
            
329
            return $value;
330
        };
331
    }
332 1
    
333 1
    /**
334
     * Return the batch normalizer. If null value is provided, it will add the delete batch action if the delete
335
     * actions is allowed .
336
     *
337
     * @return Closure
338
     */
339
    private function getBatchNormalizer()
340
    {
341
        return function(Options $options, $batch) {
342
            // if batch is not activated, no more checks should be done
343
            if ($batch === false) {
344
                return $batch;
345
            }
346
            // for list actions, we add a default configuration
347
            if ($batch === null) {
348
                // delete action should be allowed in order to be place in batch actions
349
                $actionConfigurations = $this
350
                    ->adminConfiguration
351
                    ->getParameter('actions')
352
                ;
353
                $allowedActions = array_keys($actionConfigurations);
354
                
355
                if ($this->actionName == 'list' && in_array('delete', $allowedActions)) {
356
                    $pattern = $this
357
                        ->adminConfiguration
358
                        ->getParameter('translation_pattern')
359
                    ;
360
                    
361
                    $batch = [
362
                        'items' => [
363
                            'delete' => [
364
                                'admin' => $this->adminName,
365
                                'action' => 'delete',
366
                                'text' => $this->getTranslationKey($pattern, 'delete', $this->adminName),
367
                            ],
368
                        ],
369 1
                    ];
370
                } else {
371
                    return $batch;
372
                }
373
            }
374
            $resolver = new OptionsResolver();
375
            $configuration = new MenuConfiguration();
376
            $configuration->configureOptions($resolver);
377
            $batch = $resolver->resolve($batch);
378
            
379 1
            return $batch;
380 1
        };
381
    }
382
    
383 1
    /**
384
     * Return the filters normalizer.
385 1
     *
386
     * @return Closure
387
     */
388
    private function getFiltersNormalizer()
389
    {
390
        return function(Options $options, $filters) {
391
            if (!is_array($filters)) {
392
                return [];
393
            }
394
            $normalizedData = [];
395
            $resolver = new OptionsResolver();
396
    
397
            foreach ($filters as $filter => $filterOptions) {
398
                // the filter name should be a string
399
                if (!is_string($filter)) {
400
                    throw new ConfigurationException(
401
                        'Invalid filter name "'.$filter.'"',
402
                        $this->actionName
403
                    );
404
                }
405
                // Normalize string notation : if only a string is provided (instead of an array), this string is
406
                // taken as the filter type
407
                if (is_string($filterOptions)) {
408 1
                    $filterOptions = [
409 1
                        'type' => $filterOptions,
410
                    ];
411
                }
412
    
413
                if (null === $filterOptions) {
414
                    $filterOptions = [];
415
                }
416
                $configuration = new FilterConfiguration();
417 1
                $configuration->configureOptions($resolver);
418
                $filterOptions = $resolver->resolve($filterOptions);
419
                $resolver->clear();
420 1
    
421 1
                // set the normalized data
422 1
                $normalizedData[$filter] = $filterOptions;
423
            }
424
            
425 1
            return $normalizedData;
426
        };
427
    }
428
    
429
    private function getRouteDefaultNormalizer()
430
    {
431
        return function (Options $options, $value) {
432
            if (!is_array($value)) {
433
                $value = [];
434
            }
435 1
            $value['_admin'] = $this->adminName;
436
            $value['_action'] = $this->actionName;
437
    
438 1
            return $value;
439
        };
440
    }
441
    
442
    /**
443
     * Return the default title using the configured translation pattern.
444
     *
445
     * @return string
446 1
     */
447
    private function getDefaultTitle()
448
    {
449 1
        $translationPattern = $this
450 1
            ->adminConfiguration
451 1
            ->getParameter('translation_pattern')
452
        ;
453
        
454 1
        if (false !== $translationPattern) {
455 1
            // by default, the action title is action name using the configured translation pattern
456
            
457 1
            $actionTitle = $this->getTranslationKey(
458
                $translationPattern,
459
                $this->actionName,
460
                $this->adminName
461 1
            );
462
        } else {
463
            // no admin was provided, we camelize the action name
464
            $actionTitle = Container::camelize($this->actionName);
465
        }
466
        
467
        return $actionTitle;
468
    }
469 1
    
470
    /**
471
     * Return the default route path according to the action name.
472
     *
473 1
     * @return string
474 1
     */
475 1
    private function getDefaultRoutePath()
476
    {
477
        $pattern = $this
478 1
            ->adminConfiguration
479 1
            ->getParameter('routing_url_pattern')
480 1
        ;
481
        
482
        $path = str_replace('{admin}', $this->adminName, $pattern);
483 1
        $path = str_replace('{action}', $this->actionName, $path);
484 1
        
485 1
        if (in_array($this->actionName, ['edit', 'delete'])) {
486
            $path .= '/{id}';
487
        }
488 1
        
489 1
        return $path;
490 1
    }
491
    
492
    /**
493 1
     * Return the defaults route parameters according to a mapping based on the action name.
494
     *
495 1
     * @return array
496 1
     */
497
    private function getDefaultRouteDefaults()
498
    {
499 1
        $mapping = [
500
            'list' => [
501
                '_controller' => LAGAdminBundle::SERVICE_ID_LIST_ACTION,
502
                '_admin' => $this->adminName,
503
                '_action' => $this->actionName,
504
            ],
505
            'create' => [
506
                '_controller' => LAGAdminBundle::SERVICE_ID_CREATE_ACTION,
507 1
                '_admin' => $this->adminName,
508
                '_action' => $this->actionName,
509
            ],
510 1
            'edit' => [
511
                '_controller' => LAGAdminBundle::SERVICE_ID_EDIT_ACTION,
512
                '_admin' => $this->adminName,
513
                '_action' => $this->actionName,
514
            ],
515
            'delete' => [
516
                '_controller' => LAGAdminBundle::SERVICE_ID_DELETE_ACTION,
517 1
                '_admin' => $this->adminName,
518
                '_action' => $this->actionName,
519 1
            ],
520
        ];
521
        $defaults = [];
522
        
523 1
        if (array_key_exists($this->actionName, $mapping)) {
524
            $defaults = $mapping[$this->actionName];
525
        }
526
        
527
        return $defaults;
528
    }
529
    
530
    /**
531 1
     * Return the default route requirements according to the action name.
532
     *
533 1
     * @return array
534
     */
535 1
    private function getDefaultRouteRequirements()
536
    {
537
        $mapping = [
538
            'edit' => [
539 1
                'id' => '\d+',
540
            ],
541
            'delete' => [
542
                'id' => '\d+',
543
            ],
544
        ];
545
        $requirements = [];
546
        
547 1
        if (array_key_exists($this->actionName, $mapping)) {
548
            $requirements = $mapping[$this->actionName];
549
        }
550 1
        
551
        return $requirements;
552
    }
553
    
554 1
    /**
555
     * Return the default service id according to the action name.
556
     *
557
     * @return string|null
558
     */
559
    private function getDefaultServiceId()
560
    {
561
        $mapping = LAGAdminBundle::getDefaultActionServiceMapping();
562
        
563
        if (!array_key_exists($this->actionName, $mapping)) {
564
            return null;
565
        }
566
        
567
        return $mapping[$this->actionName];
568
    }
569 1
    
570
    /**
571
     * Return the default form according to the action name.
572
     *
573
     * @return string|null
574
     */
575
    private function getDefaultForm()
576
    {
577 1
        $mapping = [
578
            'list' => ListType::class,
579
            'delete' => DeleteType::class,
580 1
        ];
581 1
        
582
        if (!array_key_exists($this->actionName, $mapping)) {
583
            // try to get an admin globally configured form
584 1
            $adminForm = $this
585
                ->adminConfiguration
586
                ->getParameter('form')
587
            ;
588 1
            
589
            if (null !== $adminForm) {
590
                return $adminForm;
591 1
            }
592
            
593
            return null;
594 1
        }
595
        
596
        return $mapping[$this->actionName];
597
    }
598
    
599
    /**
600
     * Return a default form handler service id, or null, according to to the action name.
601 1
     *
602
     * @return mixed|null
603
     */
604
    private function getDefaultFormHandler()
605 1
    {
606
        $mapping = [
607
            'edit' => LAGAdminBundle::SERVICE_ID_EDIT_FORM_HANDLER,
608 1
            'list' => LAGAdminBundle::SERVICE_ID_LIST_FORM_HANDLER,
609
        ];
610
        
611 1
        if (!array_key_exists($this->actionName, $mapping)) {
612
            return null;
613
        }
614
        
615
        return $mapping[$this->actionName];
616
    }
617 1
    
618
    private function getDefaultFormOptions()
619
    {
620
        $mapping = [
621 1
            'list' => [
622
                'actions' => [
623
                    'lag.admin.delete' => 'delete',
624 1
                ]
625
            ],
626 1
        ];
627
    
628
        if (!$this->isActionInMapping($mapping)) {
629 1
            return [];
630
        }
631
    
632 1
        return $mapping[$this->actionName];
633
    }
634
    
635 1
    private function getDefaultTemplate()
636
    {
637
        $mapping = [
638
            'list' => '@LAGAdmin/CRUD/list.html.twig',
639 1
            'edit' => '@LAGAdmin/CRUD/edit.html.twig',
640
            'create' => '@LAGAdmin/CRUD/create.html.twig',
641
            'delete' => '@LAGAdmin/CRUD/delete.html.twig',
642
        ];
643
        
644
        if (!$this->isActionInMapping($mapping)) {
645
            return null;
646
        }
647
        
648
        return $mapping[$this->actionName];
649
    }
650
    
651
    private function isActionInMapping(array $mapping)
652
    {
653
        return array_key_exists($this->actionName, $mapping);
654
    }
655
    
656
    private function getDefaultSortable()
657
    {
658
        $mapping = [
659
            'list' => true,
660
        ];
661
    
662
        if (!$this->isActionInMapping($mapping)) {
663
            return false;
664
        }
665
    
666
        return $mapping[$this->actionName];
667
    }
668
    
669
    private function getDefaultResponder()
670
    {
671
        $mapping = [
672
            'list' => 'lag.admin.action.list_responder',
673
            'create' => 'lag.admin.action.create_responder',
674
            'edit' => 'lag.admin.action.edit_responder',
675
            'delete' => 'lag.admin.action.delete_responder',
676
        ];
677
    
678
        if (!$this->isActionInMapping($mapping)) {
679
            return null;
680
        }
681
    
682
        return $mapping[$this->actionName];
683
    }
684
}
685