Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

NodeBundle/Controller/NodeAdminController.php (3 issues)

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\NodeBundle\Controller;
4
5
use DateTime;
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\ORM\EntityManager;
8
use InvalidArgumentException;
9
use Kunstmaan\AdminBundle\Entity\BaseUser;
10
use Kunstmaan\AdminBundle\Entity\EntityInterface;
11
use Kunstmaan\AdminBundle\FlashMessages\FlashTypes;
12
use Kunstmaan\AdminBundle\Helper\FormWidgets\FormWidget;
13
use Kunstmaan\AdminBundle\Helper\FormWidgets\Tabs\Tab;
14
use Kunstmaan\AdminBundle\Helper\FormWidgets\Tabs\TabPane;
15
use Kunstmaan\AdminBundle\Helper\Security\Acl\AclHelper;
16
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
17
use Kunstmaan\AdminBundle\Service\AclManager;
18
use Kunstmaan\AdminListBundle\AdminList\AdminList;
19
use Kunstmaan\NodeBundle\AdminList\NodeAdminListConfigurator;
20
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
21
use Kunstmaan\NodeBundle\Entity\Node;
22
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
23
use Kunstmaan\NodeBundle\Entity\NodeVersion;
24
use Kunstmaan\NodeBundle\Event\AdaptFormEvent;
25
use Kunstmaan\NodeBundle\Event\CopyPageTranslationNodeEvent;
26
use Kunstmaan\NodeBundle\Event\Events;
27
use Kunstmaan\NodeBundle\Event\NodeEvent;
28
use Kunstmaan\NodeBundle\Event\RecopyPageTranslationNodeEvent;
29
use Kunstmaan\NodeBundle\Event\RevertNodeAction;
30
use Kunstmaan\NodeBundle\Form\NodeMenuTabAdminType;
31
use Kunstmaan\NodeBundle\Form\NodeMenuTabTranslationAdminType;
32
use Kunstmaan\NodeBundle\Helper\NodeAdmin\NodeAdminPublisher;
33
use Kunstmaan\NodeBundle\Helper\NodeAdmin\NodeVersionLockHelper;
34
use Kunstmaan\NodeBundle\Helper\PageCloningHelper;
35
use Kunstmaan\NodeBundle\Repository\NodeVersionRepository;
36
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
37
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
38
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
39
use Symfony\Component\HttpFoundation\JsonResponse;
40
use Symfony\Component\HttpFoundation\RedirectResponse;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\Routing\Annotation\Route;
43
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
44
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
45
use Symfony\Component\Translation\TranslatorInterface;
46
47
/**
48
 * NodeAdminController
49
 */
