Completed
Push — master ( 67d37c...483c69 )
by Ruud
06:47
created

Kunstmaan/NodeBundle/Helper/PageCloningHelper.php (1 issue)

Severity

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\Helper;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Kunstmaan\AdminBundle\Entity\BaseUser;
7
use Kunstmaan\AdminBundle\Helper\CloneHelper;
8
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
9
use Kunstmaan\NodeBundle\Entity\DuplicateSubPageInterface;
10
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
11
use Kunstmaan\NodeBundle\Entity\Node;
12
use Kunstmaan\NodeBundle\Entity\PageInterface;
13
use Kunstmaan\NodeBundle\Event\Events;
14
use Kunstmaan\NodeBundle\Event\NodeDuplicateEvent;
15
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
16
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
17
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
18
use Symfony\Component\Security\Acl\Model\EntryInterface;
19
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
20
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
22
23
class PageCloningHelper
24
{
25
    /** @var EntityManagerInterface */
26
    private $em;
27
28
    /** @var CloneHelper */
29
    private $cloneHelper;
30
31
    /** @var AclProviderInterface */
32
    private $aclProvider;
33
34
    /** @var ObjectIdentityRetrievalStrategyInterface */
35
    private $identityRetrievalStrategy;
36
37
    /** @var AuthorizationCheckerInterface */
38
    private $authorizationCheckerInterface;
39
40
    /** @var EventDispatcherInterface */
41
    private $eventDispatcherInterface;
42
43
    public function __construct(EntityManagerInterface $em, CloneHelper $cloneHelper, AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $identityRetrivalStrategy, AuthorizationCheckerInterface $authorizationChecker, EventDispatcherInterface $eventDispatcher)
44
    {
45
        $this->em = $em;
46
        $this->cloneHelper = $cloneHelper;
47
        $this->aclProvider = $aclProvider;
48
        $this->identityRetrievalStrategy = $identityRetrivalStrategy;
49
        $this->authorizationCheckerInterface = $authorizationChecker;
50
        $this->eventDispatcherInterface = $eventDispatcher;
51
    }
52
53
    /**
54
     * @throws AccessDeniedException
55
     */
56
    public function duplicateWithChildren($id, string $locale, BaseUser $user, string $title = null): Node
57
    {
58
        /* @var Node $parentNode */
59
        $originalNode = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
60
61
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $originalNode);
62
63
        $this->eventDispatcherInterface->dispatch(Events::PRE_DUPLICATE_WITH_CHILDREN, new NodeDuplicateEvent($originalNode));
64
65
        $newPage = $this->clonePage($originalNode, $locale, $title);
66
        $nodeNewPage = $this->createNodeStructureForNewPage($originalNode, $newPage, $user, $locale);
67
68
        $this->cloneChildren($originalNode, $newPage, $user, $locale);
69
70
        $this->eventDispatcherInterface->dispatch(Events::POST_DUPLICATE_WITH_CHILDREN, new NodeDuplicateEvent($originalNode));
0 ignored issues
show
$originalNode is of type object|null, but the function expects a object<Kunstmaan\NodeBundle\Entity\Node>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
71
72
        return $nodeNewPage;
73
    }
74
75
    private function denyAccessUnlessGranted($attributes, $subject = null, $message = 'Access Denied.')
76
    {
77
        if (!$this->authorizationCheckerInterface->isGranted($attributes, $subject)) {
78
            $exception = new AccessDeniedException();
79
            $exception->setAttributes($attributes);
80
            $exception->setSubject($subject);
81
82
            throw $exception;
83
        }
84
    }
85
86
    private function clonePage(Node $originalNode, $locale, $title = null)
87
    {
88
        $originalNodeTranslations = $originalNode->getNodeTranslation($locale, true);
89
        $originalRef = $originalNodeTranslations->getPublicNodeVersion()->getRef($this->em);
90
91
        $newPage = $this->cloneHelper->deepCloneAndSave($originalRef);
92
93
        if ($title !== null) {
94
            $newPage->setTitle($title);
95
        }
96
97
        //set the parent
98
        $parentNodeTranslation = $originalNode->getParent()->getNodeTranslation($locale, true);
99
        $parent = $parentNodeTranslation->getPublicNodeVersion()->getRef($this->em);
100
        $newPage->setParent($parent);
101
102
        $this->em->persist($newPage);
103
        $this->em->flush();
104
105
        return $newPage;
106
    }
107
108
    private function createNodeStructureForNewPage(Node $originalNode, HasNodeInterface $newPage, BaseUser $user, string $locale): Node
109
    {
110
        /* @var Node $nodeNewPage */
111
        $nodeNewPage = $this->em->getRepository('KunstmaanNodeBundle:Node')->createNodeFor($newPage, $locale, $user);
112
113
        if ($newPage->isStructureNode()) {
114
            $nodeTranslation = $nodeNewPage->getNodeTranslation($locale, true);
115
            $nodeTranslation->setSlug('');
116
            $this->em->persist($nodeTranslation);
117
        }
118
        $this->em->flush();
119
120
        $this->updateAcl($originalNode, $nodeNewPage);
121
122
        return $nodeNewPage;
123
    }
124
125 View Code Duplication
    private function updateAcl($originalNode, $nodeNewPage): void
126
    {
127
        $originalIdentity = $this->identityRetrievalStrategy->getObjectIdentity($originalNode);
128
        $originalAcl = $this->aclProvider->findAcl($originalIdentity);
129
130
        $newIdentity = $this->identityRetrievalStrategy->getObjectIdentity($nodeNewPage);
131
        $newAcl = $this->aclProvider->createAcl($newIdentity);
132
133
        $aces = $originalAcl->getObjectAces();
134
        /* @var EntryInterface $ace */
135
        foreach ($aces as $ace) {
136
            $securityIdentity = $ace->getSecurityIdentity();
137
            if ($securityIdentity instanceof RoleSecurityIdentity) {
138
                $newAcl->insertObjectAce($securityIdentity, $ace->getMask());
139
            }
140
        }
141
        $this->aclProvider->updateAcl($newAcl);
142
    }
143
144
    private function cloneChildren(Node $originalNode, PageInterface $newPage, BaseUser $user, string $locale): void
145
    {
146
        $nodeChildren = $originalNode->getChildren();
147
        foreach ($nodeChildren as $originalNodeChild) {
148
            $originalNodeTranslations = $originalNodeChild->getNodeTranslation($locale, true);
149
            $originalRef = $originalNodeTranslations->getPublicNodeVersion()->getRef($this->em);
150
151
            if (!$originalRef instanceof DuplicateSubPageInterface || !$originalRef->skipClone()) {
152
                $newChildPage = $this->clonePage($originalNodeChild, $locale);
153
                $newChildPage->setParent($newPage);
154
155
                $this->createNodeStructureForNewPage($originalNodeChild, $newChildPage, $user, $locale);
156
                $this->cloneChildren($originalNodeChild, $newChildPage, $user, $locale);
157
            }
158
        }
159
    }
160
}
161