Completed
Pull Request — dev (#48)
by Arnaud
03:46
created

ExtraConfigurationSubscriber   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 225
Duplicated Lines 12.44 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 58.88%

Importance

Changes 16
Bugs 4 Features 3
Metric Value
wmc 25
c 16
b 4
f 3
lcom 1
cbo 12
dl 28
loc 225
ccs 63
cts 107
cp 0.5888
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 7 1
A __construct() 0 10 1
A adminCreate() 0 19 4
D actionCreate() 28 100 14
B addDefaultMenuConfiguration() 0 33 5

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