50
class NodeAdminController extends Controller
51
{
52
    /**
53
     * @var EntityManager
54
     */
55
    protected $em;
56
57
    /**
58
     * @var string
59
     */
60
    protected $locale;
61
62
    /**
63
     * @var AuthorizationCheckerInterface
64
     */
65
    protected $authorizationChecker;
66
67
    /**
68
     * @var BaseUser
69
     */
70
    protected $user;
71
72
    /**
73
     * @var AclHelper
74
     */
75
    protected $aclHelper;
76
77
    /**
78
     * @var AclManager
79
     */
80
    protected $aclManager;
81
82
    /**
83
     * @var NodeAdminPublisher
84
     */
85
    protected $nodePublisher;
86
87
    /**
88
     * @var TranslatorInterface
89
     */
90
    protected $translator;
91
92
    /** @var PageCloningHelper */
93
    private $pageCloningHelper;
94
95
    /**
96
     * init
97
     *
98
     * @param Request $request
99
     */
100
    protected function init(Request $request)
101
    {
102
        $this->em = $this->getDoctrine()->getManager();
103
        $this->locale = $request->getLocale();
104
        $this->authorizationChecker = $this->container->get('security.authorization_checker');
105
        $this->user = $this->getUser();
106
        $this->aclHelper = $this->container->get('kunstmaan_admin.acl.helper');
107
        $this->aclManager = $this->container->get('kunstmaan_admin.acl.manager');
108
        $this->nodePublisher = $this->container->get('kunstmaan_node.admin_node.publisher');
109
        $this->translator = $this->container->get('translator');
110
        $this->pageCloningHelper = $this->container->get(PageCloningHelper::class);
111
    }
112
113
    /**
114
     * @Route("/", name="KunstmaanNodeBundle_nodes")
115
     * @Template("@KunstmaanNode/Admin/list.html.twig")
116
     *
117
     * @param Request $request
118
     *
119
     * @return array
120
     */
121
    public function indexAction(Request $request)
122
    {
123
        $this->init($request);
124
125
        $nodeAdminListConfigurator = new NodeAdminListConfigurator(
126
            $this->em,
127
            $this->aclHelper,
128
            $this->locale,
129
            PermissionMap::PERMISSION_VIEW,
130
            $this->authorizationChecker
131
        );
132
133
        $locale = $this->locale;
134
        $acl = $this->authorizationChecker;
135
        $itemRoute = function (EntityInterface $item) use ($locale, $acl) {
136
            if ($acl->isGranted(PermissionMap::PERMISSION_VIEW, $item->getNode())) {
137
                return array(
138
                    'path' => '_slug_preview',
139
                    'params' => ['_locale' => $locale, 'url' => $item->getUrl()],
140
                );
141
            }
142
        };
143
        $nodeAdminListConfigurator->addSimpleItemAction('action.preview', $itemRoute, 'eye');
144
        $nodeAdminListConfigurator->setDomainConfiguration($this->get('kunstmaan_admin.domain_configuration'));
145
        $nodeAdminListConfigurator->setShowAddHomepage($this->getParameter('kunstmaan_node.show_add_homepage') && $this->isGranted('ROLE_SUPER_ADMIN'));
146
147
        /** @var AdminList $adminlist */
148
        $adminlist = $this->get('kunstmaan_adminlist.factory')->createList($nodeAdminListConfigurator);
149
        $adminlist->bindRequest($request);
150
151
        return array(
152
            'adminlist' => $adminlist,
153
        );
154
    }
155
156
    /**
157
     * @Route(
158
     *      "/{id}/copyfromotherlanguage",
159
     *      requirements={"id" = "\d+"},
160
     *      name="KunstmaanNodeBundle_nodes_copyfromotherlanguage",
161
     *      methods={"GET"}
162
     * )
163
     *
164
     * @param Request $request
165
     * @param int     $id      The node id
166
     *
167
     * @return RedirectResponse
168
     *
169
     * @throws AccessDeniedException
170
     */
171
    public function copyFromOtherLanguageAction(Request $request, $id)
172
    {
173
        $this->init($request);
174
        /* @var Node $node */
175
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
176
177
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
178
179
        $originalLanguage = $request->get('originallanguage');
180
        $otherLanguageNodeTranslation = $node->getNodeTranslation($originalLanguage, true);
181
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
182
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
183
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
184
            ->deepCloneAndSave($otherLanguagePage);
185
186
        /* @var NodeTranslation $nodeTranslation */
187
        $nodeTranslation = $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')
188
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
189
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
190
191
        $this->get('event_dispatcher')->dispatch(
192
            Events::COPY_PAGE_TRANSLATION,
193
            new CopyPageTranslationNodeEvent(
194
                $node,
195
                $nodeTranslation,
196
                $nodeVersion,
197
                $myLanguagePage,
198
                $otherLanguageNodeTranslation,
199
                $otherLanguageNodeNodeVersion,
200
                $otherLanguagePage,
201
                $originalLanguage
202
            )
203
        );
204
205
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
206
    }
207
208
    /**
209
     * @Route(
210
     *      "/{id}/recopyfromotherlanguage",
211
     *      requirements={"id" = "\d+"},
212
     *      name="KunstmaanNodeBundle_nodes_recopyfromotherlanguage",
213
     *      methods={"POST"}
214
     * )
215
     *
216
     * @param Request $request
217
     * @param int     $id      The node id
218
     *
219
     * @return RedirectResponse
220
     *
221
     * @throws AccessDeniedException
222
     */
223
    public function recopyFromOtherLanguageAction(Request $request, $id)
224
    {
225
        $this->init($request);
226
        /* @var Node $node */
227
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
228
229
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
230
231
        $otherLanguageNodeTranslation = $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')->find($request->get('source'));
232
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
233
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
234
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
235
            ->deepCloneAndSave($otherLanguagePage);
236
237
        /* @var NodeTranslation $nodeTranslation */
238
        $nodeTranslation = $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')
239
            ->addDraftNodeVersionFor($myLanguagePage, $this->locale, $node, $this->user);
240
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
241
242
        $this->get('event_dispatcher')->dispatch(
243
            Events::RECOPY_PAGE_TRANSLATION,
244
            new RecopyPageTranslationNodeEvent(
245
                $node,
246
                $nodeTranslation,
247
                $nodeVersion,
248
                $myLanguagePage,
249
                $otherLanguageNodeTranslation,
250
                $otherLanguageNodeNodeVersion,
251
                $otherLanguagePage,
252
                $otherLanguageNodeTranslation->getLang()
253
            )
254
        );
255
256
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id, 'subaction' => NodeVersion::DRAFT_VERSION)));
257
    }
258
259
    /**
260
     * @Route(
261
     *      "/{id}/createemptypage",
262
     *      requirements={"id" = "\d+"},
263
     *      name="KunstmaanNodeBundle_nodes_createemptypage",
264
     *      methods={"GET"}
265
     * )
266
     *
267
     * @param Request $request
268
     * @param int     $id
269
     *
270
     * @return RedirectResponse
271
     *
272
     * @throws AccessDeniedException
273
     */
