Completed
Pull Request — master (#2706)
by
unknown
13:26
created

NodeAdminController::undoDeleteNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 2
nc 2
nop 1
crap 6
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\AdminListBundle\AdminList\ListAction\SimpleListAction;
20
use Kunstmaan\NodeBundle\AdminList\DeletedNodeAdminListConfigurator;
21
use Kunstmaan\NodeBundle\AdminList\NodeAdminListConfigurator;
22
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
23
use Kunstmaan\NodeBundle\Entity\Node;
24
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
25
use Kunstmaan\NodeBundle\Entity\NodeVersion;
26
use Kunstmaan\NodeBundle\Entity\QueuedNodeTranslationAction;
27
use Kunstmaan\NodeBundle\Event\AdaptFormEvent;
28
use Kunstmaan\NodeBundle\Event\CopyPageTranslationNodeEvent;
29
use Kunstmaan\NodeBundle\Event\Events;
30
use Kunstmaan\NodeBundle\Event\NodeEvent;
31
use Kunstmaan\NodeBundle\Event\RecopyPageTranslationNodeEvent;
32
use Kunstmaan\NodeBundle\Event\RevertNodeAction;
33
use Kunstmaan\NodeBundle\Form\NodeMenuTabAdminType;
34
use Kunstmaan\NodeBundle\Form\NodeMenuTabTranslationAdminType;
35
use Kunstmaan\NodeBundle\Helper\NodeAdmin\NodeAdminPublisher;
36
use Kunstmaan\NodeBundle\Helper\NodeAdmin\NodeVersionLockHelper;
37
use Kunstmaan\NodeBundle\Helper\PageCloningHelper;
38
use Kunstmaan\NodeBundle\Repository\NodeVersionRepository;
39
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
40
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
41
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
42
use Symfony\Component\HttpFoundation\JsonResponse;
43
use Symfony\Component\HttpFoundation\RedirectResponse;
44
use Symfony\Component\HttpFoundation\Request;
45
use Symfony\Component\Routing\Annotation\Route;
46
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
47
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
48
use Symfony\Component\Translation\TranslatorInterface;
49
50
/**
51
 * NodeAdminController
52
 */
53
class NodeAdminController extends Controller
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...e\Controller\Controller has been deprecated with message: since Symfony 4.2, use "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
54
{
55
    /**
56
     * @var EntityManager
57
     */
58
    protected $em;
59
60
    /**
61
     * @var string
62
     */
63
    protected $locale;
64
65
    /**
66
     * @var AuthorizationCheckerInterface
67
     */
68
    protected $authorizationChecker;
69
70
    /**
71
     * @var BaseUser
72
     */
73
    protected $user;
74
75
    /**
76
     * @var AclHelper
77
     */
78
    protected $aclHelper;
79
80
    /**
81
     * @var AclManager
82
     */
83
    protected $aclManager;
84
85
    /**
86
     * @var NodeAdminPublisher
87
     */
88
    protected $nodePublisher;
89
90
    /**
91
     * @var TranslatorInterface
92
     */
93
    protected $translator;
94
95
    /** @var PageCloningHelper */
96
    private $pageCloningHelper;
97
98
    /**
99
     * init
100
     *
101
     * @param Request $request
102
     */
103
    protected function init(Request $request)
104
    {
105
        $this->em = $this->getDoctrine()->getManager();
106
        $this->locale = $request->getLocale();
107
        $this->authorizationChecker = $this->container->get('security.authorization_checker');
108
        $this->user = $this->getUser();
109
        $this->aclHelper = $this->container->get('kunstmaan_admin.acl.helper');
110
        $this->aclManager = $this->container->get('kunstmaan_admin.acl.manager');
111
        $this->nodePublisher = $this->container->get('kunstmaan_node.admin_node.publisher');
112
        $this->translator = $this->container->get('translator');
113
        $this->pageCloningHelper = $this->container->get(PageCloningHelper::class);
114
    }
115
116
    /**
117
     * @Route("/", name="KunstmaanNodeBundle_nodes")
118
     * @Template("@KunstmaanNode/Admin/list.html.twig")
119
     *
120
     * @param Request $request
121
     *
122
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,AdminList>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
123
     */
124
    public function indexAction(Request $request)
125
    {
126
        $this->init($request);
127
128
        $nodeAdminListConfigurator = new NodeAdminListConfigurator(
129
            $this->em,
130
            $this->aclHelper,
131
            $this->locale,
132
            PermissionMap::PERMISSION_VIEW,
133
            $this->authorizationChecker
134
        );
135
136
        $locale = $this->locale;
137
        $acl = $this->authorizationChecker;
138 View Code Duplication
        $itemRoute = function (EntityInterface $item) use ($locale, $acl) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
139
            if ($acl->isGranted(PermissionMap::PERMISSION_VIEW, $item->getNode())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Kunstmaan\AdminBundle\Entity\EntityInterface as the method getNode() does only exist in the following implementations of said interface: Kunstmaan\FormBundle\Entity\FormSubmission, Kunstmaan\FormBundle\Tes...List\FakeFormSubmission, Kunstmaan\NodeBundle\Entity\NodeTranslation, Kunstmaan\NodeSearchBundle\Entity\NodeSearch.

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...
140
                return array(
141
                    'path' => '_slug_preview',
142
                    'params' => ['_locale' => $locale, 'url' => $item->getUrl()],
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Kunstmaan\AdminBundle\Entity\EntityInterface as the method getUrl() does only exist in the following implementations of said interface: Kunstmaan\AdminBundle\Entity\Exception, Kunstmaan\MediaBundle\Entity\Media, Kunstmaan\MenuBundle\Entity\BaseMenuItem, Kunstmaan\MenuBundle\Entity\MenuItem, Kunstmaan\NodeBundle\Entity\NodeTranslation, Kunstmaan\PagePartBundle\Entity\LinkPagePart.

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...
143
                );
144
            }
145
146
            return null;
147
        };
148
149
        $nodeAdminListConfigurator->addSimpleItemAction('action.preview', $itemRoute, 'eye');
150
        $nodeAdminListConfigurator->addListAction(
151
            new SimpleListAction(
152
                [
153
                    'path' => 'KunstmaanNodeBundle_deleted_nodes',
154
                    'params' => [],
155
                ],
156
                'deleted_pages.view_action',
157
                null,
158
                '@KunstmaanAdmin/Settings/button_resolve_all.html.twig'
159
            )
160
        );
161
        $nodeAdminListConfigurator->setDomainConfiguration($this->get('kunstmaan_admin.domain_configuration'));
162
        $nodeAdminListConfigurator->setShowAddHomepage(
163
            $this->getParameter('kunstmaan_node.show_add_homepage') && $this->isGranted('ROLE_SUPER_ADMIN')
164
        );
165
166
        return $this->renderAdminList($request, $nodeAdminListConfigurator);
167
    }
168
169
    /**
170
     * @Route(
171
     *      "/{id}/copyfromotherlanguage",
172
     *      requirements={"id" = "\d+"},
173
     *      name="KunstmaanNodeBundle_nodes_copyfromotherlanguage",
174
     *      methods={"GET"}
175
     * )
176
     *
177
     * @param Request $request
178
     * @param int     $id      The node id
179
     *
180
     * @return RedirectResponse
181
     *
182
     * @throws AccessDeniedException
183
     */
184
    public function copyFromOtherLanguageAction(Request $request, $id)
185
    {
186
        $this->init($request);
187
        /* @var Node $node */
188
        $node = $this->em->getRepository(Node::class)->find($id);
189
190
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
191
192
        $originalLanguage = $request->get('originallanguage');
193
        $otherLanguageNodeTranslation = $node->getNodeTranslation($originalLanguage, true);
194
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
195
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
196
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
197
            ->deepCloneAndSave($otherLanguagePage);
198
199
        /* @var NodeTranslation $nodeTranslation */
200
        $nodeTranslation = $this->em->getRepository(NodeTranslation::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeTranslationFor() 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...
201
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
202
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
203
204
        $this->get('event_dispatcher')->dispatch(
205
            Events::COPY_PAGE_TRANSLATION,
206
            new CopyPageTranslationNodeEvent(
207
                $node,
208
                $nodeTranslation,
209
                $nodeVersion,
210
                $myLanguagePage,
211
                $otherLanguageNodeTranslation,
0 ignored issues
show
Bug introduced by
It seems like $otherLanguageNodeTranslation defined by $node->getNodeTranslatio...originalLanguage, true) on line 193 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
212
                $otherLanguageNodeNodeVersion,
213
                $otherLanguagePage,
214
                $originalLanguage
215
            )
216
        );
217
218
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
219
    }
220
221
    /**
222
     * @Route(
223
     *      "/{id}/recopyfromotherlanguage",
224
     *      requirements={"id" = "\d+"},
225
     *      name="KunstmaanNodeBundle_nodes_recopyfromotherlanguage",
226
     *      methods={"POST"}
227
     * )
228
     *
229
     * @param Request $request
230
     * @param int     $id      The node id
231
     *
232
     * @return RedirectResponse
233
     *
234
     * @throws AccessDeniedException
235
     */
236
    public function recopyFromOtherLanguageAction(Request $request, $id)
237
    {
238
        $this->init($request);
239
        /* @var Node $node */
240
        $node = $this->em->getRepository(Node::class)->find($id);
241
242
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
243
244
        $otherLanguageNodeTranslation = $this->em->getRepository(NodeTranslation::class)->find($request->get('source'));
245
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
246
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
247
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
248
            ->deepCloneAndSave($otherLanguagePage);
249
250
        /* @var NodeTranslation $nodeTranslation */
251
        $nodeTranslation = $this->em->getRepository(NodeTranslation::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method addDraftNodeVersionFor() 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...
252
            ->addDraftNodeVersionFor($myLanguagePage, $this->locale, $node, $this->user);
253
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
254
255
        $this->get('event_dispatcher')->dispatch(
256
            Events::RECOPY_PAGE_TRANSLATION,
257
            new RecopyPageTranslationNodeEvent(
258
                $node,
259
                $nodeTranslation,
260
                $nodeVersion,
261
                $myLanguagePage,
262
                $otherLanguageNodeTranslation,
0 ignored issues
show
Documentation introduced by
$otherLanguageNodeTranslation is of type object|null, but the function expects a object<Kunstmaan\NodeBun...Entity\NodeTranslation>.

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...
263
                $otherLanguageNodeNodeVersion,
264
                $otherLanguagePage,
265
                $otherLanguageNodeTranslation->getLang()
266
            )
267
        );
268
269
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id, 'subaction' => NodeVersion::DRAFT_VERSION)));
270
    }
