Completed
Pull Request — master (#90)
by Arnaud
03:14
created

ExtraConfigurationSubscriber   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 273
Duplicated Lines 10.26 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 95.7%

Importance

Changes 0
Metric Value
wmc 28
c 0
b 0
f 0
lcom 1
cbo 12
dl 28
loc 273
ccs 89
cts 93
cp 0.957
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A getSubscribedEvents() 0 7 1
A adminCreate() 0 18 4
B addDefaultMenuConfiguration() 0 37 5
C guessFieldConfiguration() 0 32 7
B guessLinkedActionsConfiguration() 28 55 8
B beforeActionConfiguration() 0 43 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace LAG\AdminBundle\Event\Subscriber;
4
5
use Doctrine\Bundle\DoctrineBundle\Registry;
6
use Doctrine\ORM\EntityManager;
7
use LAG\AdminBundle\Action\Event\ActionEvents;
8
use LAG\AdminBundle\Action\Event\BeforeConfigurationEvent;
9
use LAG\AdminBundle\Admin\Behaviors\TranslationKeyTrait;
10
use LAG\AdminBundle\Admin\Event\AdminCreateEvent;
11
use LAG\AdminBundle\Application\Configuration\ApplicationConfiguration;
12
use LAG\AdminBundle\Configuration\Factory\ConfigurationFactory;
13
use LAG\AdminBundle\Admin\Event\AdminEvents;
14
use LAG\AdminBundle\Utils\FieldTypeGuesser;
15
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16
use Symfony\Component\OptionsResolver\OptionsResolver;
17
18
/**
19
 * Add extra default configuration for actions and fields. Bind to ADMIN_CREATE and ACTION_CREATE events
20
 */
21
class ExtraConfigurationSubscriber implements EventSubscriberInterface
22
{
23
    use TranslationKeyTrait;
24
25
    /**
26
     * If is true, the extra configuration will be added.
27
     *
28
     * @var boolean
29
     */
30
    protected $extraConfigurationEnabled = false;
31
32
    /**
33
     * @var EntityManager
34
     */
35
    protected $entityManager;
36
37
    /**
38
     * @var ApplicationConfiguration
39
     */
40
    protected $applicationConfiguration;
41
42
    /**
43
     * @return array
44
     */
45 1
    public static function getSubscribedEvents()
46
    {
47
        return [
48 1
            AdminEvents::ADMIN_CREATE => 'adminCreate',
49
            ActionEvents::BEFORE_CONFIGURATION => 'beforeActionConfiguration',
50
        ];
51
    }
52
53
    /**
54
     * ExtraConfigurationSubscriber constructor.
55
     *
56
     * @param boolean $extraConfigurationEnabled
57
     * @param Registry $doctrine
58
     * @param ConfigurationFactory $configurationFactory
59
     */
60 6
    public function __construct(
61
        $extraConfigurationEnabled = true,
62
        Registry $doctrine,
63
        ConfigurationFactory $configurationFactory
64
    ) {
65 6
        $this->extraConfigurationEnabled = $extraConfigurationEnabled;
66
        // entity manager can be closed, so its better to inject the Doctrine registry instead
67 6
        $this->entityManager = $doctrine->getManager();
68 6
        $this->applicationConfiguration = $configurationFactory->getApplicationConfiguration();
69 6
    }
70
71
    /**
72
     * Adding default CRUD if none is defined.
73
     *
74
     * @param AdminCreateEvent $event
75
     */
76 2
    public function adminCreate(AdminCreateEvent $event)
77
    {
78 2
        if (!$this->extraConfigurationEnabled) {
79 1
            return;
80
        }
81 1
        $configuration = $event->getAdminConfiguration();
82
83
        // if no actions are defined, we set default CRUD action
84 1
        if (!array_key_exists('actions', $configuration) || !count($configuration['actions'])) {
85 1
            $configuration['actions'] = [
86
                'create' => [],
87
                'list' => [],
88
                'edit' => [],
89
                'delete' => [],
90
            ];
91 1
            $event->setAdminConfiguration($configuration);
92
        }
93 1
    }
94
95
    /**
96
     * Add default linked actions and default menu actions.
97
     *
98
     * @param BeforeConfigurationEvent $event
99
     */
100 4
    public function beforeActionConfiguration(BeforeConfigurationEvent $event)
101
    {
102
        // add configuration only if extra configuration is enabled
103 4
        if (!$this->extraConfigurationEnabled) {
104 1
            return;
105
        }
106
        // Action configuration array
107 3
        $configuration = $event->getActionConfiguration();
108
        
109
        // current Admin
110 3
        $admin = $event->getAdmin();
111
        
112
        // allowed Actions according to the admin
113
        $keys = $admin
114 3
            ->getConfiguration()
115 3
            ->getParameter('actions');
116 3
        $allowedActions = array_keys($keys);
117
118
        // add default menu configuration
119 3
        $configuration = $this->addDefaultMenuConfiguration(
120 3
            $admin->getName(),
121 3
            $event->getActionName(),
122
            $configuration,
123 3
            $allowedActions
124
        );
125
126
        // guess field configuration if required
127 3
        $this->guessFieldConfiguration(
128
            $configuration,
129 3
            $event->getActionName(),
130 3
            $admin->getConfiguration()->getParameter('entity')
131
        );
132
133
        // guess linked actions for list actions
134 3
        $this->guessLinkedActionsConfiguration(
135
            $configuration,
136
            $allowedActions,
137 3
            $event
138
        );
139
140
        // reset action configuration
141 3
        $event->setActionConfiguration($configuration);
142 3
    }
143
144
    /**
145
     * Add default menu configuration for an action.
146
     *
147
     * @param string $adminName
148
     * @param string $actionName
149
     * @param array $actionConfiguration
150
     * @param array $allowedActions
151
     * @return array The modified configuration
152
     */
153 3
    protected function addDefaultMenuConfiguration(
154
        $adminName,
155
        $actionName,
156
        array $actionConfiguration,
157
        array $allowedActions
158
    ) {
159
        // we add a default top menu item "create" only for list action
160 3
        if ($actionName === 'list') {
161
162
            // the create action should enabled
163 2
            if (in_array('create', $allowedActions)) {
164
165 2
                if (!array_key_exists('menus', $actionConfiguration)) {
166 2
                    $actionConfiguration['menus'] = [];
167
                }
168
                // if the menu is disabled we do not add the menu item
169 2
                if ($actionConfiguration['menus'] !== false) {
170 2
                    $resolver = new OptionsResolver();
171 2
                    $resolver->setDefaults([
172
                        'top' => [
173
                            'items' => [
174
                                'create' => [
175 2
                                    'admin' => $adminName,
176 2
                                    'action' => 'create',
177 2
                                    'icon' => 'fa fa-plus',
178
                                ]
179
                            ]
180
                        ]
181
                    ]);
182
                    // resolve default menu options
183 2
                    $actionConfiguration['menus'] = $resolver->resolve($actionConfiguration['menus']);
184
                }
185
            }
186
        }
187
188 3
        return $actionConfiguration;
189
    }
190
191
    /**
192
     * If no field was provided, try to guess field
193
     *
194
     * @param array $configuration
195
     * @param $actionName
196
     * @param $entityClass
197
     */
198 3
    protected function guessFieldConfiguration(array &$configuration, $actionName, $entityClass)
199
    {
200
        // if no field was provided in configuration, we try to take fields from doctrine metadata
201 3
        if (empty($configuration['fields']) || !count($configuration['fields'])) {
202 2
            $fields = [];
203 2
            $guesser = new FieldTypeGuesser();
204
            $metadata = $this
205 2
                ->entityManager
206 2
                ->getMetadataFactory()
207 2
                ->getMetadataFor($entityClass);
208 2
            $fieldsName = $metadata->getFieldNames();
209
210 2
            foreach ($fieldsName as $name) {
211 2
                $type = $metadata->getTypeOfField($name);
212
                // get field type from doctrine type
213 2
                $fieldConfiguration = $guesser->getTypeAndOptions($type);
214
215
                // if a field configuration was found, we take it
216 2
                if (count($fieldConfiguration)) {
217 2
                    $fields[$name] = $fieldConfiguration;
218
                }
219
            }
220 2
            if (count($fields)) {
221
                // adding new fields to action configuration
222 1
                $configuration['fields'] = $fields;
223
224 1
                if ($actionName == 'list') {
225 1
                    $configuration['fields']['_actions'] = null;
226
                }
227
            }
228
        }
229 3
    }
230
231
    /**
232
     * Add fake link fields to edit and delete action for the list view.
233
     *
234
     * @param array $configuration
235
     * @param array $allowedActions
236
     * @param BeforeConfigurationEvent $event
237
     */
238 3
    protected function guessLinkedActionsConfiguration(
239
        array &$configuration,
240
        array $allowedActions,
241
        BeforeConfigurationEvent $event
242
    ) {
243 3
        if (!array_key_exists('fields', $configuration)) {
244 1
            return;
245
        }
246
247
        // configured linked actions :
248
        // _action key should exists and be null
249 2
        $_actionExists = array_key_exists('_actions', $configuration['fields']);
250 2
        $_actionIsNull = $_actionExists && $configuration['fields']['_actions'] === null;
251
252
        // _action is added extra configuration only for the "list" action
253 2
        $isListAction = $event->getActionName() == 'list';
254
255 2
        if ($_actionExists && $_actionIsNull && $isListAction) {
256
            // in list view, we add by default and an edit and a delete button
257
            $translationPattern = $this
258 1
                ->applicationConfiguration
259 1
                ->getParameter('translation')['pattern'];
260
261
            // add a link to the "edit" action, if it is allowed
262 1 View Code Duplication
            if (in_array('edit', $allowedActions)) {
263 1
                $configuration['fields']['_actions']['type'] = 'collection';
264 1
                $configuration['fields']['_actions']['options']['_edit'] = [
265 1
                    'type' => 'action',
266
                    'options' => [
267 1
                        'title' => $this->getTranslationKey($translationPattern, 'edit', $event->getAdmin()->getName()),
268 1
                        'route' => $event->getAdmin()->generateRouteName('edit'),
269
                        'parameters' => [
270
                            'id' => false
271
                        ],
272 1
                        'icon' => 'pencil'
273
                    ]
274
                ];
275
            }
276
            // add a link to the "delete" action, if it is allowed
277 1 View Code Duplication
            if (in_array('delete', $allowedActions)) {
278 1
                $configuration['fields']['_actions']['type'] = 'collection';
279 1
                $configuration['fields']['_actions']['options']['_delete'] = [
280 1
                    'type' => 'action',
281
                    'options' => [
282 1
                        'title' => $this->getTranslationKey($translationPattern, 'delete', $event->getAdmin()->getName()),
283 1
                        'route' => $event->getAdmin()->generateRouteName('delete'),
284
                        'parameters' => [
285
                            'id' => false
286
                        ],
287 1
                        'icon' => 'remove'
288
                    ]
289
                ];
290
            }
291
        }
292 2
    }
293
}
294