274
    public function createEmptyPageAction(Request $request, $id)
275
    {
276
        $this->init($request);
277
        /* @var Node $node */
278
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
279
280
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
281
282
        $entityName = $node->getRefEntityName();
283
        /* @var HasNodeInterface $myLanguagePage */
284
        $myLanguagePage = new $entityName();
285
        $myLanguagePage->setTitle('New page');
286
287
        $this->em->persist($myLanguagePage);
288
        $this->em->flush();
289
        /* @var NodeTranslation $nodeTranslation */
290
        $nodeTranslation = $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')
291
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
292
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
293
294
        $this->get('event_dispatcher')->dispatch(
295
            Events::ADD_EMPTY_PAGE_TRANSLATION,
296
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $myLanguagePage)
297
        );
298
299
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
300
    }
301
302
    /**
303
     * @Route("/{id}/publish", requirements={"id" =
304
     *                         "\d+"},
305
     *                         name="KunstmaanNodeBundle_nodes_publish", methods={"GET", "POST"})
306
     *
307
     * @param Request $request
308
     * @param int     $id
309
     *
310
     * @return RedirectResponse
311
     *
312
     * @throws AccessDeniedException
313
     */
314 View Code Duplication
    public function publishAction(Request $request, $id)
315
    {
316
        $this->init($request);
317
        /* @var Node $node */
318
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
319
320
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
321
        $request = $this->get('request_stack')->getCurrentRequest();
322
        $this->nodePublisher->chooseHowToPublish($request, $nodeTranslation, $this->translator);
323
324
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
325
    }
326
327
    /**
328
     * @Route(
329
     *      "/{id}/unpublish",
330
     *      requirements={"id" = "\d+"},
331
     *      name="KunstmaanNodeBundle_nodes_unpublish",
332
     *      methods={"GET", "POST"}
333
     * )
334
     *
335
     * @param Request $request
336
     * @param int     $id
337
     *
338
     * @return RedirectResponse
339
     *
340
     * @throws AccessDeniedException
341
     */
342 View Code Duplication
    public function unPublishAction(Request $request, $id)
343
    {
344
        $this->init($request);
345
        /* @var Node $node */
346
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
347
348
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
349
        $request = $this->get('request_stack')->getCurrentRequest();
350
        $this->nodePublisher->chooseHowToUnpublish($request, $nodeTranslation, $this->translator);
351
352
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
353
    }
354
355
    /**
356
     * @Route(
357
     *      "/{id}/unschedulepublish",
358
     *      requirements={"id" = "\d+"},
359
     *      name="KunstmaanNodeBundle_nodes_unschedule_publish",
360
     *      methods={"GET", "POST"}
361
     * )
362
     *
363
     * @param Request $request
364
     * @param int     $id
365
     *
366
     * @return RedirectResponse
367
     *
368
     * @throws AccessDeniedException
369
     */
370 View Code Duplication
    public function unSchedulePublishAction(Request $request, $id)
371
    {
372
        $this->init($request);
373
374
        /* @var Node $node */
375
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
376
377
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
378
        $this->nodePublisher->unSchedulePublish($nodeTranslation);
379
380
        $this->addFlash(
381
            FlashTypes::SUCCESS,
382
            $this->get('translator')->trans('kuma_node.admin.unschedule.flash.success')
383
        );
384
385
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
386
    }
387
388
    /**
389
     * @Route(
390
     *      "/{id}/delete",
391
     *      requirements={"id" = "\d+"},
392
     *      name="KunstmaanNodeBundle_nodes_delete",
393
     *      methods={"POST"}
394
     * )
395
     *
396
     * @param Request $request
397
     * @param int     $id
398
     *
399
     * @return RedirectResponse
400
     *
401
     * @throws AccessDeniedException
402
     */
403
    public function deleteAction(Request $request, $id)
404
    {
405
        $this->init($request);
406
        /* @var Node $node */
407
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
408
409
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_DELETE, $node);
410
411
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
412
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
413
        $page = $nodeVersion->getRef($this->em);
414
415
        $this->get('event_dispatcher')->dispatch(
416
            Events::PRE_DELETE,
417
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
418
        );
419
420
        $node->setDeleted(true);
421
        $this->em->persist($node);
422
423
        $children = $node->getChildren();
424
        $this->deleteNodeChildren($this->em, $this->user, $this->locale, $children);
425
        $this->em->flush();
426
427
        $event = new NodeEvent($node, $nodeTranslation, $nodeVersion, $page);
428
        $this->get('event_dispatcher')->dispatch(Events::POST_DELETE, $event);