271
272
    /**
273
     * @Route(
274
     *      "/{id}/createemptypage",
275
     *      requirements={"id" = "\d+"},
276
     *      name="KunstmaanNodeBundle_nodes_createemptypage",
277
     *      methods={"GET"}
278
     * )
279
     *
280
     * @param Request $request
281
     * @param int     $id
282
     *
283
     * @return RedirectResponse
284
     *
285
     * @throws AccessDeniedException
286
     */
287
    public function createEmptyPageAction(Request $request, $id)
288
    {
289
        $this->init($request);
290
        /* @var Node $node */
291
        $node = $this->em->getRepository(Node::class)->find($id);
292
293
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
294
295
        $entityName = $node->getRefEntityName();
296
        /* @var HasNodeInterface $myLanguagePage */
297
        $myLanguagePage = new $entityName();
298
        $myLanguagePage->setTitle('New page');
299
300
        $this->em->persist($myLanguagePage);
301
        $this->em->flush();
302
        /* @var NodeTranslation $nodeTranslation */
303
        $nodeTranslation = $this->em->getRepository(NodeTranslation::class)
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeTranslationFor() 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...
304
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
305
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
306
307
        $this->get('event_dispatcher')->dispatch(
308
            Events::ADD_EMPTY_PAGE_TRANSLATION,
309
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $myLanguagePage)
310
        );
311
312
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
313
    }
314
315
    /**
316
     * @Route("/{id}/publish", requirements={"id" =
317
     *                         "\d+"},
318
     *                         name="KunstmaanNodeBundle_nodes_publish", methods={"GET", "POST"})
319
     *
320
     * @param Request $request
321
     * @param int     $id
322
     *
323
     * @return RedirectResponse
324
     *
325
     * @throws AccessDeniedException
326
     */
