Completed
Push — dev ( 243dfc...851a92 )
by Arnaud
9s
created

ActionConfiguration   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 367
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 77.88%

Importance

Changes 2
Bugs 2 Features 0
Metric Value
wmc 33
c 2
b 2
f 0
lcom 1
cbo 9
dl 0
loc 367
ccs 88
cts 113
cp 0.7788
rs 9.3999

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A configureOptions() 0 8 1
B configureDefaultOptions() 0 40 1
A setAllowedValues() 0 14 1
A setAllowedTypes() 0 17 1
A configureNormalizers() 0 12 1
A getFieldsNormalizer() 0 17 3
B getOrderNormalizer() 0 17 5
A getRouteNormalizer() 0 18 3
A getLoadStrategyNormalizer() 0 16 4
A getMenuNormalizer() 0 11 2
A getCriteriaNormalizer() 0 19 3
B getBatchNormalizer() 0 42 5
A getDefaultTitle() 0 21 2
1
<?php
2
3
namespace LAG\AdminBundle\Action\Configuration;
4
5
use Closure;
6
use LAG\AdminBundle\Admin\AdminInterface;
7
use LAG\AdminBundle\Admin\Behaviors\TranslationKeyTrait;
8
use LAG\AdminBundle\Configuration\Configuration;
9
use LAG\AdminBundle\Menu\Configuration\MenuConfiguration;
10
use Symfony\Component\DependencyInjection\Container;
11
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
12
use Symfony\Component\OptionsResolver\Options;
13
use Symfony\Component\OptionsResolver\OptionsResolver;
14
15
class ActionConfiguration extends Configuration
16
{
17
    use TranslationKeyTrait;
18
19
    /**
20
     * Related Action name.
21
     *
22
     * @var string
23
     */
24
    protected $actionName;
25
26
    /**
27
     * Related Admin (optional)
28
     *
29
     * @var AdminInterface
30
     */
31
    protected $admin = null;
32
33
    /**
34
     * ActionConfiguration constructor.
35
     *
36
     * @param string $actionName
37 16
     * @param AdminInterface|null $admin
38
     */
39 16
    public function __construct($actionName, AdminInterface $admin = null)
40
    {
41 16
        parent::__construct();
42 16
43 16
        $this->actionName = $actionName;
44
        $this->admin = $admin;
45
    }
46
47
    /**
48
     * Define allowed parameters and values for this configuration, using optionsResolver component.
49
     *
50 15
     * @param OptionsResolver $resolver
51
     */
52
    public function configureOptions(OptionsResolver $resolver)
53 15
    {
54
        $this->configureDefaultOptions($resolver);
55 15
        $this->configureNormalizers($resolver);
56 15
57
        $this->setAllowedTypes($resolver);
58
        $this->setAllowedValues($resolver);
59 15
    }
60 15
61 15
    /**
62 15
     * Configure the default options for an Action.
63 15
     *
64 15
     * @param OptionsResolver $resolver
65
     */
66
    protected function configureDefaultOptions(OptionsResolver $resolver)
67
    {
68 15
        $resolver
69 15
            ->setDefaults([
70 15
                // the default action title is a translation key using the translation pattern and the action name
71 15
                'title' => $this->getDefaultTitle(),
72
                // the default field mapping configuration: id=23 in request, getId() in the entity
73 15
                'fields' => [
74
                    'id' => []
75 15
                ],
76
                // by default, only administrator can access the admin
77 15
                'permissions' => [
78
                    'ROLE_ADMIN'
79
                ],
80
                // all export are activated
81 15
                'export' => [
82 15
                    'json',
83
                    'html',
84 15
                    'csv',
85 15
                    'xls'
86
                ],
87
                // no order
88
                'order' => [],
89
                // route will be generated if empty string or null or false is provided
90 15
                'route' => '',
91
                // route parameters will be used when using the route (for links...)
92 15
                'route_parameters' => [],
93
                // icon in the menu
94
                'icon' => '',
95
                // entities loading strategy
96 15
                'load_strategy' => null,
97 15
                // pager interface, only null or pagerfanta are allowed
98 15
                'pager' => 'pagerfanta',
99 15
                // default criteria used to load entities
100
                'criteria' => [],
101 15
                'filters' => [],
102
                'menus' => [],
103
                'batch' => false,
104
            ]);
105
    }
106 15
107 15
    /**
108
     * Define the allowed values.
109
     *
110
     * @param OptionsResolver $resolver
111 15
     */
112 15
    protected function setAllowedValues(OptionsResolver $resolver)
113
    {
114 15
        $resolver
115
            ->setAllowedValues('load_strategy', [
116 14
                AdminInterface::LOAD_STRATEGY_NONE,
117
                AdminInterface::LOAD_STRATEGY_UNIQUE,
118
                AdminInterface::LOAD_STRATEGY_MULTIPLE,
119
                null
120
            ])
121 14
            ->setAllowedValues('pager', [
122
                'pagerfanta',
123 14
                false
124
            ]);
125
    }
126 1
127 15
    /**
128
     * Define the allowed types.
129
     *
130
     * @param OptionsResolver $resolver
131 15
     */
132 15
    protected function setAllowedTypes(OptionsResolver $resolver)
133
    {
134
        $resolver
135
            ->setAllowedTypes('title', 'string')
136 15
            ->setAllowedTypes('fields', 'array')
137 15
            ->setAllowedTypes('order', 'array')
138
            ->setAllowedTypes('route', 'string')
139
            ->setAllowedTypes('route_parameters', 'array')
140
            ->setAllowedTypes('icon', 'string')
141 15
            ->setAllowedTypes('criteria', 'array')
142 15
            ->setAllowedTypes('filters', 'array')
143 15
            ->setAllowedTypes('menus', [
144 15
                'array',
145 15
                'boolean',
146
            ])
147
        ;
148 14
    }
149 6
150
    /**
151 6
     * Configure the normalizers.
152
     *
153
     * @param OptionsResolver $resolver
154 6
     */
155
    protected function configureNormalizers(OptionsResolver $resolver)
156 6
    {
157
        $resolver
158 14
            ->setNormalizer('fields', $this->getFieldsNormalizer())
159 15
            ->setNormalizer('order', $this->getOrderNormalizer())
160
            ->setNormalizer('route', $this->getRouteNormalizer())
161
            ->setNormalizer('load_strategy', $this->getLoadStrategyNormalizer())
162
            ->setNormalizer('criteria', $this->getCriteriaNormalizer())
163 15
            ->setNormalizer('menus', $this->getMenuNormalizer())
164 15
            ->setNormalizer('batch', $this->getBatchNormalizer())
165 15
        ;
166
    }
167
168
    /**
169
     * Return the field normalizer. It will transform null configuration into array to allow field type guessing
170 15
     * working.
171
     *
172
     * @return Closure
173 14
     */
174
    protected function getFieldsNormalizer()
175 14
    {
176
        return function(Options $options, $fields) {
177 14
            $normalizedFields = [];
178
179 14
            foreach ($fields as $name => $field) {
180
181
                if ($field === null) {
182 1
                    $field = [];
183 1
                }
184 14
185
                $normalizedFields[$name] = $field;
186 14
            }
187 15
188
            return $normalizedFields;
189
        };
190
    }
191 15
192
    /**
193
     * Return the order normalizer. It will check if the order value passed are valid.
194
     *
195 15
     * @return Closure
196
     */
197
    protected function getOrderNormalizer()
198 14
    {
199
        return function(Options $options, $order) {
200
            foreach ($order as $field => $sort) {
201
202 14
                if (!is_string($sort) || !is_string($field) || !in_array(strtolower($sort), ['asc', 'desc'])) {
203 15
                    throw new ConfigurationException(
204
                        'Order value should be an array of string (["field" => $key]), got '.gettype($sort),
205
                        $this->actionName,
206
                        $this->admin
207
                    );
208
                }
209 15
            }
210 15
211
            return $order;
212
        };
213 14
    }
214
215
    /**
216
     * Return the route normalizer. If an empty value or null or false, it will generate the route using the Admin.
217 14
     *
218
     * @return Closure
219 14
     */
220
    protected function getRouteNormalizer()
221 14
    {
222 14
        return function(Options $options, $value) {
223
            if (!$value) {
224 14
                // if no route was provided, it should be linked to an Admin
225
                if (!$this->admin) {
226
                    throw new InvalidOptionsException('No route was provided for action : '.$this->actionName);
227
                }
228
229
                // generate default route from admin
230
                return $this
231
                    ->admin
232
                    ->generateRouteName($this->actionName);
233
            }
234
235
            return $value;
236
        };
237
    }
238
239
    /**
240 14
     * Return the load strategy normalizer. It will set the default strategy according to the action name, if no value
241
     * is provided.
242
     *
243
     * @return Closure
244
     */
245
    protected function getLoadStrategyNormalizer()
246
    {
247
        return function(Options $options, $value) {
248
            if (!$value) {
249 15
                if ($this->actionName == 'create') {
250
                    $value = AdminInterface::LOAD_STRATEGY_NONE;
251 15
                } else if ($this->actionName == 'list') {
252
                    $value = AdminInterface::LOAD_STRATEGY_MULTIPLE;
253
                } else {
254
                    $value = AdminInterface::LOAD_STRATEGY_UNIQUE;
255
                }
256
            }
257
258
            return $value;
259
        };
260
    }
261
262
    /**
263
     * Return the menu normalizer. It will transform false values into an empty array to allow default menu
264
     * configuration working.
265
     *
266
     * @return Closure
267
     */
268
    protected function getMenuNormalizer()
269
    {
270
        return function(Options $options, $menus) {
271
            // set default to an array
272
            if ($menus === false) {
273
                $menus = [];
274
            }
275
276
            return $menus;
277
        };
278
    }
279
280
    /**
281
     * Return the criteria normalizer. It will add the id parameters for the edit and delete actions if no value is
282
     * provided.
283
     *
284
     * @return Closure
285
     */
286
    protected function getCriteriaNormalizer()
287
    {
288
        return function(Options $options, $value) {
289
            if (!$value) {
290
                $idActions = [
291
                    'edit',
292
                    'delete'
293
                ];
294
295
                if (in_array($this->actionName, $idActions)) {
296
                    $value = [
297
                        'id'
298
                    ];
299
                }
300
            }
301
302
            return $value;
303
        };
304
    }
305
306
    /**
307
     * Return the batch normalizer. If null value is provided, it will add the delete batch action if the delete
308
     * actions is allowed .
309
     *
310
     * @return Closure
311
     */
312
    protected function getBatchNormalizer()
313
    {
314
        return function(Options $options, $batch) {
315
            // if batch is not activated, no more checks should be done
316
            if ($batch === false) {
317
                return $batch;
318
            }
319
            // for list actions, we add a default configuration
320
            if ($batch === null) {
321
                // delete action should be allowed in order to be place in batch actions
322
                $allowedActions = array_keys($this
323
                    ->admin
324
                    ->getConfiguration()
325
                    ->getParameter('actions'));
326
327
                if ($this->actionName == 'list' && in_array('delete', $allowedActions)) {
328
                    $pattern = $this
329
                        ->admin
330
                        ->getConfiguration()
331
                        ->getParameter('translation_pattern');
332
333
                    $batch = [
334
                        'items' => [
335
                            'delete' => [
336
                                'admin' => $this->admin->getName(),
337
                                'action' => 'delete',
338
                                'text' => $this->getTranslationKey($pattern, 'delete', $this->admin->getName())
339
                            ]
340
                        ]
341
                    ];
342
                } else {
343
                    return $batch;
344
                }
345
            }
346
            $resolver = new OptionsResolver();
347
            $configuration = new MenuConfiguration();
348
            $configuration->configureOptions($resolver);
349
            $batch = $resolver->resolve($batch);
350
351
            return $batch;
352
        };
353
    }
354
355
    /**
356
     * Return the default title using the configured translation pattern.
357
     *
358
     * @return string
359
     */
360
    protected function getDefaultTitle()
361
    {
362
        if ($this->admin) {
363
            // by default, the action title is action name using the configured translation pattern
364
            $translationPattern = $this
365
                ->admin
366
                ->getConfiguration()
367
                ->getParameter('translation_pattern');
368
369
            $actionTitle = $this->getTranslationKey(
370
                $translationPattern,
371
                $this->actionName,
372
                $this->admin->getName()
373
            );
374
        } else {
375
            // no admin was provided, we camelize the action name
376
            $actionTitle = Container::camelize($this->actionName);
377
        }
378
379
        return $actionTitle;
380
    }
381
}
382