429
        if (null === $response = $event->getResponse()) {
430
            $nodeParent = $node->getParent();
431
            // Check if we have a parent. Otherwise redirect to pages overview.
432
            if ($nodeParent) {
433
                $url = $this->get('router')->generate(
434
                    'KunstmaanNodeBundle_nodes_edit',
435
                    array('id' => $nodeParent->getId())
436
                );
437
            } else {
438
                $url = $this->get('router')->generate(
439
                    'KunstmaanNodeBundle_nodes'
440
                );
441
            }
442
            $response = new RedirectResponse($url);
443
        }
444
445
        $this->addFlash(
446
            FlashTypes::SUCCESS,
447
            $this->get('translator')->trans('kuma_node.admin.delete.flash.success')
448
        );
449
450
        return $response;
451
    }
452
453
    /**
454
     * @Route(
455
     *      "/{id}/duplicate",
456
     *      requirements={"id" = "\d+"},
457
     *      name="KunstmaanNodeBundle_nodes_duplicate",
458
     *      methods={"POST"}
459
     * )
460
     *
461
     * @param Request $request
462
     * @param int     $id
463
     *
464
     * @return RedirectResponse
465
     *
466
     * @throws AccessDeniedException
467
     */
468
    public function duplicateAction(Request $request, $id)
469
    {
470
        $this->init($request);
471
        /* @var Node $parentNode */
472
        $originalNode = $this->em->getRepository('KunstmaanNodeBundle:Node')
473
            ->find($id);
474
475
        // Check with Acl
476
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $originalNode);
477
478
        $request = $this->get('request_stack')->getCurrentRequest();
479
480
        $originalNodeTranslations = $originalNode->getNodeTranslation($this->locale, true);
481
        $originalRef = $originalNodeTranslations->getPublicNodeVersion()->getRef($this->em);
482
        $newPage = $this->get('kunstmaan_admin.clone.helper')
483
            ->deepCloneAndSave($originalRef);
484
485
        //set the title
486
        $title = $request->get('title');
487
        if (\is_string($title) && !empty($title)) {
488
            $newPage->setTitle($title);
489
        } else {
490
            $newPage->setTitle('New page');
491
        }
492
493
        //set the parent
494
        $parentNodeTranslation = $originalNode->getParent()->getNodeTranslation($this->locale, true);
495
        $parent = $parentNodeTranslation->getPublicNodeVersion()->getRef($this->em);
496
        $newPage->setParent($parent);
497
        $this->em->persist($newPage);
498
        $this->em->flush();
499
500
        /* @var Node $nodeNewPage */
501
        $nodeNewPage = $this->em->getRepository('KunstmaanNodeBundle:Node')->createNodeFor(
502
            $newPage,
503
            $this->locale,
504
            $this->user
505
        );
506
507
        $nodeTranslation = $nodeNewPage->getNodeTranslation($this->locale, true);
508
        if ($newPage->isStructureNode()) {
509
            $nodeTranslation->setSlug('');
510
            $this->em->persist($nodeTranslation);
511
        }
512
        $this->em->flush();
513
514
        $this->aclManager->updateNodeAcl($originalNode, $nodeNewPage);
515
516
        $this->addFlash(
517
            FlashTypes::SUCCESS,
518
            $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success')
519
        );
520
521
        return $this->redirect(
522
            $this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $nodeNewPage->getId()))
523
        );
524
    }
525
526
    /**
527
     * @Route(
528
     *      "/{id}/duplicate-with-children",
529
     *      requirements={"id" = "\d+"},
530
     *      name="KunstmaanNodeBundle_nodes_duplicate_with_children",
531
     *      methods={"POST"}
532
     * )
533
     *
534
     * @throws AccessDeniedException
535
     */
536
    public function duplicateWithChildrenAction(Request $request, $id)
537
    {
538
        if (!$this->getParameter('kunstmaan_node.show_duplicate_with_children')) {
539
            return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $id]);
540
        }
541
542
        $this->init($request);
543
        $title = $request->get('title', null);
544
545
        $nodeNewPage = $this->pageCloningHelper->duplicateWithChildren($id, $this->locale, $this->user, $title);
546
547
        $this->addFlash(FlashTypes::SUCCESS, $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success'));
548
549
        return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $nodeNewPage->getId()]);
550
    }
551
552
    /**
553
     * @Route(
554
     *      "/{id}/revert",
555
     *      requirements={"id" = "\d+"},
556
     *      defaults={"subaction" = "public"},
557
     *      name="KunstmaanNodeBundle_nodes_revert",
558
     *      methods={"GET"}
559
     * )
560
     *
561
     * @param Request $request
562
     * @param int     $id      The node id
563
     *
564
     * @return RedirectResponse
565
     *
566
     * @throws AccessDeniedException
567
     * @throws InvalidArgumentException
568
     */
569
    public function revertAction(Request $request, $id)