327 View Code Duplication
    public function publishAction(Request $request, $id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
328
    {
329
        $this->init($request);
330
        /* @var Node $node */
331
        $node = $this->em->getRepository(Node::class)->find($id);
332
333
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
334
        $request = $this->get('request_stack')->getCurrentRequest();
335
        $this->nodePublisher->chooseHowToPublish($request, $nodeTranslation, $this->translator);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 333 can be null; however, Kunstmaan\NodeBundle\Hel...r::chooseHowToPublish() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
336
337
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
338
    }
339
340
    /**
341
     * @Route(
342
     *      "/{id}/unpublish",
343
     *      requirements={"id" = "\d+"},
344
     *      name="KunstmaanNodeBundle_nodes_unpublish",
345
     *      methods={"GET", "POST"}
346
     * )
347
     *
348
     * @param Request $request
349
     * @param int     $id
350
     *
351
     * @return RedirectResponse
352
     *
353
     * @throws AccessDeniedException
354
     */
355 View Code Duplication
    public function unPublishAction(Request $request, $id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
356
    {
357
        $this->init($request);
358
        /* @var Node $node */
359
        $node = $this->em->getRepository(Node::class)->find($id);
360
361
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
362
        $request = $this->get('request_stack')->getCurrentRequest();
363
        $this->nodePublisher->chooseHowToUnpublish($request, $nodeTranslation, $this->translator);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 361 can be null; however, Kunstmaan\NodeBundle\Hel...:chooseHowToUnpublish() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
364
365
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
366
    }
367
368
    /**
369
     * @Route(
370
     *      "/{id}/unschedulepublish",
371
     *      requirements={"id" = "\d+"},
372
     *      name="KunstmaanNodeBundle_nodes_unschedule_publish",
373
     *      methods={"GET", "POST"}
374
     * )
375
     *
376
     * @param Request $request
377
     * @param int     $id
378
     *
379
     * @return RedirectResponse
380
     *
381
     * @throws AccessDeniedException
382
     */
383 View Code Duplication
    public function unSchedulePublishAction(Request $request, $id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
384
    {
385
        $this->init($request);
386
387
        /* @var Node $node */
388
        $node = $this->em->getRepository(Node::class)->find($id);
389
390
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
391
        $this->nodePublisher->unSchedulePublish($nodeTranslation);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 390 can be null; however, Kunstmaan\NodeBundle\Hel...er::unSchedulePublish() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
392
393
        $this->addFlash(
394
            FlashTypes::SUCCESS,
395
            $this->get('translator')->trans('kuma_node.admin.unschedule.flash.success')
396
        );
397
398
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
399
    }
400
401
    /**
402
     * @Route(
403
     *      "/{id}/delete",
404
     *      requirements={"id" = "\d+"},
405
     *      name="KunstmaanNodeBundle_nodes_delete",
406
     *      methods={"POST"}
407
     * )
408
     *
409
     * @param Request $request
410
     * @param int     $id
411
     *
412
     * @return RedirectResponse
413
     *
414
     * @throws AccessDeniedException
415
     */
416
    public function deleteAction(Request $request, $id)
417
    {
418
        $this->init($request);
419
        /* @var Node $node */
420
        $node = $this->em->getRepository(Node::class)->find($id);
421
422
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_DELETE, $node);
423
424
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
425
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
426
        $page = $nodeVersion->getRef($this->em);
427
428
        $this->get('event_dispatcher')->dispatch(
429
            Events::PRE_DELETE,
430
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 424 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
431
        );
432
433
        $node->setDeleted(true);
434
        $this->em->persist($node);
435
436
        $children = $node->getChildren();
437
        $this->deleteNodeChildren($this->em, $this->user, $this->locale, $children);
0 ignored issues
show
Bug introduced by
It seems like $children defined by $node->getChildren() on line 436 can also be of type array<integer,object<Kun...odeBundle\Entity\Node>>; however, Kunstmaan\NodeBundle\Con...r::deleteNodeChildren() does only seem to accept object<Doctrine\Common\C...ctions\ArrayCollection>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
438
        $this->em->flush();
439
440
        $event = new NodeEvent($node, $nodeTranslation, $nodeVersion, $page);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 424 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
441
        $this->get('event_dispatcher')->dispatch(Events::POST_DELETE, $event);
442
        if (null === $response = $event->getResponse()) {
443
            $nodeParent = $node->getParent();
444
            // Check if we have a parent. Otherwise redirect to pages overview.
445
            if ($nodeParent) {
446
                $url = $this->get('router')->generate(
447
                    'KunstmaanNodeBundle_nodes_edit',
448
                    array('id' => $nodeParent->getId())
449
                );
450
            } else {
451
                $url = $this->get('router')->generate(
452
                    'KunstmaanNodeBundle_nodes'
453
                );
454
            }
455
            $response = new RedirectResponse($url);
456
        }
457
458
        $this->addFlash(
459
            FlashTypes::SUCCESS,
460
            $this->get('translator')->trans('kuma_node.admin.delete.flash.success')
461
        );
462
463
        return $response;
464
    }
465
466
    /**
467
     * @Route("/deleted", name="KunstmaanNodeBundle_deleted_nodes")
468
     * @Template("@KunstmaanNode/Admin/deleted_list.html.twig")
469
     *
470
     * @param Request $request
471
     *
472
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,AdminList>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
473
     */
474
    public function deletedNodesAction(Request $request)
475
    {
476
        $this->init($request);
477
478
        $nodeAdminListConfigurator = new DeletedNodeAdminListConfigurator(
479
            $this->em,
480
            $this->aclHelper,
481
            $this->locale,
482
            PermissionMap::PERMISSION_DELETE,
483
            $this->authorizationChecker
484
        );
485
        $nodeAdminListConfigurator->addListAction(
486
            new SimpleListAction(
487
                [
488
                    'path' => 'KunstmaanNodeBundle_nodes',
489
                    'params' => [],
490
                ],
491
                'pages.view_action',
492
                null,
493
                '@KunstmaanAdmin/Settings/button_resolve_all.html.twig'
494
            )
495
        );
496
497
        $locale = $this->locale;
498
        $acl = $this->authorizationChecker;
499
500
        $nodeAdminListConfigurator->addSimpleItemAction(
501
            'action.undo_delete',
502 View Code Duplication
            function (EntityInterface $item) use ($locale, $acl) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
503
                if ($acl->isGranted(PermissionMap::PERMISSION_DELETE, $item->getNode())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Kunstmaan\AdminBundle\Entity\EntityInterface as the method getNode() does only exist in the following implementations of said interface: Kunstmaan\FormBundle\Entity\FormSubmission, Kunstmaan\FormBundle\Tes...List\FakeFormSubmission, Kunstmaan\NodeBundle\Entity\NodeTranslation, Kunstmaan\NodeSearchBundle\Entity\NodeSearch.

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...
504
                    return [
505
                        'path' => 'KunstmaanNodeBundle_nodes_delete_undo',
506
                        'params' => [
507
                            '_locale' => $locale,
508
                            'id' => $item->getNode()->getId()
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Kunstmaan\AdminBundle\Entity\EntityInterface as the method getNode() does only exist in the following implementations of said interface: Kunstmaan\FormBundle\Entity\FormSubmission, Kunstmaan\FormBundle\Tes...List\FakeFormSubmission, Kunstmaan\NodeBundle\Entity\NodeTranslation, Kunstmaan\NodeSearchBundle\Entity\NodeSearch.

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...
509
                        ],
510
                    ];
511
                }
512
513
                return null;
514
            },
515
            'undo'
516
        );
517
518
        return $this->renderAdminList($request, $nodeAdminListConfigurator);
519
    }
520
521
    /**
522
     * @Route(
523
     *      "/{id}/delete/undo",
524
     *      requirements={"id" = "\d+"},
525
     *      name="KunstmaanNodeBundle_nodes_delete_undo",
526
     * )
527
     *
528
     * @param Request $request
529
     * @param int     $id
530
     *
531
     * @return RedirectResponse
532
     */
533
    public function undoDeleteAction(Request $request, $id)
534
    {
535
        $this->init($request);
536
537
        /* @var Node $node */
538
        $node = $this->em->getRepository('KunstmaanNodeBundle:Node')->find($id);
539
540
        try {
541
            $this->undoDeleteNode($node);
542
543
            $this->em->flush();
544
545
            $this->addFlash(
546
                FlashTypes::SUCCESS,
547
                $this->get('translator')->trans('kuma_node.admin.undo_delete.flash.success')
548
            );
549
        } catch (AccessDeniedException $exception) {
550
            $this->addFlash(
551
                FlashTypes::SUCCESS,
552
                $this->get('translator')->trans('kuma_node.admin.undo_delete.flash.error')
553
            );
554
        }
555
556
        return $this->redirectToRoute(
557
            'KunstmaanNodeBundle_deleted_nodes'
558
        );
559
    }
560
561
    /**
562
     * @Route(
563
     *      "/{id}/duplicate",
564
     *      requirements={"id" = "\d+"},
565
     *      name="KunstmaanNodeBundle_nodes_duplicate",
566
     *      methods={"POST"}
567
     * )
568
     *
569
     * @param Request $request
570
     * @param int     $id
571
     *
572
     * @return RedirectResponse
573
     *
574
     * @throws AccessDeniedException
575
     */
576
    public function duplicateAction(Request $request, $id)
577
    {
578
        $this->init($request);
579
        /* @var Node $parentNode */
580
        $originalNode = $this->em->getRepository(Node::class)
581
            ->find($id);
582
583
        // Check with Acl
584
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $originalNode);
585
586
        $request = $this->get('request_stack')->getCurrentRequest();
587
588
        $originalNodeTranslations = $originalNode->getNodeTranslation($this->locale, true);
589
        $originalRef = $originalNodeTranslations->getPublicNodeVersion()->getRef($this->em);
590
        $newPage = $this->get('kunstmaan_admin.clone.helper')
591
            ->deepCloneAndSave($originalRef);
592
593
        //set the title
594
        $title = $request->get('title');
595
        if (\is_string($title) && !empty($title)) {
596
            $newPage->setTitle($title);
597
        } else {
598
            $newPage->setTitle('New page');
599
        }
600
601
        //set the parent
602
        $parentNodeTranslation = $originalNode->getParent()->getNodeTranslation($this->locale, true);
603
        $parent = $parentNodeTranslation->getPublicNodeVersion()->getRef($this->em);
604
        $newPage->setParent($parent);
605
        $this->em->persist($newPage);
606
        $this->em->flush();
607
608
        /* @var Node $nodeNewPage */
609
        $nodeNewPage = $this->em->getRepository(Node::class)->createNodeFor(
0 ignored issues
show
Bug introduced by
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...
610
            $newPage,
611
            $this->locale,
612
            $this->user
613
        );
614
615
        $nodeTranslation = $nodeNewPage->getNodeTranslation($this->locale, true);
616
        if ($newPage->isStructureNode()) {
617
            $nodeTranslation->setSlug('');
618
            $this->em->persist($nodeTranslation);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $nodeNewPage->getNodeTra...on($this->locale, true) on line 615 can be null; however, Doctrine\ORM\EntityManager::persist() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
619
        }
620
        $this->em->flush();
621
622
        $this->aclManager->updateNodeAcl($originalNode, $nodeNewPage);
0 ignored issues
show
Documentation introduced by
$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...
623
624
        $this->addFlash(
625
            FlashTypes::SUCCESS,
626
            $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success')
627
        );
628
629
        return $this->redirect(
630
            $this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $nodeNewPage->getId()))
