Completed
Pull Request — master (#90)
by Arnaud
12:13 queued 03:07
created

ActionConfiguration::getDefaultResponder()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 0
crap 6
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
0 ignored issues
show
Documentation introduced by
$this->adminName is of type string, but the function expects a null|object<LAG\AdminBundle\Admin\AdminInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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
406
                // transform "name" => 'string' into "name" => ['type' => 'string']
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

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