1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace LAG\AdminBundle\Event\Subscriber; |
4
|
|
|
|
5
|
|
|
use Doctrine\ORM\EntityManagerInterface; |
6
|
|
|
use Exception; |
7
|
|
|
use LAG\AdminBundle\Configuration\ApplicationConfiguration; |
8
|
|
|
use LAG\AdminBundle\Configuration\ApplicationConfigurationStorage; |
9
|
|
|
use LAG\AdminBundle\Event\AdminEvents; |
10
|
|
|
use LAG\AdminBundle\Event\ConfigurationEvent; |
11
|
|
|
use LAG\AdminBundle\Event\Menu\MenuConfigurationEvent; |
12
|
|
|
use LAG\AdminBundle\Factory\ConfigurationFactory; |
13
|
|
|
use LAG\AdminBundle\LAGAdminBundle; |
14
|
|
|
use LAG\AdminBundle\Resource\ResourceCollection; |
15
|
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Add extra default configuration for actions and fields. |
19
|
|
|
*/ |
20
|
|
|
class ExtraConfigurationSubscriber implements EventSubscriberInterface |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* @var ApplicationConfiguration |
24
|
|
|
*/ |
25
|
|
|
private $applicationConfiguration; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var EntityManagerInterface |
29
|
|
|
*/ |
30
|
|
|
private $entityManager; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var ResourceCollection |
34
|
|
|
*/ |
35
|
|
|
private $resourceCollection; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var ConfigurationFactory |
39
|
|
|
*/ |
40
|
|
|
private $configurationFactory; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @return array |
44
|
|
|
*/ |
45
|
|
|
public static function getSubscribedEvents() |
46
|
|
|
{ |
47
|
|
|
return [ |
48
|
|
|
AdminEvents::ADMIN_CONFIGURATION => 'enrichAdminConfiguration', |
49
|
|
|
AdminEvents::MENU_CONFIGURATION => 'enrichMenuConfiguration', |
50
|
|
|
]; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* ExtraConfigurationSubscriber constructor. |
55
|
|
|
* |
56
|
|
|
* @param ApplicationConfigurationStorage $applicationConfigurationStorage |
57
|
|
|
* @param EntityManagerInterface $entityManager |
58
|
|
|
* @param ResourceCollection $resourceCollection |
59
|
|
|
* @param ConfigurationFactory $configurationFactory |
60
|
|
|
*/ |
61
|
|
View Code Duplication |
public function __construct( |
|
|
|
|
62
|
|
|
ApplicationConfigurationStorage $applicationConfigurationStorage, |
63
|
|
|
EntityManagerInterface $entityManager, |
64
|
|
|
ResourceCollection $resourceCollection, |
65
|
|
|
ConfigurationFactory $configurationFactory |
66
|
|
|
) { |
67
|
|
|
$this->applicationConfiguration = $applicationConfigurationStorage->getConfiguration(); |
68
|
|
|
$this->entityManager = $entityManager; |
69
|
|
|
$this->resourceCollection = $resourceCollection; |
70
|
|
|
$this->configurationFactory = $configurationFactory; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
public function enrichAdminConfiguration(ConfigurationEvent $event) |
74
|
|
|
{ |
75
|
|
|
if (!$this->isExtraConfigurationEnabled()) { |
76
|
|
|
return; |
77
|
|
|
} |
78
|
|
|
$configuration = $event->getConfiguration(); |
79
|
|
|
|
80
|
|
|
// Actions |
81
|
|
|
$this->addDefaultActions($configuration); |
82
|
|
|
|
83
|
|
|
// Fields |
84
|
|
|
$this->addDefaultFields($configuration, $event->getEntityClass(), $event->getAdminName()); |
85
|
|
|
$this->addDefaultStrategy($configuration); |
86
|
|
|
$this->addDefaultRouteParameters($configuration); |
87
|
|
|
$this->addDefaultFormUse($configuration); |
88
|
|
|
|
89
|
|
|
// Menus |
90
|
|
|
$this->addDefaultRightMenu($configuration); |
91
|
|
|
$this->addDefaultLeftMenu($configuration); |
92
|
|
|
|
93
|
|
|
// Filters |
94
|
|
|
$this->addDefaultFilters($configuration); |
95
|
|
|
|
96
|
|
|
$event->setConfiguration($configuration); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
public function enrichMenuConfiguration(MenuConfigurationEvent $event) |
100
|
|
|
{ |
101
|
|
|
if (!$this->isExtraConfigurationEnabled()) { |
102
|
|
|
return; |
103
|
|
|
} |
104
|
|
|
$configuration = $event->getMenuConfigurations(); |
105
|
|
|
|
106
|
|
|
if (!key_exists('top', $configuration) || [] === $configuration['top']) { |
107
|
|
|
$configuration['top'] = [ |
108
|
|
|
'brand' => $this->applicationConfiguration->getParameter('title'), |
109
|
|
|
]; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
if (!key_exists('left', $configuration) || [] === $configuration['left']) { |
113
|
|
|
$configuration['left'] = $this->configurationFactory->createResourceMenuConfiguration(); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
$event->setMenuConfigurations($configuration); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Defines the default CRUD actions if no action was configured. |
121
|
|
|
* |
122
|
|
|
* @param array $configuration |
123
|
|
|
*/ |
124
|
|
|
private function addDefaultActions(array &$configuration) |
125
|
|
|
{ |
126
|
|
|
if (!key_exists('actions', $configuration) || !is_array($configuration['actions'])) { |
127
|
|
|
$configuration['actions'] = []; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if (0 !== count($configuration['actions'])) { |
131
|
|
|
return; |
132
|
|
|
} |
133
|
|
|
$configuration['actions'] = [ |
134
|
|
|
'create' => [], |
135
|
|
|
'list' => [], |
136
|
|
|
'edit' => [], |
137
|
|
|
'delete' => [], |
138
|
|
|
]; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
private function addDefaultFields(array &$configuration, $entityClass, $adminName) |
142
|
|
|
{ |
143
|
|
|
$fieldsMapping = [ |
144
|
|
|
'string' => [ |
145
|
|
|
'type' => 'string', |
146
|
|
|
'options' => [ |
147
|
|
|
'length' => 100, |
148
|
|
|
], |
149
|
|
|
], |
150
|
|
|
'boolean' => [ |
151
|
|
|
'type' => 'boolean', |
152
|
|
|
'options' => [], |
153
|
|
|
], |
154
|
|
|
'datetime' => [ |
155
|
|
|
'type' => 'date', |
156
|
|
|
'options' => [], |
157
|
|
|
], |
158
|
|
|
]; |
159
|
|
|
|
160
|
|
|
foreach ($configuration['actions'] as $actionName => $action) { |
161
|
|
|
if (null === $action) { |
162
|
|
|
$action = []; |
163
|
|
|
} |
164
|
|
|
$metadata = $this->findMetadata($entityClass); |
165
|
|
|
|
166
|
|
|
if (null === $metadata) { |
167
|
|
|
continue; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
// If fields are already defined, nothing to do |
171
|
|
|
if (key_exists('fields', $action) && is_array($action['fields']) && count($action['fields'])) { |
172
|
|
|
$fields = $action['fields']; |
173
|
|
|
} else { |
174
|
|
|
$fields = []; |
175
|
|
|
|
176
|
|
|
// Get fields names from the metadata if no configuration is defined |
177
|
|
|
foreach ($metadata->getFieldNames() as $fieldName) { |
178
|
|
|
$fields[$fieldName] = null; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
$actionField = $this->getActionField($metadata->getFieldNames()); |
182
|
|
|
|
183
|
|
|
foreach ($fields as $fieldName => $fieldConfiguration) { |
184
|
|
|
$fieldType = $metadata->getTypeOfField($fieldName); |
185
|
|
|
|
186
|
|
|
if ( |
187
|
|
|
'list' === $actionName && |
188
|
|
|
$fieldName === $actionField && |
189
|
|
|
key_exists('edit', $configuration['actions']) |
190
|
|
|
) { |
191
|
|
|
$fieldConfiguration = [ |
192
|
|
|
'type' => 'action', |
193
|
|
|
'options' => [ |
194
|
|
|
'admin' => $adminName, |
195
|
|
|
'action' => 'edit', |
196
|
|
|
'parameters' => [ |
197
|
|
|
'id' => null, |
198
|
|
|
], |
199
|
|
|
] |
200
|
|
|
]; |
201
|
|
|
|
202
|
|
|
} else if ( |
203
|
|
|
'_delete' === $fieldName && |
204
|
|
|
!$metadata->hasField('_delete') && |
205
|
|
|
null === $fieldConfiguration && |
206
|
|
|
key_exists('delete', $configuration['actions']) |
207
|
|
|
) { |
208
|
|
|
// If a "delete" field is declared, and if it is not configured in the metadata, and if no |
209
|
|
|
// configuration is declared for this field, and if the "delete" action is allowed, we add a default |
210
|
|
|
// "button" configuration |
211
|
|
|
$fieldConfiguration = [ |
212
|
|
|
'type' => 'link', |
213
|
|
|
'options' => [ |
214
|
|
|
'admin' => $adminName, |
215
|
|
|
'action' => 'delete', |
216
|
|
|
'parameters' => [ |
217
|
|
|
'id' => null, |
218
|
|
|
], |
219
|
|
|
'text' => 'Delete', |
220
|
|
|
'class' => 'btn btn-sm btn-danger', |
221
|
|
|
'icon' => 'remove', |
222
|
|
|
], |
223
|
|
|
]; |
224
|
|
|
|
225
|
|
|
} else if (key_exists($fieldType, $fieldsMapping)) { |
226
|
|
|
$fieldConfiguration = $fieldsMapping[$metadata->getTypeOfField($fieldName)]; |
227
|
|
|
} |
228
|
|
|
$configuration['actions'][$actionName]['fields'][$fieldName] = $fieldConfiguration; |
229
|
|
|
} |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
private function addDefaultStrategy(array &$configuration) |
234
|
|
|
{ |
235
|
|
|
$mapping = [ |
236
|
|
|
'list' => LAGAdminBundle::LOAD_STRATEGY_MULTIPLE, |
237
|
|
|
'create' => LAGAdminBundle::LOAD_STRATEGY_NONE, |
238
|
|
|
'delete' => LAGAdminBundle::LOAD_STRATEGY_UNIQUE, |
239
|
|
|
'edit' => LAGAdminBundle::LOAD_STRATEGY_UNIQUE, |
240
|
|
|
]; |
241
|
|
|
|
242
|
|
|
foreach ($configuration['actions'] as $name => $action) { |
243
|
|
|
if (null === $action) { |
244
|
|
|
continue; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
if (key_exists('load_strategy', $action)) { |
248
|
|
|
continue; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
if (!key_exists($name, $mapping)) { |
252
|
|
|
continue; |
253
|
|
|
} |
254
|
|
|
$configuration['actions'][$name]['load_strategy'] = $mapping[$name]; |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
private function addDefaultRouteParameters(array &$configuration) |
259
|
|
|
{ |
260
|
|
|
$mapping = [ |
261
|
|
|
'edit' => [ |
262
|
|
|
'id' => '\d+', |
263
|
|
|
], |
264
|
|
|
'delete' => [ |
265
|
|
|
'id' => '\d+', |
266
|
|
|
], |
267
|
|
|
]; |
268
|
|
|
|
269
|
|
View Code Duplication |
foreach ($configuration['actions'] as $name => $actionConfiguration) { |
|
|
|
|
270
|
|
|
if (key_exists($name, $mapping) && !key_exists('route_requirements', $actionConfiguration)) { |
271
|
|
|
$configuration['actions'][$name]['route_requirements'] = [ |
272
|
|
|
'id' => '\d+', |
273
|
|
|
]; |
274
|
|
|
} |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
private function addDefaultFormUse(array &$configuration) |
279
|
|
|
{ |
280
|
|
|
$mapping = [ |
281
|
|
|
'edit', |
282
|
|
|
'create', |
283
|
|
|
'delete', |
284
|
|
|
]; |
285
|
|
|
|
286
|
|
|
foreach ($configuration['actions'] as $name => $action) { |
287
|
|
|
if (!in_array($name, $mapping) && !isset($action['use_form'])) { |
288
|
|
|
continue; |
289
|
|
|
} |
290
|
|
|
$configuration['actions'][$name]['use_form'] = true; |
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Add the default left menu configuration. One item for each Admin. |
296
|
|
|
* |
297
|
|
|
* @param array $configuration |
298
|
|
|
*/ |
299
|
|
|
private function addDefaultLeftMenu(array &$configuration) |
300
|
|
|
{ |
301
|
|
|
if (!$this->applicationConfiguration->getParameter('enable_menus')) { |
302
|
|
|
return; |
303
|
|
|
} |
304
|
|
|
$menus = $this->configurationFactory->createResourceMenuConfiguration(); |
305
|
|
|
|
306
|
|
|
// Add the resources menu for each action of the admin |
307
|
|
View Code Duplication |
foreach ($configuration['actions'] as $name => $action) { |
|
|
|
|
308
|
|
|
if (key_exists('menus', $action) && key_exists('left', $action)) { |
309
|
|
|
continue; |
310
|
|
|
} |
311
|
|
|
|
312
|
|
|
$configuration['actions'][$name]['menus']['left'] = $menus; |
313
|
|
|
} |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Add the default right menu. |
318
|
|
|
* |
319
|
|
|
* @param array $configuration |
320
|
|
|
*/ |
321
|
|
|
private function addDefaultRightMenu(array &$configuration) |
322
|
|
|
{ |
323
|
|
|
if (!$this->applicationConfiguration->getParameter('enable_menus')) { |
324
|
|
|
return; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
if (!key_exists('list', $configuration['actions'])) { |
328
|
|
|
return; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
if ( |
332
|
|
|
key_exists('menus', $configuration['actions']['list']) && |
333
|
|
|
is_array($configuration['actions']['list']['menus']) && |
334
|
|
|
key_exists('right', $configuration['actions']['list']['menus']) |
335
|
|
|
) { |
336
|
|
|
return; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
$configuration['actions']['list']['menus']['right'] = [ |
340
|
|
|
]; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* Return the default action field if found. |
345
|
|
|
* |
346
|
|
|
* @param array $fields |
347
|
|
|
* |
348
|
|
|
* @return string|null |
349
|
|
|
*/ |
350
|
|
|
private function getActionField(array $fields) |
351
|
|
|
{ |
352
|
|
|
$mapping = [ |
353
|
|
|
'title', |
354
|
|
|
'name', |
355
|
|
|
'id', |
356
|
|
|
]; |
357
|
|
|
|
358
|
|
|
foreach ($mapping as $name) { |
359
|
|
|
if (in_array($name, $fields)) { |
360
|
|
|
return $name; |
361
|
|
|
} |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
return null; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Add default filters for the list actions, guessed using the entity metadata. |
369
|
|
|
* |
370
|
|
|
* @param array $configuration |
371
|
|
|
*/ |
372
|
|
|
private function addDefaultFilters(array &$configuration) |
373
|
|
|
{ |
374
|
|
|
// Add the filters only for the "list" action |
375
|
|
|
if (!key_exists('list', $configuration['actions'])) { |
376
|
|
|
return; |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
// If some filters are already configured, we do not add the default filters |
380
|
|
|
if (key_exists('filter', $configuration['actions']['list'])) { |
381
|
|
|
return; |
382
|
|
|
} |
383
|
|
|
$metadata = $this->findMetadata($configuration['entity']); |
384
|
|
|
|
385
|
|
|
if (null === $metadata) { |
386
|
|
|
return; |
387
|
|
|
} |
388
|
|
|
$filters = []; |
389
|
|
|
|
390
|
|
|
foreach ($metadata->getFieldNames() as $fieldName) { |
391
|
|
|
$type = $metadata->getTypeOfField($fieldName); |
392
|
|
|
$operator = $this->getOperatorFromFieldType($type); |
393
|
|
|
|
394
|
|
|
$filters[$fieldName] = [ |
395
|
|
|
'type' => $type, |
396
|
|
|
'options' => [], |
397
|
|
|
'operator' => $operator, |
398
|
|
|
]; |
399
|
|
|
} |
400
|
|
|
$configuration['actions']['list']['filters'] = $filters; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* Return the Doctrine metadata of the given class. |
405
|
|
|
* |
406
|
|
|
* @param $class |
407
|
|
|
* |
408
|
|
|
* @return \Doctrine\Common\Persistence\Mapping\ClassMetadata|null |
409
|
|
|
*/ |
410
|
|
|
private function findMetadata($class) |
411
|
|
|
{ |
412
|
|
|
$metadata = null; |
413
|
|
|
|
414
|
|
|
try { |
415
|
|
|
// We could not use the hasMetadataFor() method as it is not working if the entity is not loaded. But |
416
|
|
|
// the getMetadataFor() method could throw an exception if the class is not found |
417
|
|
|
$metadata = $this->entityManager->getMetadataFactory()->getMetadataFor($class); |
418
|
|
|
} catch (Exception $exception) {} |
|
|
|
|
419
|
|
|
|
420
|
|
|
return $metadata; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
private function getOperatorFromFieldType($type) |
424
|
|
|
{ |
425
|
|
|
$mapping = [ |
426
|
|
|
'string' => 'like', |
427
|
|
|
'text' => 'like', |
428
|
|
|
]; |
429
|
|
|
|
430
|
|
|
if (key_exists($type, $mapping)) { |
431
|
|
|
return $mapping[$type]; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
return '='; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* @return bool |
439
|
|
|
*/ |
440
|
|
|
private function isExtraConfigurationEnabled(): bool |
441
|
|
|
{ |
442
|
|
|
return $this->applicationConfiguration->getParameter('enable_extra_configuration'); |
443
|
|
|
} |
444
|
|
|
} |
445
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.