631
        );
632
    }
633
634
    /**
635
     * @Route(
636
     *      "/{id}/duplicate-with-children",
637
     *      requirements={"id" = "\d+"},
638
     *      name="KunstmaanNodeBundle_nodes_duplicate_with_children",
639
     *      methods={"POST"}
640
     * )
641
     *
642
     * @throws AccessDeniedException
643
     */
644
    public function duplicateWithChildrenAction(Request $request, $id)
645
    {
646
        if (!$this->getParameter('kunstmaan_node.show_duplicate_with_children')) {
647
            return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $id]);
648
        }
649
650
        $this->init($request);
651
        $title = $request->get('title', null);
652
653
        $nodeNewPage = $this->pageCloningHelper->duplicateWithChildren($id, $this->locale, $this->user, $title);
654
655
        $this->addFlash(FlashTypes::SUCCESS, $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success'));
656
657
        return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $nodeNewPage->getId()]);
658
    }
659
660
    /**
661
     * @Route(
662
     *      "/{id}/revert",
663
     *      requirements={"id" = "\d+"},
664
     *      defaults={"subaction" = "public"},
665
     *      name="KunstmaanNodeBundle_nodes_revert",
666
     *      methods={"GET"}
667
     * )
668
     *
669
     * @param Request $request
670
     * @param int     $id      The node id
671
     *
672
     * @return RedirectResponse
673
     *
674
     * @throws AccessDeniedException
675
     * @throws InvalidArgumentException
676
     */
677
    public function revertAction(Request $request, $id)
678
    {
679
        $this->init($request);
680
        /* @var Node $node */
681
        $node = $this->em->getRepository(Node::class)->find($id);
682
683
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
684
685
        $version = $request->get('version');
686
687
        if (empty($version) || !is_numeric($version)) {
688
            throw new InvalidArgumentException('No version was specified');
689
        }
690
691
        /* @var NodeVersionRepository $nodeVersionRepo */
692
        $nodeVersionRepo = $this->em->getRepository(NodeVersion::class);
693
        /* @var NodeVersion $nodeVersion */
694
        $nodeVersion = $nodeVersionRepo->find($version);
695
696
        if (\is_null($nodeVersion)) {
697
            throw new InvalidArgumentException('Version does not exist');
698
        }
699
700
        /* @var NodeTranslation $nodeTranslation */
701
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
702
        $page = $nodeVersion->getRef($this->em);
703
        /* @var HasNodeInterface $clonedPage */
704
        $clonedPage = $this->get('kunstmaan_admin.clone.helper')
705
            ->deepCloneAndSave($page);
706
        $newNodeVersion = $nodeVersionRepo->createNodeVersionFor(
707
            $clonedPage,
708
            $nodeTranslation,
709
            $this->user,
710
            $nodeVersion,
711
            'draft'
712
        );
713
714
        $nodeTranslation->setTitle($clonedPage->getTitle());
715
        $this->em->persist($nodeTranslation);
716
        $this->em->flush();
717
718
        $this->get('event_dispatcher')->dispatch(
719
            Events::REVERT,
720
            new RevertNodeAction(
721
                $node,
722
                $nodeTranslation,
723
                $newNodeVersion,
724
                $clonedPage,
725
                $nodeVersion,
726
                $page
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 702 can be null; however, Kunstmaan\NodeBundle\Eve...deAction::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
727
            )
728
        );
729
730
        $this->addFlash(
731
            FlashTypes::SUCCESS,
732
            $this->get('translator')->trans('kuma_node.admin.revert.flash.success')
733
        );
734
735
        return $this->redirect(
736
            $this->generateUrl(
737
                'KunstmaanNodeBundle_nodes_edit',
738
                array(
739
                    'id' => $id,
740
                    'subaction' => 'draft',
741
                )
742
            )
743
        );
744
    }
