Completed
Branch master (b7eb35)
by Arnaud
02:59
created

ActionConfiguration::setAllowedValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4285
cc 1
eloc 10
nc 1
nop 1
crap 1
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
     * @param AdminInterface|null $admin
38
     */
39 24
    public function __construct($actionName, AdminInterface $admin = null)
40
    {
41 24
        parent::__construct();
42
43 24
        $this->actionName = $actionName;
44 24
        $this->admin = $admin;
45 24
    }
46
47
    /**
48
     * Define allowed parameters and values for this configuration, using optionsResolver component.
49
     *
50
     * @param OptionsResolver $resolver
51
     */
52 21
    public function configureOptions(OptionsResolver $resolver)
53
    {
54 21
        $this->configureDefaultOptions($resolver);
55 21
        $this->configureNormalizers($resolver);
56
57 21
        $this->setAllowedTypes($resolver);
58 21
        $this->setAllowedValues($resolver);
59 21
    }
60
61
    /**
62
     * Configure the default options for an Action.
63
     *
64
     * @param OptionsResolver $resolver
65
     */
66 21
    protected function configureDefaultOptions(OptionsResolver $resolver)
67
    {
68
        $resolver
69 21
            ->setDefaults([
70
                // the default action title is a translation key using the translation pattern and the action name
71 21
                'title' => $this->getDefaultTitle(),
72
                // the default field mapping configuration: id=23 in request, getId() in the entity
73
                'fields' => [
74
                    'id' => []
75
                ],
76
                // by default, only administrator can access the admin
77
                'permissions' => [
78
                    'ROLE_ADMIN'
79
                ],
80
                // all export are activated
81
                'export' => [
82
                    'json',
83
                    'html',
84
                    'csv',
85
                    'xls'
86
                ],
87
                // no order
88
                'order' => [],
89
                // route will be generated if empty string or null or false is provided
90 21
                'route' => '',
91
                // route parameters will be used when using the route (for links...)
92
                'route_parameters' => [],
93
                // icon in the menu
94 21
                'icon' => '',
95
                // entities loading strategy
96
                'load_strategy' => null,
97
                // pager interface, only null or pagerfanta are allowed
98 21
                'pager' => 'pagerfanta',
99
                // default criteria used to load entities
100
                'criteria' => [],
101
                'filters' => [],
102
                'menus' => [],
103
                'batch' => false,
104
            ]);
105 21
    }
106
107
    /**
108
     * Define the allowed values.
109
     *
110
     * @param OptionsResolver $resolver
111
     */
112 21
    protected function setAllowedValues(OptionsResolver $resolver)
113
    {
114
        $resolver
115 21
            ->setAllowedValues('load_strategy', [
116 21
                AdminInterface::LOAD_STRATEGY_NONE,
117 21
                AdminInterface::LOAD_STRATEGY_UNIQUE,
118 21
                AdminInterface::LOAD_STRATEGY_MULTIPLE,
119
                null
120
            ])
121 21
            ->setAllowedValues('pager', [
122 21
                'pagerfanta',
123
                false
124
            ]);
125 21
    }
126
127
    /**
128
     * Define the allowed types.
129
     *
130
     * @param OptionsResolver $resolver
131
     */
132 21
    protected function setAllowedTypes(OptionsResolver $resolver)
133
    {
134
        $resolver
135 21
            ->setAllowedTypes('title', 'string')
136 21
            ->setAllowedTypes('fields', 'array')
137 21
            ->setAllowedTypes('order', 'array')
138 21
            ->setAllowedTypes('route', 'string')
139 21
            ->setAllowedTypes('route_parameters', 'array')
140 21
            ->setAllowedTypes('icon', 'string')
141 21
            ->setAllowedTypes('criteria', 'array')
142 21
            ->setAllowedTypes('filters', 'array')
143 21
            ->setAllowedTypes('menus', [
144 21
                'array',
145
                'boolean',
146
            ])
147
        ;
148 21
    }
149
150
    /**
151
     * Configure the normalizers.
152
     *
153
     * @param OptionsResolver $resolver
154
     */
155 21
    protected function configureNormalizers(OptionsResolver $resolver)
156
    {
157
        $resolver
158 21
            ->setNormalizer('fields', $this->getFieldsNormalizer())
159 21
            ->setNormalizer('order', $this->getOrderNormalizer())
160 21
            ->setNormalizer('route', $this->getRouteNormalizer())
161 21
            ->setNormalizer('load_strategy', $this->getLoadStrategyNormalizer())
162 21
            ->setNormalizer('criteria', $this->getCriteriaNormalizer())
163 21
            ->setNormalizer('menus', $this->getMenuNormalizer())
164 21
            ->setNormalizer('batch', $this->getBatchNormalizer())
165
        ;
166 21
    }