570
    {
571
        $this->init($request);
572
        /* @var Node $node */
573
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
574
575
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
576
577
        $version = $request->get('version');
578
579
        if (empty($version) || !is_numeric($version)) {
580
            throw new InvalidArgumentException('No version was specified');
581
        }
582
583
        /* @var NodeVersionRepository $nodeVersionRepo */
584
        $nodeVersionRepo = $this->em->getRepository('KunstmaanNodeBundle:NodeVersion');
585
        /* @var NodeVersion $nodeVersion */
586
        $nodeVersion = $nodeVersionRepo->find($version);
587
588
        if (\is_null($nodeVersion)) {
589
            throw new InvalidArgumentException('Version does not exist');
590
        }
591
592
        /* @var NodeTranslation $nodeTranslation */
593
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
594
        $page = $nodeVersion->getRef($this->em);
595
        /* @var HasNodeInterface $clonedPage */
596
        $clonedPage = $this->get('kunstmaan_admin.clone.helper')
597
            ->deepCloneAndSave($page);
598
        $newNodeVersion = $nodeVersionRepo->createNodeVersionFor(
599
            $clonedPage,
600
            $nodeTranslation,
601
            $this->user,
602
            $nodeVersion,
603
            'draft'
604
        );
605
606
        $nodeTranslation->setTitle($clonedPage->getTitle());
607
        $this->em->persist($nodeTranslation);
608
        $this->em->flush();
609
610
        $this->get('event_dispatcher')->dispatch(
611
            Events::REVERT,
612
            new RevertNodeAction(
613
                $node,
614
                $nodeTranslation,
615
                $newNodeVersion,
616
                $clonedPage,
617
                $nodeVersion,
618
                $page
619
            )
620
        );
621
622
        $this->addFlash(
623
            FlashTypes::SUCCESS,
624
            $this->get('translator')->trans('kuma_node.admin.revert.flash.success')
625
        );
626
627
        return $this->redirect(
628
            $this->generateUrl(
629
                'KunstmaanNodeBundle_nodes_edit',
630
                array(
631
                    'id' => $id,
632
                    'subaction' => 'draft',
633
                )
634
            )
635
        );
636
    }
637
638
    /**
639
     * @Route(
640
     *      "/{id}/add",
641
     *      requirements={"id" = "\d+"},
642
     *      name="KunstmaanNodeBundle_nodes_add",
643
     *      methods={"POST"}
644
     * )
645
     *
646
     * @param Request $request
647
     * @param int     $id
648
     *
649
     * @return RedirectResponse
650
     *
651
     * @throws AccessDeniedException
652
     * @throws InvalidArgumentException
653
     */
654
    public function addAction(Request $request, $id)
655
    {
656
        $this->init($request);
657
        /* @var Node $parentNode */
658
        $parentNode = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
659
660
        // Check with Acl
661
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parentNode);
662
663
        $parentNodeTranslation = $parentNode->getNodeTranslation($this->locale, true);
664
        $parentNodeVersion = $parentNodeTranslation->getPublicNodeVersion();
665
        $parentPage = $parentNodeVersion->getRef($this->em);
666
667
        $type = $this->validatePageType($request);
668
        $newPage = $this->createNewPage($request, $type);
669
        $newPage->setParent($parentPage);
670
671
        /* @var Node $nodeNewPage */
672
        $nodeNewPage = $this->em->getRepository('KunstmaanNodeBundle:Node')
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeFor() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Repository\NodeRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
673
            ->createNodeFor($newPage, $this->locale, $this->user);
674
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
675
            $this->locale,
676
            true
677
        );
678
        $weight = $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method getMaxChildrenWeight() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Rep...deTranslationRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
679
                ->getMaxChildrenWeight($parentNode, $this->locale) + 1;
680
        $nodeTranslation->setWeight($weight);
681
682
        if ($newPage->isStructureNode()) {
683
            $nodeTranslation->setSlug('');
684
        }
685
686
        $this->em->persist($nodeTranslation);
687
        $this->em->flush();
688
689
        $this->aclManager->updateNodeAcl($parentNode, $nodeNewPage);
690
691
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
692
693
        $this->get('event_dispatcher')->dispatch(
694
            Events::ADD_NODE,
695
            new NodeEvent(
696
                $nodeNewPage, $nodeTranslation, $nodeVersion, $newPage
697
            )
698
        );
699
700
        return $this->redirect(
701
            $this->generateUrl(
702
                'KunstmaanNodeBundle_nodes_edit',
703
                array('id' => $nodeNewPage->getId())
704
            )
705
        );
706
    }
707
708
    /**
709
     * @Route("/add-homepage", name="KunstmaanNodeBundle_nodes_add_homepage", methods={"POST"})
710
     *
711
     * @return RedirectResponse
712
     *
713
     * @throws AccessDeniedException
714
     * @throws InvalidArgumentException
715
     */
716
    public function addHomepageAction(Request $request)
