Passed
Pull Request — master (#300)
by Arnaud
14:15 queued 08:05
created

ActionConfiguration::configureOptions()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 123
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 87
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 123
rs 8.2836

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace LAG\AdminBundle\Admin\Configuration;
6
7
use Closure;
8
use JK\Configuration\Configuration;
9
use LAG\AdminBundle\Admin\Action;
10
use LAG\AdminBundle\Admin\AdminInterface;
11
use LAG\AdminBundle\Admin\Configuration\Normalizer\LinkNormalizer;
12
use LAG\AdminBundle\Configuration\FilterConfiguration;
13
use LAG\AdminBundle\Controller\AdminAction;
14
use LAG\AdminBundle\Exception\Action\ActionConfigurationException;
15
use LAG\AdminBundle\Exception\Exception;
16
use Symfony\Component\Form\Extension\Core\Type\TextType;
17
use Symfony\Component\OptionsResolver\Options;
18
use Symfony\Component\OptionsResolver\OptionsResolver;
19
use function Symfony\Component\String\u;
20
21
class ActionConfiguration extends Configuration
22
{
23
    protected function configureOptions(OptionsResolver $resolver): void
24
    {
25
        $resolver
26
            // Main info
27
            ->setRequired('name')
28
            ->setAllowedTypes('name', 'string')
29
            ->setRequired('admin_name')
30
            ->setAllowedTypes('admin_name', 'string')
31
            ->setDefault('title', null)
32
            ->addNormalizer('title', $this->getTitleNormalizer())
33
            ->setAllowedTypes('title', ['string', 'null'])
34
            ->setDefault('icon', null)
35
            ->setAllowedTypes('icon', ['string', 'null'])
36
            ->setDefault('action_class', Action::class)
37
            ->setAllowedTypes('action_class', 'string')
38
            ->setDefault('template', null)
39
            ->addNormalizer('template', $this->getTemplateNormalizer())
40
            ->setAllowedTypes('template', ['string', 'null'])
41
42
            // Linked actions
43
            ->setDefault('list_actions', [
44
                'edit' => [],
45
                'delete' => [],
46
            ])
47
            ->setAllowedTypes('list_actions', 'array')
48
            ->setNormalizer('list_actions', function (Options $options, $value) {
49
                foreach ($value as $actionName => $actionConfiguration) {
50
                    $value[$actionName] = LinkNormalizer::normalize(
51
                        $actionConfiguration,
52
                        $options->offsetGet('name'),
53
                        $actionName
54
                    );
55
                }
56
57
                return $value;
58
            })
59
60
            ->setDefault('item_actions', [
61
                'create' => [],
62
            ])
63
            ->setAllowedTypes('item_actions', 'array')
64
            ->setNormalizer('item_actions', function (Options $options, $value) {
65
                foreach ($value as $actionName => $actionConfiguration) {
66
                    $value[$actionName] = LinkNormalizer::normalize(
67
                        $actionConfiguration,
68
                        $options->offsetGet('name'),
69
                        $actionName
70
                    );
71
                }
72
73
                return $value;
74
            })
75
76
            // Routing
77
            ->setDefault('controller', AdminAction::class)
78
            ->setAllowedTypes('controller', 'string')
79
            ->setRequired('route')
80
            ->setAllowedTypes('route', 'string')
81
            ->setDefault('route_parameters', [])
82
            ->setAllowedTypes('route_parameters', 'array')
83
            ->addNormalizer('route_parameters', $this->getRouteParametersNormalizer())
84
            ->setDefault('path', null)
85
            ->setAllowedTypes('path', ['string', 'null'])
86
            ->addNormalizer('path', $this->getPathNormalizer())
87
88
            // Fields
89
            ->setDefault('fields', [])
90
            ->setAllowedTypes('fields', 'array')
91
            ->addNormalizer('fields', $this->getFieldsNormalizer())
92
93
            // Filter and orders
94
            ->setDefault('order', [])
95
            ->setAllowedTypes('order', 'array')
96
            ->addNormalizer('order', $this->getOrderNormalizer())
97
            ->setDefault('criteria', [])
98
            ->setAllowedTypes('criteria', 'array')
99
            ->addNormalizer('criteria', $this->getCriteriaNormalizer())
100
            ->setDefault('filters', [])
101
            ->setAllowedTypes('filters', 'array')
102
            ->addNormalizer('filters', $this->getFiltersNormalizer())
103
104
            // Security
105
            ->setDefault('permissions', ['ROLE_ADMIN'])
106
            ->setAllowedTypes('permissions', 'array')
107
108
            // Export
109
            ->setDefault('export', ['csv', 'xml', 'yaml'])
110
            ->setAllowedTypes('export', 'array')
111
112
            // Data
113
            ->setDefault('load_strategy', null)
114
            ->setAllowedValues('load_strategy', [
115
                null,
116
                AdminInterface::LOAD_STRATEGY_NONE,
117
                AdminInterface::LOAD_STRATEGY_UNIQUE,
118
                AdminInterface::LOAD_STRATEGY_MULTIPLE,
119
            ])
120
            ->addNormalizer('load_strategy', $this->getLoadStrategyNormalizer())
121
            ->setDefault('repository_method', null)
122
            ->setAllowedTypes('repository_method', ['string', 'null'])
123
124
            // Pagination
125
            ->setDefault('pager', 'pagerfanta')
126
            ->setAllowedValues('pager', ['pagerfanta', false])
127
            ->setDefault('max_per_page', 25)
128
            ->setAllowedTypes('max_per_page', 'integer')
129
            ->setDefault('page_parameter', 'page')
130
            ->setAllowedTypes('page_parameter', 'string')
131
132
            ->setDefault('date_format', 'Y-m-d')
133
            ->setAllowedTypes('date_format', 'string')
134
135
            // Form
136
            ->setDefault('form', null)
137
            ->setAllowedTypes('form', ['string', 'null', 'boolean'])
138
            ->setDefault('form_options', [])
139
            ->setAllowedTypes('form_options', 'array')
140
141
            // Redirection after success
142
            ->setDefault('target_route', 'list')
143
            ->setAllowedTypes('target_route', 'string')
144
            ->setDefault('target_route_parameters', [])
145
            ->setAllowedTypes('target_route_parameters', 'array')
146
        ;
147
    }
148
149
    public function getName(): string
150
    {
151
        return $this->getString('name');
152
    }
153
154
    public function getAdminName(): string
155
    {
156
        return $this->getString('admin_name');
157
    }
158
159
    public function getTitle(): string
160
    {
161
        return $this->getString('title');
162
    }
163
164
    public function getIcon(): ?string
165
    {
166
        return $this->get('icon');
167
    }
168
169
    public function getActionClass(): string
170
    {
171
        return $this->getString('action_class');
172
    }
173
174
    public function getTemplate(): string
175
    {
176
        return $this->get('template');
177
    }
178
179
    public function getListActions(): array
180
    {
181
        return $this->get('list_actions');
182
    }
183
184
    public function getItemActions(): array
185
    {
186
        return $this->get('item_actions');
187
    }
188
189
    public function getController(): string
190
    {
191
        return $this->getString('controller');
192
    }
193
194
    public function getRoute(): string
195
    {
196
        return $this->getString('route');
197
    }
198
199
    public function getRouteParameters(): array
200
    {
201
        return $this->get('route_parameters');
202
    }
203
204
    public function getPath(): string
205
    {
206
        return $this->getString('path');
207
    }
208
209
    public function getFields(): array
210
    {
211
        return $this->get('fields');
212
    }
213
214
    public function getOrder(): array
215
    {
216
        return $this->get('order');
217
    }
218
219
    public function getCriteria(): array
220
    {
221
        return $this->get('criteria');
222
    }
223
224
    public function getFilters(): array
225
    {
226
        return $this->get('filters');
227
    }
228
229
    public function getPermissions(): array
230
    {
231
        return $this->get('permissions');
232
    }
233
234
    public function getExport(): array
235
    {
236
        return $this->get('export');
237
    }
238
239
    public function getLoadStrategy(): string
240
    {
241
        return $this->getString('load_strategy');
242
    }
243
244
    public function isPaginationEnabled(): bool
245
    {
246
        $pager = $this->get('pager');
247
248
        if ($pager === false) {
249
            return false;
250
        }
251
252
        return true;
253
    }
254
255
    public function getPager(): string
256
    {
257
        if (!$this->isPaginationEnabled()) {
258
            throw new Exception('The pagination is not enabled');
259
        }
260
261
        return $this->getString('pager');
262
    }
263
264
    public function getMaxPerPage(): int
265
    {
266
        if (!$this->isPaginationEnabled()) {
267
            throw new Exception('The pagination is not enabled');
268
        }
269
270
        return $this->getInt('max_per_page');
271
    }
272
273
    public function getPageParameter(): string
274
    {
275
        return $this->getString('page_parameter');
276
    }
277
278
    public function getDateFormat(): string
279
    {
280
        return $this->getString('date_format');
281
    }
282
283
    public function getForm(): ?string
284
    {
285
        return $this->get('form');
286
    }
287
288
    public function getFormOptions(): array
289
    {
290
        return $this->get('form_options');
291
    }
292
293
    public function getRepositoryMethod(): ?string
294
    {
295
        return $this->get('repository_method');
296
    }
297
298
    public function getTargetRoute(): string
299
    {
300
        return $this->getString('target_route');
301
    }
302
303
    public function getTargetRouteParameters(): array
304
    {
305
        return $this->get('target_route_parameters');
306
    }
307
308
    private function getTitleNormalizer(): Closure
309
    {
310
        return function (Options $options, $value) {
311
            if ($value === null) {
312
                $value = u($options->offsetGet('name'))->camel()->title()->toString();
313
            }
314
315
            return $value;
316
        };
317
    }
318
319
    private function getTemplateNormalizer(): Closure
320
    {
321
        return function (Options $options, $value) {
322
            $map = [
323
                'create' => '@LAGAdmin/crud/create.html.twig',
324
                'edit' => '@LAGAdmin/crud/edit.html.twig',
325
                'list' => '@LAGAdmin/crud/list.html.twig',
326
                'delete' => '@LAGAdmin/crud/delete.html.twig',
327
                'batch' => '@LAGAdmin/crud/batch.html.twig',
328
            ];
329
330
            if (array_key_exists($options->offsetGet('name'), $map) && $value === null) {
331
                return $map[$options->offsetGet('name')];
332
            }
333
334
            throw new ActionConfigurationException(
335
                'The template should be defined if the action is not named create, edit, list, delete or batch'
336
            );
337
        };
338
    }
339
340
    private function getPathNormalizer(): Closure
341
    {
342
        return function (Options $options, $value) {
343
            if ($value !== null) {
344
                $path = u($value);
345
346
                if ($path->endsWith('/')) {
347
                    $path = $path->slice(0, -1);
348
                }
349
350
                return $path->toString();
351
            }
352
            $loadStrategy = $options->offsetGet('load_strategy');
353
            $path = u($options->offsetGet('admin_name'))
354
                ->snake()
355
                ->replace('_', '-')
356
            ;
357
358
            if (!$path->endsWith('s')) {
359
                $path = $path->append('s');
360
361
                if ($path->endsWith('ys')) {
362
                    $path = $path->before('ys')->append('ies');
363
                }
364
            }
365
            $snakeActionName = u($options->offsetGet('name'))
366
                ->snake()
367
                ->replace('_', '-')
368
                ->toString()
369
            ;
370
371
            // Edit the the default action. It is not append to the path (ex: articles/{id} for edit,
372
            // articles/{id}/delete for delete)
373
            if ($loadStrategy === AdminInterface::LOAD_STRATEGY_UNIQUE) {
374
                $path = $path->append('/{id}');
375
376
                if ($options->offsetGet('name') !== 'edit') {
377
                    $path = $path
378
                        ->append('/')
379
                        ->append($snakeActionName)
380
                    ;
381
                }
382
            }
383
384
            if ($loadStrategy === AdminInterface::LOAD_STRATEGY_NONE) {
385
                $path = $path
386
                    ->append('/')
387
                    ->append($snakeActionName)
388
                ;
389
            }
390
391
            return $path->toString();
392
        };
393
    }
394
395
    /**
396
     * Return the field normalizer. It will transform null configuration into array to allow field type guessing
397
     * working.
398
     */
399
    private function getFieldsNormalizer(): Closure
400
    {
401
        return function (Options $options, $fields) {
402
            $normalizedFields = [];
403
404
            foreach ($fields as $name => $field) {
405
                if ($field === null) {
406
                    $field = [];
407
                }
408
409
                $normalizedFields[$name] = $field;
410
            }
411
412
            return $normalizedFields;
413
        };
414
    }
415
416
    /**
417
     * Return the order normalizer. It will check if the order value passed are valid.
418
     */
419
    private function getOrderNormalizer(): Closure
420
    {
421
        return function (Options $options, $order) {
422
            foreach ($order as $field => $sort) {
423
                if (!\is_string($sort) || !\is_string($field) || !\in_array(strtolower($sort), ['asc', 'desc'])) {
424
                    throw new Exception('Order value should be an array of string (["field" => $key]), got '.\gettype($sort));
425
                }
426
            }
427
428
            return $order;
429
        };
430
    }
431
432
    private function getLoadStrategyNormalizer(): Closure
433
    {
434
        return function (Options $options, $value) {
435
            if ($value !== null) {
436
                return $value;
437
            }
438
439
            if ($options->offsetGet('name') == 'create') {
440
                $value = AdminInterface::LOAD_STRATEGY_NONE;
441
            } elseif ($options->offsetGet('name') == 'list') {
442
                $value = AdminInterface::LOAD_STRATEGY_MULTIPLE;
443
            } else {
444
                $value = AdminInterface::LOAD_STRATEGY_UNIQUE;
445
            }
446
447
            return $value;
448
        };
449
    }
450
451
    /**
452
     * Return the criteria normalizer. It will add the id parameters for the edit and delete actions if no value is
453
     * provided.
454
     */
455
    private function getCriteriaNormalizer(): Closure
456
    {
457
        return function (Options $options, $value) {
458
            if (!$value) {
459
                $idActions = [
460
                    'edit',
461
                    'delete',
462
                ];
463
464
                if (\in_array($options->offsetGet('name'), $idActions)) {
465
                    $value = [
466
                        'id',
467
                    ];
468
                }
469
            }
470
471
            return $value;
472
        };
473
    }
474
475
    /**
476
     * Return the filters normalizer.
477
     */
478
    private function getFiltersNormalizer(): Closure
479
    {
480
        return function (Options $options, $data) {
481
            $normalizedData = [];
482
483
            foreach ($data as $name => $field) {
484
                if (\is_string($field)) {
485
                    $field = [
486
                        'name' => $field,
487
                        'type' => TextType::class,
488
                        'options' => [],
489
                    ];
490
                } else {
491
                    $field['name'] = $name;
492
                }
493
494
                $filterConfiguration = new FilterConfiguration();
495
                $filterConfiguration->configure($field);
496
497
                $normalizedData[$field['name']] = $filterConfiguration->toArray();
498
            }
499
500
            return $normalizedData;
501
        };
502
    }
503
504
    private function getRouteParametersNormalizer(): Closure
505
    {
506
        return function (Options $options, $value) {
507
            if (\count($value) > 0) {
508
                return $value;
509
            }
510
511
            if ($options->offsetGet('name') === 'edit' || $options->offsetGet('name') === 'delete') {
512
                return ['id' => null];
513
            }
514
515
            return [];
516
        };
517
    }
518
519
    private function getLinkedActionsNormalizer(): Closure
0 ignored issues
show
Unused Code introduced by
The method getLinkedActionsNormalizer() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
520
    {
521
        return function (Options $options, $value) {
522
            $actions = array_keys($options->offsetGet('actions'));
523
524
            foreach ($value as $actionName) {
525
                if (!in_array($actionName, $actions)) {
526
                    throw new Exception(sprintf(
527
                        'The action "%s" does not exists in the admin "%s"',
528
                        $actionName,
529
                        $options->offsetGet('name'),
530
                    ));
531
                }
532
            }
533
534
            return $value;
535
        };
536
    }
537
}
538