Completed
Pull Request — 5.6 (#2830)
by Jeroen
14:14
created

AdminListBundle/Controller/AdminListController.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\AdminListBundle\Controller;
4
5
use Doctrine\ORM\EntityManager;
6
use Kunstmaan\AdminBundle\Entity\EntityInterface;
7
use Kunstmaan\AdminBundle\Event\AdaptSimpleFormEvent;
8
use Kunstmaan\AdminBundle\Event\Events;
9
use Kunstmaan\AdminBundle\FlashMessages\FlashTypes;
10
use Kunstmaan\AdminListBundle\AdminList\AdminList;
11
use Kunstmaan\AdminListBundle\AdminList\Configurator\AbstractAdminListConfigurator;
12
use Kunstmaan\AdminListBundle\AdminList\ItemAction\SimpleItemAction;
13
use Kunstmaan\AdminListBundle\AdminList\SortableInterface;
14
use Kunstmaan\AdminListBundle\Entity\LockableEntityInterface;
15
use Kunstmaan\AdminListBundle\Event\AdminListEvent;
16
use Kunstmaan\AdminListBundle\Event\AdminListEvents;
17
use Kunstmaan\AdminListBundle\Service\EntityVersionLockService;
18
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
19
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
20
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
21
use Symfony\Component\HttpFoundation\RedirectResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
25
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
26
use Symfony\Component\PropertyAccess\PropertyAccess;
27
28
/**
29
 * AdminListController
30
 */
31
abstract class AdminListController extends Controller
32
{
33
    /**
34
     * You can override this method to return the correct entity manager when using multiple databases ...
35
     *
36
     * @return \Doctrine\Common\Persistence\ObjectManager|object
37
     */
38
    protected function getEntityManager()
39
    {
40
        return $this->getDoctrine()->getManager();
41
    }
42
43
    /**
44
     * Shows the list of entities
45
     *
46
     * @param Request|null $request
0 ignored issues
show
Consider making the type for parameter $request a bit more specific; maybe use Request.
Loading history...
47
     *
48
     * @return Response
49
     */
50
    protected function doIndexAction(AbstractAdminListConfigurator $configurator, Request $request)
51
    {
52
        /* @var AdminList $adminList */
53
        $adminList = $this->container->get('kunstmaan_adminlist.factory')->createList($configurator);
54
        $adminList->bindRequest($request);
55
56
        $this->buildSortableFieldActions($configurator);
57
58
        return new Response(
59
            $this->renderView(
60
                $configurator->getListTemplate(),
61
                ['adminlist' => $adminList, 'adminlistconfigurator' => $configurator, 'addparams' => []]
62
            )
63
        );
64
    }
65
66
    /**
67
     * Export a list of Entities
68
     *
69
     * @param AbstractAdminListConfigurator $configurator The adminlist configurator
70
     * @param string                        $_format      The format to export to
71
     *
72
     * @throws AccessDeniedHttpException
73
     *
74
     * @return Response
75
     */
76
    protected function doExportAction(AbstractAdminListConfigurator $configurator, $_format, Request $request = null)
77
    {
78
        if (!$configurator->canExport()) {
79
            throw $this->createAccessDeniedException('You do not have sufficient rights to access this page.');
80
        }
81
82
        /* @var AdminList $adminList */
83
        $adminList = $this->container->get('kunstmaan_adminlist.factory')->createExportList($configurator);
84
        $adminList->bindRequest($request);
85
86
        return $this->container->get('kunstmaan_adminlist.service.export')->getDownloadableResponse($adminList, $_format);
87
    }
88
89
    /**
90
     * Creates and processes the form to add a new Entity
91
     *
92
     * @param AbstractAdminListConfigurator $configurator The adminlist configurator
93
     * @param string                        $type         The type to add
94
     * @param Request|null                  $request
95
     *
96
     * @throws AccessDeniedHttpException
97
     *
98
     * @return Response
99
     */
100
    protected function doAddAction(AbstractAdminListConfigurator $configurator, $type = null, Request $request)
101
    {
102
        if (!$configurator->canAdd()) {
103
            throw $this->createAccessDeniedException('You do not have sufficient rights to access this page.');
104
        }
105
106
        /* @var EntityManager $em */
107
        $em = $this->getEntityManager();
108
        $entityName = isset($type) ? $type : $configurator->getRepositoryName();
109
110
        $classMetaData = $em->getClassMetadata($entityName);
111
        // Creates a new instance of the mapped class, without invoking the constructor.
112
        $classname = $classMetaData->getName();
113
        $helper = new $classname();
114
        $helper = $configurator->decorateNewEntity($helper);
115
116
        $formType = $configurator->getAdminType($helper);
117
118
        $event = new AdaptSimpleFormEvent($request, $formType, $helper, $configurator->getAdminTypeOptions());
119
        $event = $this->container->get('event_dispatcher')->dispatch(Events::ADAPT_SIMPLE_FORM, $event);
120
        $tabPane = $event->getTabPane();
121
122
        $form = $this->createForm($formType, $helper, $event->getOptions());
123
124 View Code Duplication
        if ($request->isMethod('POST')) {
125
            if ($tabPane) {
126
                $tabPane->bindRequest($request);
127
                $form = $tabPane->getForm();
128
            } else {
129
                $form->handleRequest($request);
130
            }
131
132
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
133
            if ($form->isSubmitted() && $form->isValid() && !$request->isXmlHttpRequest()) {
134
                $adminListEvent = new AdminListEvent($helper, $request, $form);
135
                $this->container->get('event_dispatcher')->dispatch(
136
                    AdminListEvents::PRE_ADD,
137
                    $adminListEvent
138
                );
139
140
                // Check if Response is given
141
                if ($adminListEvent->getResponse() instanceof Response) {
142
                    return $adminListEvent->getResponse();
143
                }
144
145
                // Set sort weight
146
                $helper = $this->setSortWeightOnNewItem($configurator, $helper);
147
148
                $em->persist($helper);
149
                $em->flush();
150
                $this->container->get('event_dispatcher')->dispatch(
151
                    AdminListEvents::POST_ADD,
152
                    $adminListEvent
153
                );
154
155
                // Check if Response is given
156
                if ($adminListEvent->getResponse() instanceof Response) {
157
                    return $adminListEvent->getResponse();
158
                }
159
160
                $indexUrl = $configurator->getIndexUrl();
161
162
                return new RedirectResponse(
163
                    $this->generateUrl($indexUrl['path'], isset($indexUrl['params']) ? $indexUrl['params'] : [])
164
                );
165
            }
166
        }
167
168
        $params = [
169
            'form' => $form->createView(),
170
            'adminlistconfigurator' => $configurator,
171
            'entityVersionLockCheck' => false,
172
            'entity' => $helper,
173
        ];
174
175
        if ($tabPane) {
176
            $params = array_merge($params, ['tabPane' => $tabPane]);
177
        }
178
179
        return new Response(
180
            $this->renderView($configurator->getAddTemplate(), $params)
181
        );
182
    }
183
184
    /**
185
     * Creates and processes the edit form for an Entity using its ID
186
     *
187
     * @param AbstractAdminListConfigurator $configurator The adminlist configurator
188
     * @param string                        $entityId     The id of the entity that will be edited
189
     * @param Request|null                  $request
190
     *
191
     * @throws NotFoundHttpException
192
     * @throws AccessDeniedHttpException
193
     *
194
     * @return Response
195
     */
196
    protected function doEditAction(AbstractAdminListConfigurator $configurator, $entityId, Request $request)
197
    {
198
        /* @var EntityManager $em */
199
        $em = $this->getEntityManager();
200
        $helper = $em->getRepository($configurator->getRepositoryName())->findOneById($entityId);
201
202
        if ($helper === null) {
203
            throw new NotFoundHttpException('Entity not found.');
204
        }
205
206
        if (!$configurator->canEdit($helper)) {
207
            throw $this->createAccessDeniedException('You do not have sufficient rights to access this page.');
208
        }
209
210
        // This entity is locked
211
        if (($helper instanceof LockableEntityInterface) && $this->isLockableEntityLocked($helper)) {
212
            $indexUrl = $configurator->getIndexUrl();
213
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
214
            if (!$request->isXmlHttpRequest()) {
215
                /** @var EntityVersionLockService $entityVersionLockService */
216
                $entityVersionLockService = $this->container->get('kunstmaan_entity.admin_entity.entity_version_lock_service');
217
218
                $user = $entityVersionLockService->getUsersWithEntityVersionLock($helper, $this->getUser());
219
                $message = $this->container->get('translator')->trans('kuma_admin_list.edit.flash.locked', ['%user%' => implode(', ', $user)]);
220
                $this->addFlash(
221
                    FlashTypes::WARNING,
222
                    $message
223
                );
224
225
                return new RedirectResponse(
226
                    $this->generateUrl(
227
                        $indexUrl['path'],
228
                        isset($indexUrl['params']) ? $indexUrl['params'] : []
229
                    )
230
                );
231
            }
232
        }
233
234
        $formType = $configurator->getAdminType($helper);
235
236
        $event = new AdaptSimpleFormEvent($request, $formType, $helper, $configurator->getAdminTypeOptions());
237
        $event = $this->container->get('event_dispatcher')->dispatch(Events::ADAPT_SIMPLE_FORM, $event);
238
        $tabPane = $event->getTabPane();
239
240
        $form = $this->createForm($formType, $helper, $event->getOptions());
241
242 View Code Duplication
        if ($request->isMethod('POST')) {
243
            if ($tabPane) {
244
                $tabPane->bindRequest($request);
245
                $form = $tabPane->getForm();
246
            } else {
247
                $form->handleRequest($request);
248
            }
249
250
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
251
            if ($form->isSubmitted() && $form->isValid() && !$request->isXmlHttpRequest()) {
252
                $adminListEvent = new AdminListEvent($helper, $request, $form);
253
                $this->container->get('event_dispatcher')->dispatch(
254
                    AdminListEvents::PRE_EDIT,
255
                    $adminListEvent
256
                );
257
258
                // Check if Response is given
259
                if ($adminListEvent->getResponse() instanceof Response) {
260
                    return $adminListEvent->getResponse();
261
                }
262
263
                $em->persist($helper);
264
                $em->flush();
265
                $this->container->get('event_dispatcher')->dispatch(
266
                    AdminListEvents::POST_EDIT,
267
                    $adminListEvent
268
                );
269
270
                // Check if Response is given
271
                if ($adminListEvent->getResponse() instanceof Response) {
272
                    return $adminListEvent->getResponse();
273
                }
274
275
                $indexUrl = $configurator->getIndexUrl();
276
277
                // Don't redirect to listing when coming from ajax request, needed for url chooser.
278
                if (!$request->isXmlHttpRequest()) {
279
                    return new RedirectResponse(
280
                        $this->generateUrl(
281
                            $indexUrl['path'],
282
                            isset($indexUrl['params']) ? $indexUrl['params'] : []
283
                        )
284
                    );
285
                }
286
            }
287
        }
288
289
        $configurator->buildItemActions();
290
291
        $params = [
292
            'form' => $form->createView(),
293
            'entity' => $helper, 'adminlistconfigurator' => $configurator,
294
            'entityVersionLockInterval' => $this->container->getParameter('kunstmaan_entity.lock_check_interval'),
295
            'entityVersionLockCheck' => $this->container->getParameter('kunstmaan_entity.lock_enabled') && $helper instanceof LockableEntityInterface,
296
        ];
297
298
        if ($tabPane) {
299
            $params = array_merge($params, ['tabPane' => $tabPane]);
300
        }
301
302
        return new Response(
303
            $this->renderView(
304
                $configurator->getEditTemplate(),
305
                $params
306
            )
307
        );
308
    }
309
310
    protected function doViewAction(AbstractAdminListConfigurator $configurator, $entityId, Request $request)
311
    {
312
        /* @var EntityManager $em */
313
        $em = $this->getEntityManager();
314
        $helper = $em->getRepository($configurator->getRepositoryName())->findOneById($entityId);
315
        if ($helper === null) {
316
            throw new NotFoundHttpException('Entity not found.');
317
        }
318
319
        if (!$configurator->canView($helper)) {
320
            throw $this->createAccessDeniedException('You do not have sufficient rights to access this page.');
321
        }
322
323
        $MetaData = $em->getClassMetadata($configurator->getRepositoryName());
324
        $fields = [];
325
        $accessor = PropertyAccess::createPropertyAccessor();
326
        foreach ($MetaData->fieldNames as $value) {
327
            $fields[$value] = $accessor->getValue($helper, $value);
328
        }
329
330
        return new Response(
331
            $this->renderView(
332
                $configurator->getViewTemplate(),
333
                ['entity' => $helper, 'adminlistconfigurator' => $configurator, 'fields' => $fields]
334
            )
335
        );
336
    }
337
338
    /**
339
     * Delete the Entity using its ID
340
     *
341
     * @param AbstractAdminListConfigurator $configurator The adminlist configurator
342
     * @param int                           $entityId     The id to delete
343
     * @param Request|null                  $request
344
     *
345
     * @throws NotFoundHttpException
346
     * @throws AccessDeniedHttpException
347
     *
348
     * @return Response
349
     */
350
    protected function doDeleteAction(AbstractAdminListConfigurator $configurator, $entityId, Request $request)
351
    {
352
        /* @var $em EntityManager */
353
        $em = $this->getEntityManager();
354
        $helper = $em->getRepository($configurator->getRepositoryName())->findOneById($entityId);
355
        if ($helper === null) {
356
            throw new NotFoundHttpException('Entity not found.');
357
        }
358
        if (!$configurator->canDelete($helper)) {
359
            throw $this->createAccessDeniedException('You do not have sufficient rights to access this page.');
360
        }
361
362
        $indexUrl = $configurator->getIndexUrl();
363
        if ($request->isMethod('POST')) {
364
            $adminListEvent = new AdminListEvent($helper, $request);
365
            $this->container->get('event_dispatcher')->dispatch(
366
                AdminListEvents::PRE_DELETE,
367
                $adminListEvent
368
            );
369
370
            // Check if Response is given
371
            if ($adminListEvent->getResponse() instanceof Response) {
372
                return $adminListEvent->getResponse();
373
            }
374
375
            $em->remove($helper);
376
            $em->flush();
377
            $this->container->get('event_dispatcher')->dispatch(
378
                AdminListEvents::POST_DELETE,
379
                $adminListEvent
380
            );
381
382
            // Check if Response is given
383
            if ($adminListEvent->getResponse() instanceof Response) {
384
                return $adminListEvent->getResponse();
385
            }
386
        }
387
388
        return new RedirectResponse(
389
            $this->generateUrl($indexUrl['path'], isset($indexUrl['params']) ? $indexUrl['params'] : [])
390
        );
391
    }
392
393
    /**
394
     * Move an item up in the list.
395
     *
396
     * @return RedirectResponse
397
     */
398 View Code Duplication
    protected function doMoveUpAction(AbstractAdminListConfigurator $configurator, $entityId, Request $request)
399
    {
400
        $em = $this->getEntityManager();
401
        $sortableField = $configurator->getSortableField();
402
403
        $repositoryName = $this->getAdminListRepositoryName($configurator);
404
405
        $repo = $em->getRepository($repositoryName);
406
        $item = $repo->find($entityId);
407
408
        $setter = 'set' . ucfirst($sortableField);
409
        $getter = 'get' . ucfirst($sortableField);
410
411
        $nextItem = $repo->createQueryBuilder('i')
412
            ->where('i.' . $sortableField . ' < :weight')
413
            ->setParameter('weight', $item->$getter())
414
            ->orderBy('i.' . $sortableField, 'DESC')
415
            ->setMaxResults(1)
416
            ->getQuery()
417
            ->getOneOrNullResult();
418
        if ($nextItem) {
419
            $nextItem->$setter($item->$getter());
420
            $em->persist($nextItem);
421
            $item->$setter($item->$getter() - 1);
422
423
            $em->persist($item);
424
            $em->flush();
425
        }
426
427
        $indexUrl = $configurator->getIndexUrl();
428
429
        return new RedirectResponse(
430
            $this->generateUrl($indexUrl['path'], isset($indexUrl['params']) ? $indexUrl['params'] : [])
431
        );
432
    }
433
434 View Code Duplication
    protected function doMoveDownAction(AbstractAdminListConfigurator $configurator, $entityId, Request $request)
435
    {
436
        $em = $this->getEntityManager();
437
        $sortableField = $configurator->getSortableField();
438
439
        $repositoryName = $this->getAdminListRepositoryName($configurator);
440
441
        $repo = $em->getRepository($repositoryName);
442
        $item = $repo->find($entityId);
443
444
        $setter = 'set' . ucfirst($sortableField);
445
        $getter = 'get' . ucfirst($sortableField);
446
447
        $nextItem = $repo->createQueryBuilder('i')
448
            ->where('i.' . $sortableField . ' > :weight')
449
            ->setParameter('weight', $item->$getter())
450
            ->orderBy('i.' . $sortableField, 'ASC')
451
            ->setMaxResults(1)
452
            ->getQuery()
453
            ->getOneOrNullResult();
454
        if ($nextItem) {
455
            $nextItem->$setter($item->$getter());
456
            $em->persist($nextItem);
457
            $item->$setter($item->$getter() + 1);
458
459
            $em->persist($item);
460
            $em->flush();
461
        }
462
463
        $indexUrl = $configurator->getIndexUrl();
464
465
        return new RedirectResponse(
466
            $this->generateUrl($indexUrl['path'], isset($indexUrl['params']) ? $indexUrl['params'] : [])
467
        );
468
    }
469
470
    private function getMaxSortableField($repo, $sort)
471
    {
472
        $maxWeight = $repo->createQueryBuilder('i')
473
            ->select('max(i.' . $sort . ')')
474
            ->getQuery()
475
            ->getSingleScalarResult();
476
477
        return (int) $maxWeight;
478
    }
479
480
    /**
481
     * @return bool
482
     */
483
    protected function isLockableEntityLocked(LockableEntityInterface $entity)
484
    {
485
        /** @var EntityVersionLockService $entityVersionLockService */
486
        $entityVersionLockService = $this->container->get('kunstmaan_entity.admin_entity.entity_version_lock_service');
487
488
        return $entityVersionLockService->isEntityBelowThreshold($entity) && $entityVersionLockService->isEntityLocked(
489
                $this->getUser(),
490
                $entity
491
            );
492
    }
493
494
    /**
495
     * Sets the sort weight on a new item. Can be overridden if a non-default sorting implementation is being used.
496
     *
497
     * @param AbstractAdminListConfigurator $configurator The adminlist configurator
498
     * @param $item
499
     *
500
     * @return mixed
501
     */
502
    protected function setSortWeightOnNewItem(AbstractAdminListConfigurator $configurator, $item)
503
    {
504
        if ($configurator instanceof SortableInterface) {
505
            $repo = $this->getEntityManager()->getRepository($configurator->getRepositoryName());
506
            $sort = $configurator->getSortableField();
507
            $weight = $this->getMaxSortableField($repo, $sort);
508
            $setter = 'set' . ucfirst($sort);
509
            $item->$setter($weight + 1);
510
        }
511
512
        return $item;
513
    }
514
515
    protected function buildSortableFieldActions(AbstractAdminListConfigurator $configurator)
516
    {
517
        // Check if Sortable interface is implemented
518
        if ($configurator instanceof SortableInterface) {
519 View Code Duplication
            $route = function (EntityInterface $item) use ($configurator) {
520
                return [
521
                    'path' => $configurator->getPathByConvention() . '_move_up',
522
                    'params' => ['id' => $item->getId()],
523
                ];
524
            };
525
526
            $action = new SimpleItemAction($route, 'arrow-up', 'kuma_admin_list.action.move_up');
527
            $configurator->addItemAction($action);
528
529 View Code Duplication
            $route = function (EntityInterface $item) use ($configurator) {
530
                return [
531
                    'path' => $configurator->getPathByConvention() . '_move_down',
532
                    'params' => ['id' => $item->getId()],
533
                ];
534
            };
535
536
            $action = new SimpleItemAction($route, 'arrow-down', 'kuma_admin_list.action.move_down');
537
            $configurator->addItemAction($action);
538
        }
539
    }
540
541
    /**
542
     * @return string
543
     */
544
    protected function getAdminListRepositoryName(AbstractAdminListConfigurator $configurator)
545
    {
546
        $em = $this->getEntityManager();
547
        $className = $em->getClassMetadata($configurator->getRepositoryName())->getName();
548
549
        $implements = class_implements($className);
550
        if (isset($implements[HasNodeInterface::class])) {
551
            return NodeTranslation::class;
552
        }
553
554
        return $configurator->getRepositoryName();
555
    }
556
}
557