717
    {
718
        $this->init($request);
719
720
        // Check with Acl
721
        $this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
722
723
        $type = $this->validatePageType($request);
724
725
        $newPage = $this->createNewPage($request, $type);
726
727
        /* @var Node $nodeNewPage */
728
        $nodeNewPage = $this->em->getRepository('KunstmaanNodeBundle:Node')
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeFor() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Repository\NodeRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
729
            ->createNodeFor($newPage, $this->locale, $this->user);
730
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
731
            $this->locale,
732
            true
733
        );
734
        $this->em->flush();
735
736
        // Set default permissions
737
        $this->container->get('kunstmaan_node.acl_permission_creator_service')
738
            ->createPermission($nodeNewPage);
739
740
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
741
742
        $this->get('event_dispatcher')->dispatch(
743
            Events::ADD_NODE,
744
            new NodeEvent(
745
                $nodeNewPage, $nodeTranslation, $nodeVersion, $newPage
746
            )
747
        );
748
749
        return $this->redirect(
750
            $this->generateUrl(
751
                'KunstmaanNodeBundle_nodes_edit',
752
                array('id' => $nodeNewPage->getId())
753
            )
754
        );
755
    }
756
757
    /**
758
     * @Route("/reorder", name="KunstmaanNodeBundle_nodes_reorder", methods={"POST"})
759
     *
760
     * @param Request $request
761
     *
762
     * @return string
763
     *
764
     * @throws AccessDeniedException
765
     */
766
    public function reorderAction(Request $request)
767
    {
768
        $this->init($request);
769
        $nodes = array();
770
        $nodeIds = $request->get('nodes');
771
        $changeParents = $request->get('parent');
772
773
        foreach ($nodeIds as $id) {
774
            /* @var Node $node */
775
            $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
776
            $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
777
            $nodes[] = $node;
778
        }
779
780
        $weight = 1;
781
        foreach ($nodes as $node) {
782
            $newParentId = isset($changeParents[$node->getId()]) ? $changeParents[$node->getId()] : null;
783
            if ($newParentId) {
784
                $parent = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($newParentId);
785
                $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parent);
786
                $node->setParent($parent);
787
                $this->em->persist($node);
788
                $this->em->flush($node);
789
            }
790
791
            /* @var NodeTranslation $nodeTranslation */
792
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
793
794
            if ($nodeTranslation) {
795
                $nodeVersion = $nodeTranslation->getPublicNodeVersion();
796
                $page = $nodeVersion->getRef($this->em);
797
798
                $this->get('event_dispatcher')->dispatch(
799
                    Events::PRE_PERSIST,
800
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
801
                );
802
803
                $nodeTranslation->setWeight($weight);
804
                $this->em->persist($nodeTranslation);
805
                $this->em->flush($nodeTranslation);
806
807
                $this->get('event_dispatcher')->dispatch(
808
                    Events::POST_PERSIST,
809
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
810
                );
811
812
                ++$weight;
813
            }
814
        }
815
816
        return new JsonResponse(
817
            array(
818
                'Success' => 'The node-translations for [' . $this->locale . '] have got new weight values',
819
            )
820
        );
821
    }
822
823
    /**
824
     * @Route(
825
     *      "/{id}/{subaction}",
826
     *      requirements={"id" = "\d+"},
827
     *      defaults={"subaction" = "public"},
828
     *      name="KunstmaanNodeBundle_nodes_edit",
829
     *      methods={"GET", "POST"}
830
     * )
831
     * @Template("@KunstmaanNode/NodeAdmin/edit.html.twig")
832
     *
833
     * @param Request $request
834
     * @param int     $id        The node id
835
     * @param string  $subaction The subaction (draft|public)
836
     *
837
     * @return RedirectResponse|array
838
     *
839
     * @throws AccessDeniedException
840
     */
841
    public function editAction(Request $request, $id, $subaction)