745
746
    /**
747
     * @Route(
748
     *      "/{id}/add",
749
     *      requirements={"id" = "\d+"},
750
     *      name="KunstmaanNodeBundle_nodes_add",
751
     *      methods={"POST"}
752
     * )
753
     *
754
     * @param Request $request
755
     * @param int     $id
756
     *
757
     * @return RedirectResponse
758
     *
759
     * @throws AccessDeniedException
760
     * @throws InvalidArgumentException
761
     */
762
    public function addAction(Request $request, $id)
763
    {
764
        $this->init($request);
765
        /* @var Node $parentNode */
766
        $parentNode = $this->em->getRepository(Node::class)->find($id);
767
768
        // Check with Acl
769
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parentNode);
770
771
        $parentNodeTranslation = $parentNode->getNodeTranslation($this->locale, true);
772
        $parentNodeVersion = $parentNodeTranslation->getPublicNodeVersion();
773
        $parentPage = $parentNodeVersion->getRef($this->em);
774
775
        $type = $this->validatePageType($request);
776
        $newPage = $this->createNewPage($request, $type);
777
        $newPage->setParent($parentPage);
778
779
        /* @var Node $nodeNewPage */
780
        $nodeNewPage = $this->em->getRepository(Node::class)
0 ignored issues
show
Bug introduced by
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...
781
            ->createNodeFor($newPage, $this->locale, $this->user);
782
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
783
            $this->locale,
784
            true
785
        );
786
        $weight = $this->em->getRepository(NodeTranslation::class)
0 ignored issues
show
Bug introduced by
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...
787
                ->getMaxChildrenWeight($parentNode, $this->locale) + 1;
788
        $nodeTranslation->setWeight($weight);
789
790
        if ($newPage->isStructureNode()) {
791
            $nodeTranslation->setSlug('');
792
        }
793
794
        $this->em->persist($nodeTranslation);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $nodeNewPage->getNodeTra...on($this->locale, true) on line 782 can be null; however, Doctrine\ORM\EntityManager::persist() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
795
        $this->em->flush();
796
797
        $this->aclManager->updateNodeAcl($parentNode, $nodeNewPage);
798
799
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
800
801
        $this->get('event_dispatcher')->dispatch(
802
            Events::ADD_NODE,
803
            new NodeEvent(
804
                $nodeNewPage, $nodeTranslation, $nodeVersion, $newPage
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $nodeNewPage->getNodeTra...on($this->locale, true) on line 782 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
805
            )
806
        );
807
808
        return $this->redirect(
809
            $this->generateUrl(
810
                'KunstmaanNodeBundle_nodes_edit',
811
                array('id' => $nodeNewPage->getId())
812
            )
813
        );
814
    }
815
816
    /**
817
     * @Route("/add-homepage", name="KunstmaanNodeBundle_nodes_add_homepage", methods={"POST"})
818
     *
819
     * @return RedirectResponse
820
     *
821
     * @throws AccessDeniedException
822
     * @throws InvalidArgumentException
823
     */
824
    public function addHomepageAction(Request $request)
825
    {
826
        $this->init($request);
827
828
        // Check with Acl
829
        $this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
830
831
        $type = $this->validatePageType($request);
832
833
        $newPage = $this->createNewPage($request, $type);
834
835
        /* @var Node $nodeNewPage */
836
        $nodeNewPage = $this->em->getRepository(Node::class)
0 ignored issues
show
Bug introduced by
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...
837
            ->createNodeFor($newPage, $this->locale, $this->user);
838
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
839
            $this->locale,
840
            true
841
        );
842
        $this->em->flush();
843
844
        // Set default permissions
845
        $this->container->get('kunstmaan_node.acl_permission_creator_service')
846
            ->createPermission($nodeNewPage);
847
848
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
849
850
        $this->get('event_dispatcher')->dispatch(
851
            Events::ADD_NODE,
852
            new NodeEvent(
853
                $nodeNewPage, $nodeTranslation, $nodeVersion, $newPage
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $nodeNewPage->getNodeTra...on($this->locale, true) on line 838 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
854
            )
855
        );
856
857
        return $this->redirect(
858
            $this->generateUrl(
859
                'KunstmaanNodeBundle_nodes_edit',
860
                array('id' => $nodeNewPage->getId())
861
            )
862
        );
863
    }
864
865
    /**
866
     * @Route("/reorder", name="KunstmaanNodeBundle_nodes_reorder", methods={"POST"})
867
     *
868
     * @param Request $request
869
     *
870
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be JsonResponse?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
871
     *
872
     * @throws AccessDeniedException
873
     */
874
    public function reorderAction(Request $request)
875
    {
876
        $this->init($request);
877
        $nodes = array();
878
        $nodeIds = $request->get('nodes');
879
        $changeParents = $request->get('parent');
880
881
        foreach ($nodeIds as $id) {
882
            /* @var Node $node */
883
            $node = $this->em->getRepository(Node::class)->find($id);
884
            $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
885
            $nodes[] = $node;
886
        }
887
888
        $weight = 1;
889
        foreach ($nodes as $node) {
890
            $newParentId = isset($changeParents[$node->getId()]) ? $changeParents[$node->getId()] : null;
891
            if ($newParentId) {
892
                $parent = $this->em->getRepository(Node::class)->find($newParentId);
893
                $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parent);
894
                $node->setParent($parent);
895
                $this->em->persist($node);
896
                $this->em->flush($node);
897
            }
898
899
            /* @var NodeTranslation $nodeTranslation */
900
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
901
902
            if ($nodeTranslation) {
903
                $nodeVersion = $nodeTranslation->getPublicNodeVersion();
904
                $page = $nodeVersion->getRef($this->em);
905
906
                $this->get('event_dispatcher')->dispatch(
907
                    Events::PRE_PERSIST,
908
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 904 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
909
                );
910
911
                $nodeTranslation->setWeight($weight);
912
                $this->em->persist($nodeTranslation);
913
                $this->em->flush($nodeTranslation);
914
915
                $this->get('event_dispatcher')->dispatch(
916
                    Events::POST_PERSIST,
917
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 904 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
918
                );
919
920
                ++$weight;
921
            }
922
        }
923
924
        return new JsonResponse(
925
            array(
926
                'Success' => 'The node-translations for [' . $this->locale . '] have got new weight values',
927
            )
928
        );
929
    }