167
168
    /**
169
     * Return the field normalizer. It will transform null configuration into array to allow field type guessing
170
     * working.
171
     *
172
     * @return Closure
173
     */
174 21
    protected function getFieldsNormalizer()
175
    {
176
        return function(Options $options, $fields) {
177 21
            $normalizedFields = [];
178
179 21
            foreach ($fields as $name => $field) {
180
181 21
                if ($field === null) {
182 1
                    $field = [];
183
                }
184
185 21
                $normalizedFields[$name] = $field;
186
            }
187
188 21
            return $normalizedFields;
189 21
        };
190
    }
191
192
    /**
193
     * Return the order normalizer. It will check if the order value passed are valid.
194
     *
195
     * @return Closure
196
     */
197 21
    protected function getOrderNormalizer()
198
    {
199
        return function(Options $options, $order) {
200 21
            foreach ($order as $field => $sort) {
201
202 2
                if (!is_string($sort) || !is_string($field) || !in_array(strtolower($sort), ['asc', 'desc'])) {
203 1
                    throw new ConfigurationException(
204 1
                        'Order value should be an array of string (["field" => $key]), got '.gettype($sort),
205 1
                        $this->actionName,
206 2
                        $this->admin
207
                    );
208
                }
209
            }
210
211 20
            return $order;
212 21
        };
213
    }
214
215
    /**
216
     * Return the route normalizer. If an empty value or null or false, it will generate the route using the Admin.
217
     *
218
     * @return Closure
219
     */
220 21
    protected function getRouteNormalizer()
221
    {
222
        return function(Options $options, $value) {
223 20
            if (!$value) {
224
                // if no route was provided, it should be linked to an Admin
225 19
                if (!$this->admin) {
226 1
                    throw new InvalidOptionsException('No route was provided for action : '.$this->actionName);
227
                }
228
229
                // generate default route from admin
230
                return $this
231 18
                    ->admin
232 18
                    ->generateRouteName($this->actionName);
233
            }
234
235 1
            return $value;
236 21
        };
237
    }
238
239
    /**
240
     * 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 21
    protected function getLoadStrategyNormalizer()
246
    {
247
        return function(Options $options, $value) {
248 18
            if (!$value) {
249 9
                if ($this->actionName == 'create') {
250
                    $value = AdminInterface::LOAD_STRATEGY_NONE;
251 9
                } else if ($this->actionName == 'list') {
252
                    $value = AdminInterface::LOAD_STRATEGY_MULTIPLE;
253
                } else {
254 9
                    $value = AdminInterface::LOAD_STRATEGY_UNIQUE;
255
                }
256
            }
257
258 18
            return $value;
259 21
        };
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 21
    protected function getMenuNormalizer()
269
    {
270
        return function(Options $options, $menus) {
271
            // set default to an array
272 18
            if ($menus === false) {
273
                $menus = [];
274
            }
275
276 18
            return $menus;
277 21
        };
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 21
    protected function getCriteriaNormalizer()
287
    {
288
        return function(Options $options, $value) {
289 18
            if (!$value) {
290
                $idActions = [
291 18
                    'edit',
292
                    'delete'
293
                ];
294
295 18
                if (in_array($this->actionName, $idActions)) {
296
                    $value = [
297
                        'id'
298 1
                    ];
299
                }
300
            }
301
302 18
            return $value;
303 21
        };
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 21
        return function(Options $options, $batch) {
315
            // if batch is not activated, no more checks should be done
316 18
            if ($batch === false) {
317 18
                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 21
        };
353
    }
354
355
    /**
356
     * Return the default title using the configured translation pattern.
357
     *
358
     * @return string
359
     */
360 21
    protected function getDefaultTitle()
361
    {
362 21
        if ($this->admin) {
363
            // by default, the action title is action name using the configured translation pattern
364
            $translationPattern = $this
365 19
                ->admin
366 19
                ->getConfiguration()
367 19
                ->getParameter('translation_pattern');
368
369 19
            $actionTitle = $this->getTranslationKey(
370
                $translationPattern,
371 19
                $this->actionName,
372 19
                $this->admin->getName()
373
            );
374
        } else {
375
            // no admin was provided, we camelize the action name
376 2
            $actionTitle = Container::camelize($this->actionName);
377
        }
378
379 21
        return $actionTitle;
380
    }
381
}
382