842
    {
843
        $this->init($request);
844
        /* @var Node $node */
845
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
846
847
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
848
849
        $tabPane = new TabPane(
850
            'todo',
851
            $request,
852
            $this->container->get('form.factory')
853
        );
854
855
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
856
        if (!$nodeTranslation) {
857
            return $this->renderNodeNotTranslatedPage($node);
858
        }
859
860
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
861
        $draftNodeVersion = $nodeTranslation->getDraftNodeVersion();
862
        $nodeVersionIsLocked = false;
863
864
        /* @var HasNodeInterface $page */
865
        $page = null;
866
        $draft = ($subaction == 'draft');
867
        $saveAsDraft = $request->get('saveasdraft');
868
        if ((!$draft && !empty($saveAsDraft)) || ($draft && \is_null($draftNodeVersion))) {
869
            // Create a new draft version
870
            $draft = true;
871
            $subaction = 'draft';
872
            $page = $nodeVersion->getRef($this->em);
873
            $nodeVersion = $this->createDraftVersion(
874
                $page,
875
                $nodeTranslation,
876
                $nodeVersion
877
            );
878
            $draftNodeVersion = $nodeVersion;
879
        } elseif ($draft) {
880
            $nodeVersion = $draftNodeVersion;
881
            $page = $nodeVersion->getRef($this->em);
882
        } else {
883
            if ($request->getMethod() == 'POST') {
884
                $nodeVersionIsLocked = $this->isNodeVersionLocked($nodeTranslation, true);
885
886
                //Check the version timeout and make a new nodeversion if the timeout is passed
887
                $thresholdDate = date(
888
                    'Y-m-d H:i:s',
889
                    time() - $this->getParameter(
890
                        'kunstmaan_node.version_timeout'
891
                    )
892
                );
893
                $updatedDate = date(
894
                    'Y-m-d H:i:s',
895
                    strtotime($nodeVersion->getUpdated()->format('Y-m-d H:i:s'))
896
                );
897 View Code Duplication
                if ($thresholdDate >= $updatedDate || $nodeVersionIsLocked) {
898
                    $page = $nodeVersion->getRef($this->em);
899
                    if ($nodeVersion === $nodeTranslation->getPublicNodeVersion()) {
900
                        $this->nodePublisher
901
                            ->createPublicVersion(
902
                                $page,
903
                                $nodeTranslation,
904
                                $nodeVersion,
905
                                $this->user
906
                            );
907
                    } else {
908
                        $this->createDraftVersion(
909
                            $page,
910
                            $nodeTranslation,
911
                            $nodeVersion
912
                        );
913
                    }
914
                }
915
            }
916
            $page = $nodeVersion->getRef($this->em);
917
        }
918
        $isStructureNode = $page->isStructureNode();
919
920
        $menubuilder = $this->get('kunstmaan_node.actions_menu_builder');
921
        $menubuilder->setActiveNodeVersion($nodeVersion);
922
        $menubuilder->setEditableNode(!$isStructureNode);
923
924
        // Building the form
925
        $propertiesWidget = new FormWidget();
926
        $propertiesWidget->addType('main', $page->getDefaultAdminType(), $page);
927
        $propertiesWidget->addType('node', $node->getDefaultAdminType(), $node);
928
        $tabPane->addTab(new Tab('kuma_node.tab.properties.title', $propertiesWidget));
929
930
        // Menu tab
931
        $menuWidget = new FormWidget();
932
        $menuWidget->addType(
933
            'menunodetranslation',
934
            NodeMenuTabTranslationAdminType::class,
935
            $nodeTranslation,
936
            ['slugable' => !$isStructureNode]
937
        );
938
        $menuWidget->addType('menunode', NodeMenuTabAdminType::class, $node, ['available_in_nav' => !$isStructureNode]);
939
        $tabPane->addTab(new Tab('kuma_node.tab.menu.title', $menuWidget));
940
941
        $this->get('event_dispatcher')->dispatch(
942
            Events::ADAPT_FORM,
943
            new AdaptFormEvent(
944
                $request,
945
                $tabPane,
946
                $page,
947
                $node,
948
                $nodeTranslation,
949
                $nodeVersion
950
            )
951
        );
952
953
        $tabPane->buildForm();
954
955
        if ($request->getMethod() == 'POST') {
956
            $tabPane->bindRequest($request);
957
958
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
959
            if ($tabPane->isValid() && !$request->isXmlHttpRequest()) {
960
                $this->get('event_dispatcher')->dispatch(
961
                    Events::PRE_PERSIST,
962
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
963
                );
964
965
                $nodeTranslation->setTitle($page->getTitle());
966
                if ($isStructureNode) {
967
                    $nodeTranslation->setSlug('');
968
                }
969
                $nodeVersion->setUpdated(new DateTime());
970
                if ($nodeVersion->getType() == 'public') {
971
                    $nodeTranslation->setUpdated($nodeVersion->getUpdated());
972
                }
973
                $this->em->persist($nodeTranslation);
974
                $this->em->persist($nodeVersion);
975
                $tabPane->persist($this->em);
976
                $this->em->flush();
977
978
                $this->get('event_dispatcher')->dispatch(
979
                    Events::POST_PERSIST,
980
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
981
                );
982
983
                if ($nodeVersionIsLocked) {
984
                    $this->addFlash(
985
                        FlashTypes::SUCCESS,
986
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.locked_success')
987
                    );
988
                } elseif ($request->request->has('publishing') || $request->request->has('publish_later')) {
989
                    $this->nodePublisher->chooseHowToPublish($request, $nodeTranslation, $this->translator);
990
                } elseif ($request->request->has('unpublishing') || $request->request->has('unpublish_later')) {
991
                    $this->nodePublisher->chooseHowToUnpublish($request, $nodeTranslation, $this->translator);
992
                } else {
993
                    $this->addFlash(
994
                        FlashTypes::SUCCESS,
995
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.success')
996
                    );
997
                }
998
999
                $params = [
1000
                    'id' => $node->getId(),
1001
                    'subaction' => $subaction,
1002
                    'currenttab' => $tabPane->getActiveTab(),
1003
                ];
1004
                $params = array_merge(
1005
                    $params,
1006
                    $tabPane->getExtraParams($request)
1007
                );
1008
1009
                if ($subaction === 'draft' && ($request->request->has('publishing') || $request->request->has('publish_later'))) {
1010
                    unset($params['subaction']);
1011
                }
1012
1013
                return $this->redirect(
1014
                    $this->generateUrl(
1015
                        'KunstmaanNodeBundle_nodes_edit',
1016
                        $params
1017
                    )
1018
                );
1019
            }
1020
        }
1021
1022
        $nodeVersions = $this->em->getRepository(
1023
            'KunstmaanNodeBundle:NodeVersion'
1024
        )->findBy(
1025
            ['nodeTranslation' => $nodeTranslation],
1026
            ['updated' => 'ASC']
1027
        );
1028
        $queuedNodeTranslationAction = $this->em->getRepository(
1029
            'KunstmaanNodeBundle:QueuedNodeTranslationAction'
1030
        )->findOneBy(['nodeTranslation' => $nodeTranslation]);
1031
1032
        return [
1033
            'page' => $page,
1034
            'entityname' => ClassLookup::getClass($page),
1035
            'nodeVersions' => $nodeVersions,
1036
            'node' => $node,
1037
            'nodeTranslation' => $nodeTranslation,
1038
            'draft' => $draft,
1039
            'draftNodeVersion' => $draftNodeVersion,
1040
            'showDuplicateWithChildren' => $this->getParameter('kunstmaan_node.show_duplicate_with_children'),
1041
            'nodeVersion' => $nodeVersion,
1042
            'subaction' => $subaction,
1043
            'tabPane' => $tabPane,
1044
            'editmode' => true,
1045
            'childCount' => $this->em->getRepository('KunstmaanNodeBundle:Node')->getChildCount($node),
1046
            'queuedNodeTranslationAction' => $queuedNodeTranslationAction,
1047
            'nodeVersionLockCheck' => $this->container->getParameter('kunstmaan_node.lock_enabled'),
1048
            'nodeVersionLockInterval' => $this->container->getParameter('kunstmaan_node.lock_check_interval'),
1049
        ];
1050
    }