930
931
    /**
932
     * @Route(
933
     *      "/{id}/{subaction}",
934
     *      requirements={"id" = "\d+"},
935
     *      defaults={"subaction" = "public"},
936
     *      name="KunstmaanNodeBundle_nodes_edit",
937
     *      methods={"GET", "POST"}
938
     * )
939
     * @Template("@KunstmaanNode/NodeAdmin/edit.html.twig")
940
     *
941
     * @param Request $request
942
     * @param int     $id        The node id
943
     * @param string  $subaction The subaction (draft|public)
944
     *
945
     * @return RedirectResponse|array
0 ignored issues
show
Documentation introduced by
Should the return type not be \Symfony\Component\HttpFoundation\Response|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
946
     *
947
     * @throws AccessDeniedException
948
     */
949
    public function editAction(Request $request, $id, $subaction)
950
    {
951
        $this->init($request);
952
        /* @var Node $node */
953
        $node = $this->em->getRepository(Node::class)->find($id);
954
955
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
956
957
        $tabPane = new TabPane(
958
            'todo',
959
            $request,
960
            $this->container->get('form.factory')
0 ignored issues
show
Documentation introduced by
$this->container->get('form.factory') is of type object|null, but the function expects a object<Symfony\Component...m\FormFactoryInterface>.

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...
961
        );
962
963
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
964
        if (!$nodeTranslation) {
965
            return $this->renderNodeNotTranslatedPage($node);
966
        }
967
968
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
969
        $draftNodeVersion = $nodeTranslation->getDraftNodeVersion();
970
        $nodeVersionIsLocked = false;
971
972
        /* @var HasNodeInterface $page */
973
        $page = null;
0 ignored issues
show
Unused Code introduced by
$page is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
974
        $draft = ($subaction == 'draft');
975
        $saveAsDraft = $request->get('saveasdraft');
976
        if ((!$draft && !empty($saveAsDraft)) || ($draft && \is_null($draftNodeVersion))) {
977
            // Create a new draft version
978
            $draft = true;
979
            $subaction = 'draft';
980
            $page = $nodeVersion->getRef($this->em);
981
            $nodeVersion = $this->createDraftVersion(
982
                $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 980 can be null; however, Kunstmaan\NodeBundle\Con...r::createDraftVersion() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
983
                $nodeTranslation,
984
                $nodeVersion
985
            );
986
            $draftNodeVersion = $nodeVersion;
987
        } elseif ($draft) {
988
            $nodeVersion = $draftNodeVersion;
989
            $page = $nodeVersion->getRef($this->em);
990
        } else {
991
            if (!empty($request->request->get('undo_delete'))) {
992
                $node->setDeleted(false);
993
994
                $this->em->persist($node);
995
                $this->em->flush();
996
            }
997
998
            if ($request->getMethod() == 'POST') {
999
                $nodeVersionIsLocked = $this->isNodeVersionLocked($nodeTranslation, true);
1000
1001
                //Check the version timeout and make a new nodeversion if the timeout is passed
1002
                $thresholdDate = date(
1003
                    'Y-m-d H:i:s',
1004
                    time() - $this->getParameter(
1005
                        'kunstmaan_node.version_timeout'
1006
                    )
1007
                );
1008
                $updatedDate = date(
1009
                    'Y-m-d H:i:s',
1010
                    strtotime($nodeVersion->getUpdated()->format('Y-m-d H:i:s'))
1011
                );
1012 View Code Duplication
                if ($thresholdDate >= $updatedDate || $nodeVersionIsLocked) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
1013
                    $page = $nodeVersion->getRef($this->em);
1014
                    if ($nodeVersion === $nodeTranslation->getPublicNodeVersion()) {
1015
                        $this->nodePublisher
1016
                            ->createPublicVersion(
1017
                                $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 1013 can be null; however, Kunstmaan\NodeBundle\Hel...::createPublicVersion() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1018
                                $nodeTranslation,
1019
                                $nodeVersion,
1020
                                $this->user
1021
                            );
1022
                    } else {
1023
                        $this->createDraftVersion(
1024
                            $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 1013 can be null; however, Kunstmaan\NodeBundle\Con...r::createDraftVersion() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1025
                            $nodeTranslation,
1026
                            $nodeVersion
1027
                        );
1028
                    }
1029
                }
1030
            }
1031
            $page = $nodeVersion->getRef($this->em);
1032
        }
1033
        $isStructureNode = $page->isStructureNode();
1034
1035
        $menubuilder = $this->get('kunstmaan_node.actions_menu_builder');
1036
        $menubuilder->setActiveNodeVersion($nodeVersion);
1037
        $menubuilder->setEditableNode(!$isStructureNode);
1038
1039
        // Building the form
1040
        $propertiesWidget = new FormWidget();
1041
        $propertiesWidget->addType('main', $page->getDefaultAdminType(), $page);
1042
        $propertiesWidget->addType('node', $node->getDefaultAdminType(), $node);
1043
        $tabPane->addTab(new Tab('kuma_node.tab.properties.title', $propertiesWidget));
1044
1045
        // Menu tab
1046
        $menuWidget = new FormWidget();
1047
        $menuWidget->addType(
1048
            'menunodetranslation',
1049
            NodeMenuTabTranslationAdminType::class,
1050
            $nodeTranslation,
1051
            ['slugable' => !$isStructureNode]
1052
        );
1053
        $menuWidget->addType('menunode', NodeMenuTabAdminType::class, $node, ['available_in_nav' => !$isStructureNode]);
1054
        $tabPane->addTab(new Tab('kuma_node.tab.menu.title', $menuWidget));
1055
1056
        $this->get('event_dispatcher')->dispatch(
1057
            Events::ADAPT_FORM,
1058
            new AdaptFormEvent(
1059
                $request,
1060
                $tabPane,
1061
                $page,
1062
                $node,
1063
                $nodeTranslation,
1064
                $nodeVersion
1065
            )
1066
        );
1067
1068
        $tabPane->buildForm();
