Completed
Pull Request — master (#90)
by Arnaud
15:25
created

addDefaultMenuConfiguration()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 37
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 20
cts 20
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 20
nc 6
nop 4
crap 5
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 1
            ActionEvents::BEFORE_CONFIGURATION => 'beforeActionConfiguration',
50 1
        ];
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 1
                'create' => [],
87 1
                'list' => [],
88 1
                'edit' => [],
89 1
                'delete' => [],
90
            ];
91 1
            $event->setAdminConfiguration($configuration);
92 1
        }
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 3
            $configuration,
123
            $allowedActions
124 3
        );
125
126
        // guess field configuration if required
127 3
        $this->guessFieldConfiguration(
128 3
            $configuration,
129 3
            $event->getActionName(),
130 3
            $admin->getConfiguration()->getParameter('entity')
131 3
        );
132
133
        // guess linked actions for list actions
134 3
        $this->guessLinkedActionsConfiguration(
135 3
            $configuration,
136 3
            $allowedActions,
137
            $event
138 3
        );
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 2
                }
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 2
                            ]
180 2
                        ]
181 2
                    ]);
182
                    // resolve default menu options
183 2
                    $actionConfiguration['menus'] = $resolver->resolve($actionConfiguration['menus']);
184 2
                }
185 2
            }
186 2
        }
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 2
            $metadata = $this
205
                ->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 1
                    $fields[$name] = $fieldConfiguration;
218 1
                }
219 2
            }
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 1
                }
227 1
            }
228 2
        }
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 1
            $translationPattern = $this
258
                ->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 1
                        ],
272
                        'icon' => 'pencil'
273 1
                    ]
274 1
                ];
275 1
            }
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 1
                        ],
287
                        'icon' => 'remove'
288 1
                    ]
289 1
                ];
290 1
            }
291 1
        }
292 2
    }
293
}
294