1051
1052
    /**
1053
     * @Route(
1054
     *      "checkNodeVersionLock/{id}/{public}",
1055
     *      requirements={"id" = "\d+", "public" = "(0|1)"},
1056
     *      name="KunstmaanNodeBundle_nodes_versionlock_check"
1057
     * )
1058
     *
1059
     * @param Request $request
1060
     * @param $id
1061
     *
1062
     * @return JsonResponse
1063
     */
1064
    public function checkNodeVersionLockAction(Request $request, $id, $public)
1065
    {
1066
        $nodeVersionIsLocked = false;
1067
        $message = '';
1068
        $this->init($request);
1069
1070
        /* @var Node $node */
1071
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
1072
1073
        try {
1074
            $this->checkPermission($node, PermissionMap::PERMISSION_EDIT);
1075
1076
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1077
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1078
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
1079
1080
            if ($nodeTranslation) {
1081
                $nodeVersionIsLocked = $nodeVersionLockHelper->isNodeVersionLocked($this->getUser(), $nodeTranslation, $public);
1082
1083
                if ($nodeVersionIsLocked) {
1084
                    $users = $nodeVersionLockHelper->getUsersWithNodeVersionLock($nodeTranslation, $public, $this->getUser());
1085
                    $message = $this->get('translator')->trans('kuma_node.admin.edit.flash.locked', array('%users%' => implode(', ', $users)));
1086
                }
1087
            }
1088
        } catch (AccessDeniedException $ade) {
1089
        }
1090
1091
        return new JsonResponse(['lock' => $nodeVersionIsLocked, 'message' => $message]);
1092
    }
1093
1094
    /**
1095
     * @param NodeTranslation $nodeTranslation
1096
     * @param bool            $isPublic
1097
     *
1098
     * @return bool
1099
     */
1100
    private function isNodeVersionLocked(NodeTranslation $nodeTranslation, $isPublic)
1101
    {
1102
        if ($this->container->getParameter('kunstmaan_node.lock_enabled')) {
1103
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1104
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1105
            $nodeVersionIsLocked = $nodeVersionLockHelper->isNodeVersionLocked($this->getUser(), $nodeTranslation, $isPublic);
1106
1107
            return $nodeVersionIsLocked;
1108
        }
1109
1110
        return false;
1111
    }
1112
1113
    /**
1114