Passed
Pull Request — master (#150)
by Arnaud
07:48
created

ActionConfiguration::configureOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 60
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 1
eloc 51
c 3
b 1
f 0
nc 1
nop 1
dl 0
loc 60
rs 9.069

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
namespace LAG\AdminBundle\Configuration;
4
5
use Closure;
6
use JK\Configuration\Configuration;
7
use LAG\AdminBundle\Admin\Action;
8
use LAG\AdminBundle\Controller\AdminAction;
9
use LAG\AdminBundle\Exception\Exception;
10
use LAG\AdminBundle\Form\Type\DeleteType;
11
use LAG\AdminBundle\LAGAdminBundle;
12
use LAG\AdminBundle\Routing\RoutingLoader;
13
use LAG\AdminBundle\Utils\TranslationUtils;
14
use LAG\Component\StringUtils\StringUtils;
15
use Symfony\Component\OptionsResolver\Options;
16
use Symfony\Component\OptionsResolver\OptionsResolver;
17
18
class ActionConfiguration extends Configuration
19
{
20
    /**
21
     * Related Action name.
22
     *
23
     * @var string
24
     */
25
    protected $actionName;
26
27
    /**
28
     * @var AdminConfiguration
29
     */
30
    protected $adminConfiguration;
31
32
    /**
33
     * @var string
34
     */
35
    protected $adminName;
36
37
    /**
38
     * ActionConfiguration constructor.
39
     */
40
    public function __construct(string $actionName, string $adminName, AdminConfiguration $adminConfiguration)
41
    {
42
        parent::__construct();
43
44
        $this->actionName = $actionName;
45
        $this->adminConfiguration = $adminConfiguration;
46
        $this->adminName = $adminName;
47
    }
48
49
    /**
50
     * Define allowed parameters and values for this configuration, using optionsResolver component.
51
     */
52
    public function configureOptions(OptionsResolver $resolver)
53
    {
54
        $resolver
55
            ->setDefaults([
56
                'title' => null,
57
                'class' => Action::class,
58
                'fields' => [],
59
                'permissions' => [
60
                    'ROLE_ADMIN',
61
                ],
62
                'export' => [],
63
                'order' => [],
64
                'icon' => null,
65
                'load_strategy' => LAGAdminBundle::LOAD_STRATEGY_NONE,
66
                'pager' => $this->adminConfiguration->get('pager'),
67
                'page_parameter' => $this->adminConfiguration->get('page_parameter'),
68
                'max_per_page' => 30,
69
                'criteria' => [],
70
                'filters' => [],
71
                'template' => $this->getDefaultTemplate(),
72
                'sortable' => false,
73
                'string_length' => $this->adminConfiguration->get('string_length'),
74
                'string_length_truncate' => $this->adminConfiguration->get('string_length_truncate'),
75
                'date_format' => $this->adminConfiguration->get('date_format'),
76
                'use_form' => true,
77
                'form' => null,
78
            ])
79
            ->setAllowedTypes('title', [
80
                'string',
81
                'null',
82
            ])
83
            ->setAllowedTypes('class', 'string')
84
            ->setAllowedTypes('fields', 'array')
85
            ->setAllowedTypes('permissions', 'array')
86
            ->setAllowedTypes('export', 'array')
87
            ->setAllowedTypes('order', 'array')
88
            ->setAllowedTypes('string_length', 'integer')
89
            ->setAllowedTypes('string_length_truncate', 'string')
90
            ->setNormalizer('fields', $this->getFieldsNormalizer())
91
            ->setNormalizer('order', $this->getOrderNormalizer())
92
            ->setNormalizer('load_strategy', $this->getLoadStrategyNormalizer())
93
            ->setNormalizer('criteria', $this->getCriteriaNormalizer())
94
            ->setNormalizer('filters', $this->getFiltersNormalizer())
95
            ->setNormalizer('form', $this->getFormNormalizer())
96
            ->setNormalizer('title', $this->getTitleNormalizer())
97
            ->setAllowedValues('load_strategy', [
98
                LAGAdminBundle::LOAD_STRATEGY_NONE,
99
                LAGAdminBundle::LOAD_STRATEGY_UNIQUE,
100
                LAGAdminBundle::LOAD_STRATEGY_MULTIPLE,
101
            ])
102
            ->setAllowedValues('pager', [
103
                'pagerfanta',
104
                false,
105
                null,
106
            ])
107
        ;
108
109
        $this->configureMenu($resolver);
110
        $this->configureRepository($resolver);
111
        $this->configureRouting($resolver);
112
    }
113
114
    /**
115
     * Generate an admin route name using the pattern in the configuration.
116
     *
117
     * @throws Exception
118
     */
119
    protected function generateRouteName(): string
120
    {
121
        if (!array_key_exists($this->actionName, $this->adminConfiguration->get('actions'))) {
122
            throw new Exception(sprintf('Invalid action name %s for admin %s (available action are: %s)', $this->actionName, $this->adminName, implode(', ', array_keys($this->adminConfiguration->get('actions')))));
123
        }
124
125
        return RoutingLoader::generateRouteName(
126
            $this->adminName,
127
            $this->actionName,
128
            $this->adminConfiguration->get('routing_name_pattern')
129
        );
130
    }
131
132
    /**
133
     * Return the field normalizer. It will transform null configuration into array to allow field type guessing
134
     * working.
135
     *
136
     * @return Closure
137
     */
138
    protected function getFieldsNormalizer()
139
    {
140
        return function (Options $options, $fields) {
141
            $normalizedFields = [];
142
143
            foreach ($fields as $name => $field) {
144
                if (null === $field) {
145
                    $field = [];
146
                }
147
148
                $normalizedFields[$name] = $field;
149
            }
150
151
            return $normalizedFields;
152
        };
153
    }
154
155
    /**
156
     * Return the order normalizer. It will check if the order value passed are valid.
157
     *
158
     * @return Closure
159
     */
160
    protected function getOrderNormalizer()
161
    {
162
        return function (Options $options, $order) {
163
            foreach ($order as $field => $sort) {
164
                if (!is_string($sort) || !is_string($field) || !in_array(strtolower($sort), ['asc', 'desc'])) {
165
                    throw new Exception('Order value should be an array of string (["field" => $key]), got '.gettype($sort));
166
                }
167
            }
168
169
            return $order;
170
        };
171
    }
172
173
    /**
174
     * Return the load strategy normalizer. It will set the default strategy according to the action name, if no value
175
     * is provided.
176
     *
177
     * @return Closure
178
     */
179
    protected function getLoadStrategyNormalizer()
180
    {
181
        return function (Options $options, $value) {
182
            if (!$value) {
183
                if ('create' == $this->actionName) {
184
                    $value = LAGAdminBundle::LOAD_STRATEGY_NONE;
185
                } elseif ('list' == $this->actionName) {
186
                    $value = LAGAdminBundle::LOAD_STRATEGY_MULTIPLE;
187
                } else {
188
                    $value = LAGAdminBundle::LOAD_STRATEGY_UNIQUE;
189
                }
190
            }
191
192
            return $value;
193
        };
194
    }
195
196
    /**
197
     * Return the criteria normalizer. It will add the id parameters for the edit and delete actions if no value is
198
     * provided.
199
     *
200
     * @return Closure
201
     */
202
    protected function getCriteriaNormalizer()
203
    {
204
        return function (Options $options, $value) {
205
            if (!$value) {
206
                $idActions = [
207
                    'edit',
208
                    'delete',
209
                ];
210
211
                if (in_array($this->actionName, $idActions)) {
212
                    $value = [
213
                        'id',
214
                    ];
215
                }
216
            }
217
218
            return $value;
219
        };
220
    }
221
222
    public function getAdminName(): string
223
    {
224
        return $this->adminName;
225
    }
226
227
    public function getActionName(): string
228
    {
229
        return $this->actionName;
230
    }
231
232
    public function getAdminConfiguration(): AdminConfiguration
233
    {
234
        return $this->adminConfiguration;
235
    }
236
237
    /**
238
     * Return the filters normalizer.
239
     */
240
    protected function getFiltersNormalizer(): Closure
241
    {
242
        return function (Options $options, $data) {
243
            $normalizedData = [];
244
245
            foreach ($data as $name => $field) {
246
                if (is_string($field)) {
247
                    $field = [
248
                        'type' => $field,
249
                        'options' => [],
250
                    ];
251
                }
252
                $field['name'] = $name;
253
254
                $resolver = new OptionsResolver();
255
                $filterConfiguration = new FilterConfiguration();
256
                $filterConfiguration->configureOptions($resolver);
257
                $filterConfiguration->setParameters($resolver->resolve($field));
258
259
                $normalizedData[$name] = $filterConfiguration->getParameters();
260
            }
261
262
            return $normalizedData;
263
        };
264
    }
265
266
    protected function getFormNormalizer(): Closure
267
    {
268
        return function (Options $options, $value) {
269
            if (null !== $value) {
270
                return $value;
271
            }
272
            $mapping = [
273
                'create' => $this->adminConfiguration->get('form'),
274
                'edit' => $this->adminConfiguration->get('form'),
275
                'delete' => DeleteType::class,
276
            ];
277
278
            if (key_exists($this->actionName, $mapping)) {
279
                $value = $mapping[$this->actionName];
280
            }
281
282
            return $value;
283
        };
284
    }
285
286
    protected function getTitleNormalizer(): Closure
287
    {
288
        return function (Options $options, $value) {
289
            // If the translation system is not used, return the provided value as is
290
            if (!$this->adminConfiguration->isTranslationEnabled()) {
291
                if (null === $value) {
292
                    return StringUtils::camelize($this->actionName);
293
                }
294
295
                return $value;
296
            }
297
298
            // If a value is defined, we should return the value
299
            if (null !== $value) {
300
                return $value;
301
            }
302
            // By default, the action title is action name using the configured translation pattern
303
            $value = TranslationUtils::getTranslationKey(
304
                $this->adminConfiguration->getTranslationPattern(),
305
                $this->adminName,
306
                $this->actionName
307
            );
308
309
            return $value;
310
        };
311
    }
312
313
    /**
314
     * Return the default route path according to the action name.
315
     */
316
    protected function getDefaultRoutePath(): string
317
    {
318
        $pattern = $this
319
            ->adminConfiguration
320
            ->get('routing_url_pattern')
321
        ;
322
        $path = str_replace('{admin}', $this->adminName, $pattern);
323
        $path = str_replace('{action}', $this->actionName, $path);
324
325
        if (in_array($this->actionName, ['edit', 'delete'])) {
326
            $path .= '/{id}';
327
        }
328
329
        return $path;
330
    }
331
332
    protected function getDefaultTemplate(): ?string
333
    {
334
        $mapping = [
335
            'list' => $this->adminConfiguration->get('list_template'),
336
            'edit' => $this->adminConfiguration->get('edit_template'),
337
            'create' => $this->adminConfiguration->get('create_template'),
338
            'delete' => $this->adminConfiguration->get('delete_template'),
339
        ];
340
341
        if (!$this->isActionInMapping($mapping)) {
342
            return null;
343
        }
344
345
        return $mapping[$this->actionName];
346
    }
347
348
    protected function isActionInMapping(array $mapping): bool
349
    {
350
        return array_key_exists($this->actionName, $mapping);
351
    }
352
353
    protected function configureMenu(OptionsResolver $resolver): void
354
    {
355
        $resolver
356
            ->setDefaults([
357
                'add_return' => true,
358
                'menus' => [],
359
            ])
360
            ->setAllowedTypes('add_return', 'boolean')
361
            ->setNormalizer('menus', function (Options $options, $value) {
362
                if (false === $value) {
363
                    return $value;
364
                }
365
366
                if (!is_array($value)) {
367
                    $value = [];
368
                }
369
370
                if (!key_exists('top', $value)) {
371
                    $value['top'] = [];
372
                }
373
374
                if (!key_exists('items', $value['top'])) {
375
                    $value['top']['items'] = [];
376
                }
377
378
                // Auto return button should be optional
379
                if ($options->offsetGet('add_return')) {
380
                    $text = ucfirst('Return');
381
382
                    if ($this->adminConfiguration->isTranslationEnabled()) {
383
                        $text = TranslationUtils::getTranslationKey(
384
                            $this->adminConfiguration->getTranslationPattern(),
385
                            $this->adminName,
386
                            'return'
387
                        );
388
                    }
389
390
                    // Use array_unshift() to put the items in first in menu
391
                    array_unshift($value['top']['items'], [
392
                        'admin' => $this->adminName,
393
                        'action' => 'list',
394
                        // Do not use the translation trait as the action configuration is not configured yet, so
395
                        // translation parameters are not available
396
                        'text' => $text,
397
                        'icon' => 'arrow-left',
398
                    ]);
399
                }
400
401
                return $value;
402
            })
403
        ;
404
    }
405
406
    protected function configureRepository(OptionsResolver $resolver): void
407
    {
408
        $resolver
409
            ->setDefaults([
410
                'repository' => $this->adminConfiguration->get('repository'),
411
                'repository_method' => null,
412
            ])
413
        ;
414
    }
415
416
    protected function configureRouting(OptionsResolver $resolver): void
417
    {
418
        $resolver
419
            ->setDefaults([
420
                'controller' => $this->adminConfiguration->get('controller'),
421
                'route' => $this->generateRouteName(),
422
                'route_parameters' => [],
423
                'route_path' => $this->getDefaultRoutePath(),
424
                'route_requirements' => [],
425
                'route_defaults' => [],
426
            ])
427
            ->setAllowedTypes('route', 'string')
428
            ->setAllowedTypes('route_parameters', 'array')
429
            ->setAllowedTypes('route_path', 'string')
430
            ->setAllowedTypes('route_defaults', 'array')
431
            ->setAllowedTypes('route_requirements', 'array')
432
            ->setNormalizer('route_defaults', function (Options $options, $value) {
433
                if (!$value || is_array($value)) {
434
                    $value = [];
435
                }
436
437
                if (!key_exists('_controller', $value) || !$value['_controller']) {
438
                    $value['_controller'] = $options->offsetGet('controller');
439
                }
440
                $value['_admin'] = $this->adminName;
441
                $value['_action'] = $this->actionName;
442
443
                return $value;
444
            })
445
        ;
446
    }
447
}
448