Completed
Push — refonte ( 2cad75...548acb )
by Arnaud
06:10
created

ActionConfiguration::getFormNormalizer()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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