1069
1070
        if ($request->getMethod() == 'POST') {
1071
            $tabPane->bindRequest($request);
1072
1073
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
1074
            if ($tabPane->isValid() && !$request->isXmlHttpRequest()) {
1075
                $this->get('event_dispatcher')->dispatch(
1076
                    Events::PRE_PERSIST,
1077
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 988 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1078
                );
1079
1080
                $nodeTranslation->setTitle($page->getTitle());
1081
                if ($isStructureNode) {
1082
                    $nodeTranslation->setSlug('');
1083
                }
1084
                $nodeVersion->setUpdated(new DateTime());
1085
                if ($nodeVersion->getType() == 'public') {
1086
                    $nodeTranslation->setUpdated($nodeVersion->getUpdated());
1087
                }
1088
                $this->em->persist($nodeTranslation);
1089
                $this->em->persist($nodeVersion);
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 988 can be null; however, Doctrine\ORM\EntityManager::persist() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1090
                $tabPane->persist($this->em);
1091
                $this->em->flush();
1092
1093
                $this->get('event_dispatcher')->dispatch(
1094
                    Events::POST_PERSIST,
1095
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 988 can be null; however, Kunstmaan\NodeBundle\Eve...odeEvent::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1096
                );
1097
1098
                if ($nodeVersionIsLocked) {
1099
                    $this->addFlash(
1100
                        FlashTypes::SUCCESS,
1101
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.locked_success')
1102
                    );
1103
                } elseif ($request->request->has('publishing') || $request->request->has('publish_later')) {
1104
                    $this->nodePublisher->chooseHowToPublish($request, $nodeTranslation, $this->translator);
1105
                } elseif ($request->request->has('unpublishing') || $request->request->has('unpublish_later')) {
1106
                    $this->nodePublisher->chooseHowToUnpublish($request, $nodeTranslation, $this->translator);
1107
                } else {
1108
                    $this->addFlash(
1109
                        FlashTypes::SUCCESS,
1110
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.success')
1111
                    );
1112
                }
1113
1114
                $params = [
1115
                    'id' => $node->getId(),
1116
                    'subaction' => $subaction,
1117
                    'currenttab' => $tabPane->getActiveTab(),
1118
                ];
1119
                $params = array_merge(
1120
                    $params,
1121
                    $tabPane->getExtraParams($request)
1122
                );
1123
1124
                if ($subaction === 'draft' && ($request->request->has('publishing') || $request->request->has('publish_later'))) {
1125
                    unset($params['subaction']);
1126
                }
1127
1128
                return $this->redirect(
1129
                    $this->generateUrl(
1130
                        'KunstmaanNodeBundle_nodes_edit',
1131
                        $params
1132
                    )
1133
                );
1134
            }
1135
        }
1136
1137
        $nodeVersions = $this->em->getRepository(NodeVersion::class)->findBy(
1138
            ['nodeTranslation' => $nodeTranslation],
1139
            ['updated' => 'ASC']
1140
        );
1141
        $queuedNodeTranslationAction = $this->em->getRepository(QueuedNodeTranslationAction::class)->findOneBy(['nodeTranslation' => $nodeTranslation]);
1142
1143
        return [
1144
            'page' => $page,
1145
            'entityname' => ClassLookup::getClass($page),
1146
            'nodeVersions' => $nodeVersions,
1147
            'node' => $node,
1148
            'nodeTranslation' => $nodeTranslation,
1149
            'draft' => $draft,
1150
            'draftNodeVersion' => $draftNodeVersion,
1151
            'showDuplicateWithChildren' => $this->getParameter('kunstmaan_node.show_duplicate_with_children'),
1152
            'nodeVersion' => $nodeVersion,
1153
            'subaction' => $subaction,
1154
            'tabPane' => $tabPane,
1155
            'editmode' => true,
1156
            'childCount' => $this->em->getRepository('KunstmaanNodeBundle:Node')->getChildCount($node),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method getChildCount() 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...
1157
            'queuedNodeTranslationAction' => $queuedNodeTranslationAction,
1158
            'nodeVersionLockCheck' => $this->container->getParameter('kunstmaan_node.lock_enabled'),
1159
            'nodeVersionLockInterval' => $this->container->getParameter('kunstmaan_node.lock_check_interval'),
1160
        ];
1161
    }
1162
1163
    /**
1164
     * @Route(
1165
     *      "checkNodeVersionLock/{id}/{public}",
1166
     *      requirements={"id" = "\d+", "public" = "(0|1)"},
1167
     *      name="KunstmaanNodeBundle_nodes_versionlock_check"
1168
     * )
1169
     *
1170
     * @param Request $request
1171
     * @param $id
1172
     *
1173
     * @return JsonResponse
1174
     */
1175
    public function checkNodeVersionLockAction(Request $request, $id, $public)
1176
    {
1177
        $nodeVersionIsLocked = false;
1178
        $message = '';
1179
        $this->init($request);
1180
1181
        /* @var Node $node */
1182
        $node = $this->em->getRepository(Node::class)->find($id);
1183
1184
        try {
1185
            $this->checkPermission($node, PermissionMap::PERMISSION_EDIT);
1186
1187
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1188
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1189
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
1190
1191
            if ($nodeTranslation) {
1192
                $nodeVersionIsLocked = $nodeVersionLockHelper->isNodeVersionLocked($this->getUser(), $nodeTranslation, $public);
0 ignored issues
show
Documentation introduced by
$this->getUser() is of type null|object, but the function expects a object<Kunstmaan\AdminBundle\Entity\BaseUser>.

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...
1193
1194
                if ($nodeVersionIsLocked) {
1195
                    $users = $nodeVersionLockHelper->getUsersWithNodeVersionLock($nodeTranslation, $public, $this->getUser());
1196
                    $message = $this->get('translator')->trans('kuma_node.admin.edit.flash.locked', array('%users%' => implode(', ', $users)));
1197
                }
1198
            }
1199
        } catch (AccessDeniedException $ade) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1200
        }
1201
1202
        return new JsonResponse(['lock' => $nodeVersionIsLocked, 'message' => $message]);
1203
    }
1204
1205
    /**
1206
     * @param NodeTranslation $nodeTranslation
1207
     * @param bool            $isPublic
1208
     *
1209
     * @return bool
1210
     */
1211
    private function isNodeVersionLocked(NodeTranslation $nodeTranslation, $isPublic)
1212
    {
1213
        if ($this->container->getParameter('kunstmaan_node.lock_enabled')) {
1214
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1215
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1216
            $nodeVersionIsLocked = $nodeVersionLockHelper->isNodeVersionLocked($this->getUser(), $nodeTranslation, $isPublic);
0 ignored issues
show
Documentation introduced by
$this->getUser() is of type null|object, but the function expects a object<Kunstmaan\AdminBundle\Entity\BaseUser>.

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...
1217
1218
            return $nodeVersionIsLocked;
1219
        }
1220
1221
        return false;
1222
    }
1223
1224
    /**
1225
     * @param HasNodeInterface $page            The page
1226
     * @param NodeTranslation  $nodeTranslation The node translation
1227
     * @param NodeVersion      $nodeVersion     The node version
1228
     *
1229
     * @return NodeVersion
1230
     */
1231
    private function createDraftVersion(
1232
        HasNodeInterface $page,
1233
        NodeTranslation $nodeTranslation,
1234
        NodeVersion $nodeVersion
1235
    ) {
1236
        $publicPage = $this->get('kunstmaan_admin.clone.helper')
1237
            ->deepCloneAndSave($page);
1238
        /* @var NodeVersion $publicNodeVersion */
1239
1240
        $publicNodeVersion = $this->em->getRepository(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeVersionFor() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Rep...y\NodeVersionRepository.

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...
1241
            NodeVersion::class
1242
        )->createNodeVersionFor(
1243
            $publicPage,
1244
            $nodeTranslation,
1245
            $this->user,
1246
            $nodeVersion->getOrigin(),
1247
            'public',
1248
            $nodeVersion->getCreated()
1249
        );
1250
1251
        $nodeTranslation->setPublicNodeVersion($publicNodeVersion);
1252
        $nodeVersion->setType('draft');
1253
        $nodeVersion->setOrigin($publicNodeVersion);
1254
        $nodeVersion->setCreated(new DateTime());
1255
1256
        $this->em->persist($nodeTranslation);
1257
        $this->em->persist($nodeVersion);
1258
        $this->em->flush();
1259
1260
        $this->get('event_dispatcher')->dispatch(
1261
            Events::CREATE_DRAFT_VERSION,
1262
            new NodeEvent(
1263
                $nodeTranslation->getNode(),
1264
                $nodeTranslation,
1265
                $nodeVersion,
1266
                $page
1267
            )
1268
        );
1269
1270
        return $nodeVersion;
1271
    }
1272
1273
    /**
1274
     * @param Node   $node       The node
1275
     * @param string $permission The permission to check for
1276
     *
1277
     * @throws AccessDeniedException
1278
     */
1279
    private function checkPermission(Node $node, $permission)
1280
    {
1281
        if (false === $this->authorizationChecker->isGranted($permission, $node)) {
1282
            throw new AccessDeniedException();
1283
        }
1284
    }
1285
1286
    /**
1287
     * @param EntityManager   $em       The Entity Manager
1288
     * @param BaseUser        $user     The user who deletes the children
1289
     * @param string          $locale   The locale that was used
1290
     * @param ArrayCollection $children The children array
1291
     */
1292
    private function deleteNodeChildren(
1293
        EntityManager $em,
1294
        BaseUser $user,
1295
        $locale,
1296
        ArrayCollection $children
1297
    ) {
1298
        /* @var Node $childNode */
1299
        foreach ($children as $childNode) {
1300
            $childNodeTranslation = $childNode->getNodeTranslation(
1301
                $this->locale,
1302
                true
1303
            );
1304
1305
            $childNodeVersion = $childNodeTranslation->getPublicNodeVersion();
1306
            $childNodePage = $childNodeVersion->getRef($this->em);
1307
1308
            $this->get('event_dispatcher')->dispatch(
1309
                Events::PRE_DELETE,
1310
                new NodeEvent(
1311
                    $childNode,
1312
                    $childNodeTranslation,
1313
                    $childNodeVersion,
1314
                    $childNodePage
1315
                )
1316
            );
1317
1318
            $childNode->setDeleted(true);
1319
            $this->em->persist($childNode);
1320
1321
            $children2 = $childNode->getChildren();
1322
            $this->deleteNodeChildren($em, $user, $locale, $children2);
1323
1324
            $this->get('event_dispatcher')->dispatch(
1325
                Events::POST_DELETE,
1326
                new NodeEvent(
1327
                    $childNode,
1328
                    $childNodeTranslation,
1329
                    $childNodeVersion,
1330
                    $childNodePage
1331
                )
1332
            );
1333
        }
1334
    }
1335
1336
    /**
1337
     * @param Node $node
1338
     *
1339
     * @return void
1340
     */
1341
    private function undoDeleteNode(
1342
        Node $node
1343
    ) {
1344
        $this->denyAccessUnlessGranted(
1345
            PermissionMap::PERMISSION_DELETE,
1346
            $node
1347
        );
1348
1349
        $node->setDeleted(false);
1350
1351
        $this->em->persist($node);
1352
1353
        foreach ($node->getChildren() as $child) {
1354
            $this->undoDeleteNode($child);
1355
        }
1356
    }
1357
1358
    /**
1359
     * @param Request $request
1360
     * @param string  $type
1361
     *
1362
     * @return HasNodeInterface
1363
     */
1364
    private function createNewPage(Request $request, $type)
1365
    {
1366
        /* @var HasNodeInterface $newPage */
1367
        $newPage = new $type();
1368
1369
        $title = $request->get('title');
1370
        if (\is_string($title) && !empty($title)) {
1371
            $newPage->setTitle($title);
1372
        } else {
1373
            $newPage->setTitle($this->get('translator')->trans('kuma_node.admin.new_page.title.default'));
1374
        }
1375
        $this->em->persist($newPage);
1376
        $this->em->flush();
1377
1378
        return $newPage;
1379
    }
1380
1381
    /**
1382
     * @param Request $request
1383
     *
1384
     * @return string
1385
     * @throw InvalidArgumentException
1386
     */
1387
    private function validatePageType($request)
1388
    {
1389
        $type = $request->get('type');
1390
1391
        if (empty($type)) {
1392
            throw new InvalidArgumentException('Please specify a type of page you want to create');
1393
        }
1394
1395
        return $type;
1396
    }
1397
1398
    /**
1399
     * @param Node $node
1400
     *
1401
     * @return \Symfony\Component\HttpFoundation\Response
1402
     */
1403
    private function renderNodeNotTranslatedPage(Node $node)
1404
    {
1405
        //try to find a parent node with the correct translation, if there is none allow copy.
1406
        //if there is a parent but it doesn't have the language to copy to don't allow it
1407
        $parentNode = $node->getParent();
1408
        if ($parentNode) {
1409
            $parentNodeTranslation = $parentNode->getNodeTranslation(
1410
                $this->locale,
1411
                true
1412
            );
1413
            $parentsAreOk = false;
1414
1415
            if ($parentNodeTranslation) {
1416
                $parentsAreOk = $this->em->getRepository(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method hasParentNodeTranslationsForLanguage() 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...
1417
                    NodeTranslation::class
1418
                )->hasParentNodeTranslationsForLanguage(
1419
                    $node->getParent()->getNodeTranslation(
1420
                        $this->locale,
1421
                        true
1422
                    ),
1423
                    $this->locale
1424
                );
1425
            }
1426
        } else {
1427
            $parentsAreOk = true;
1428
        }
1429
1430
        return $this->render(
1431
            '@KunstmaanNode/NodeAdmin/pagenottranslated.html.twig',
1432
            array(
1433
                'node' => $node,
1434
                'nodeTranslations' => $node->getNodeTranslations(
1435
                    true
1436
                ),
1437
                'copyfromotherlanguages' => $parentsAreOk,
1438
            )
1439
        );
1440
    }
1441
1442
    /**
1443
     * @param Request $request
1444
     * @var NodeAdminListConfigurator $nodeAdminListConfigurator
1445
     *
1446
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,AdminList>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1447
     */
1448
    private function renderAdminList(
1449
        Request $request,
1450
        NodeAdminListConfigurator $nodeAdminListConfigurator
1451
    ) {
1452
        /** @var AdminList $adminList */
1453
        $adminList = $this->get('kunstmaan_adminlist.factory')->createList($nodeAdminListConfigurator);
1454
        $adminList->bindRequest($request);
1455
1456
        return [
1457
            'adminlist' => $adminList,
1458
        ];
1459
    }
1460
}
1461