Completed
Pull Request — master (#2706)
by
unknown
93:08 queued 86:33
created

NodeAdminController::deletedNodesAction()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 51

Duplication

Lines 13
Ratio 25.49 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 13
loc 51
ccs 0
cts 45
cp 0
rs 9.069
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 12

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\EventDispatcher\LegacyEventDispatcherProxy;
43
use Symfony\Component\HttpFoundation\JsonResponse;
44
use Symfony\Component\HttpFoundation\RedirectResponse;
45
use Symfony\Component\HttpFoundation\Request;
46
use Symfony\Component\Routing\Annotation\Route;
47
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
48
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
49
use Symfony\Component\Translation\TranslatorInterface;
50
51
/**
52
 * NodeAdminController
53
 */
54
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...
55
{
56
    /**
57
     * @var EntityManager
58
     */
59
    protected $em;
60
61
    /**
62
     * @var string
63
     */
64
    protected $locale;
65
66
    /**
67
     * @var AuthorizationCheckerInterface
68
     */
69
    protected $authorizationChecker;
70
71
    /**
72
     * @var BaseUser
73
     */
74
    protected $user;
75
76
    /**
77
     * @var AclHelper
78
     */
79
    protected $aclHelper;
80
81
    /**
82
     * @var AclManager
83
     */
84
    protected $aclManager;
85
86
    /**
87
     * @var NodeAdminPublisher
88
     */
89
    protected $nodePublisher;
90
91
    /**
92
     * @var TranslatorInterface
93
     */
94
    protected $translator;
95
96
    /**
97
     * @var PageCloningHelper
98
     */
99
    private $pageCloningHelper;
100
101
    /**
102
     * @var bool
103
     */
104
    private $isUndoDeletingNodesEnabled;
105
106
    /**
107
     * init
108
     *
109
     * @param Request $request
110
     */
111
    protected function init(Request $request)
112
    {
113
        $this->em = $this->getDoctrine()->getManager();
114
        $this->locale = $request->getLocale();
115
        $this->authorizationChecker = $this->container->get('security.authorization_checker');
116
        $this->user = $this->getUser();
117
        $this->aclHelper = $this->container->get('kunstmaan_admin.acl.helper');
118
        $this->aclManager = $this->container->get('kunstmaan_admin.acl.manager');
119
        $this->nodePublisher = $this->container->get('kunstmaan_node.admin_node.publisher');
120
        $this->translator = $this->container->get('translator');
121
        $this->pageCloningHelper = $this->container->get(PageCloningHelper::class);
122
        $this->isUndoDeletingNodesEnabled = $this->container->getParameter(
123
            'kunstmaan_node.kunstmaan_node.enable_undo_deleting_nodes'
124
        );
125
    }
126
127
    /**
128
     * @Route("/", name="KunstmaanNodeBundle_nodes")
129
     * @Template("@KunstmaanNode/Admin/list.html.twig")
130
     *
131
     * @param Request $request
132
     *
133
     * @return array
134
     */
135
    public function indexAction(Request $request)
136
    {
137
        $this->init($request);
138
139
        $nodeAdminListConfigurator = new NodeAdminListConfigurator(
140
            $this->em,
141
            $this->aclHelper,
142
            $this->locale,
143
            PermissionMap::PERMISSION_VIEW,
144
            $this->authorizationChecker
145
        );
146
147
        $locale = $this->locale;
148
        $acl = $this->authorizationChecker;
149 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...
150
            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...
151
                return array(
152
                    'path' => '_slug_preview',
153
                    '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...
154
                );
155
            }
156
157
            return null;
158
        };
159
160
        $nodeAdminListConfigurator->addSimpleItemAction('action.preview', $itemRoute, 'eye');
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
        $this->addViewDeletedNodesAction($nodeAdminListConfigurator);
167
168
        return $this->renderAdminList($request, $nodeAdminListConfigurator);
169
    }
170
171
    private function addViewDeletedNodesAction(NodeAdminListConfigurator $nodeAdminListConfigurator): void
172
    {
173
        if (!$this->isUndoDeletingNodesEnabled) {
174
            return;
175
        }
176
177
        $nodeAdminListConfigurator->addListAction(
178
            new SimpleListAction(
179
                [
180
                    'path' => 'KunstmaanNodeBundle_deleted_nodes',
181
                    'params' => [],
182
                ],
183
                'deleted_pages.view_action',
184
                null,
185
                '@KunstmaanAdmin/Settings/button_resolve_all.html.twig'
186
            )
187
        );
188
    }
189
190
    /**
191
     * @Route(
192
     *      "/{id}/copyfromotherlanguage",
193
     *      requirements={"id" = "\d+"},
194
     *      name="KunstmaanNodeBundle_nodes_copyfromotherlanguage",
195
     *      methods={"GET"}
196
     * )
197
     *
198
     * @param Request $request
199
     * @param int     $id      The node id
200
     *
201
     * @return RedirectResponse
202
     *
203
     * @throws AccessDeniedException
204
     */
205
    public function copyFromOtherLanguageAction(Request $request, $id)
206
    {
207
        $this->init($request);
208
        /* @var Node $node */
209
        $node = $this->em->getRepository(Node::class)->find($id);
210
211
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
212
213
        $originalLanguage = $request->get('originallanguage');
214
        $otherLanguageNodeTranslation = $node->getNodeTranslation($originalLanguage, true);
215
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
216
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
217
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
218
            ->deepCloneAndSave($otherLanguagePage);
219
220
        /* @var NodeTranslation $nodeTranslation */
221
        $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...
222
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
223
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
224
225
        $this->dispatch(
226
            new CopyPageTranslationNodeEvent(
227
                $node,
228
                $nodeTranslation,
229
                $nodeVersion,
230
                $myLanguagePage,
231
                $otherLanguageNodeTranslation,
0 ignored issues
show
Bug introduced by
It seems like $otherLanguageNodeTranslation defined by $node->getNodeTranslatio...originalLanguage, true) on line 214 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...
232
                $otherLanguageNodeNodeVersion,
233
                $otherLanguagePage,
234
                $originalLanguage
235
            ),
236
            Events::COPY_PAGE_TRANSLATION
237
        );
238
239
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
240
    }
241
242
    /**
243
     * @Route(
244
     *      "/{id}/recopyfromotherlanguage",
245
     *      requirements={"id" = "\d+"},
246
     *      name="KunstmaanNodeBundle_nodes_recopyfromotherlanguage",
247
     *      methods={"POST"}
248
     * )
249
     *
250
     * @param Request $request
251
     * @param int     $id      The node id
252
     *
253
     * @return RedirectResponse
254
     *
255
     * @throws AccessDeniedException
256
     */
257
    public function recopyFromOtherLanguageAction(Request $request, $id)
258
    {
259
        $this->init($request);
260
        /* @var Node $node */
261
        $node = $this->em->getRepository(Node::class)->find($id);
262
263
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
264
265
        $otherLanguageNodeTranslation = $this->em->getRepository(NodeTranslation::class)->find($request->get('source'));
266
        $otherLanguageNodeNodeVersion = $otherLanguageNodeTranslation->getPublicNodeVersion();
267
        $otherLanguagePage = $otherLanguageNodeNodeVersion->getRef($this->em);
268
        $myLanguagePage = $this->get('kunstmaan_admin.clone.helper')
269
            ->deepCloneAndSave($otherLanguagePage);
270
271
        /* @var NodeTranslation $nodeTranslation */
272
        $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...
273
            ->addDraftNodeVersionFor($myLanguagePage, $this->locale, $node, $this->user);
274
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
275
276
        $this->dispatch(
277
            new RecopyPageTranslationNodeEvent(
278
                $node,
279
                $nodeTranslation,
280
                $nodeVersion,
281
                $myLanguagePage,
282
                $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...
283
                $otherLanguageNodeNodeVersion,
284
                $otherLanguagePage,
285
                $otherLanguageNodeTranslation->getLang()
286
            ),
287
            Events::RECOPY_PAGE_TRANSLATION
288
        );
289
290
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id, 'subaction' => NodeVersion::DRAFT_VERSION)));
291
    }
292
293
    /**
294
     * @Route(
295
     *      "/{id}/createemptypage",
296
     *      requirements={"id" = "\d+"},
297
     *      name="KunstmaanNodeBundle_nodes_createemptypage",
298
     *      methods={"GET"}
299
     * )
300
     *
301
     * @param Request $request
302
     * @param int     $id
303
     *
304
     * @return RedirectResponse
305
     *
306
     * @throws AccessDeniedException
307
     */
308
    public function createEmptyPageAction(Request $request, $id)
309
    {
310
        $this->init($request);
311
        /* @var Node $node */
312
        $node = $this->em->getRepository(Node::class)->find($id);
313
314
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
315
316
        $entityName = $node->getRefEntityName();
317
        /* @var HasNodeInterface $myLanguagePage */
318
        $myLanguagePage = new $entityName();
319
        $myLanguagePage->setTitle('New page');
320
321
        $this->em->persist($myLanguagePage);
322
        $this->em->flush();
323
        /* @var NodeTranslation $nodeTranslation */
324
        $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...
325
            ->createNodeTranslationFor($myLanguagePage, $this->locale, $node, $this->user);
326
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
327
328
        $this->dispatch(
329
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $myLanguagePage),
330
            Events::ADD_EMPTY_PAGE_TRANSLATION
331
        );
332
333
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
334
    }
335
336
    /**
337
     * @Route("/{id}/publish", requirements={"id" =
338
     *                         "\d+"},
339
     *                         name="KunstmaanNodeBundle_nodes_publish", methods={"GET", "POST"})
340
     *
341
     * @param Request $request
342
     * @param int     $id
343
     *
344
     * @return RedirectResponse
345
     *
346
     * @throws AccessDeniedException
347
     */
348 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...
349
    {
350
        $this->init($request);
351
        /* @var Node $node */
352
        $node = $this->em->getRepository(Node::class)->find($id);
353
354
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
355
        $request = $this->get('request_stack')->getCurrentRequest();
356
        $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 354 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...
357
358
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
359
    }
360
361
    /**
362
     * @Route(
363
     *      "/{id}/unpublish",
364
     *      requirements={"id" = "\d+"},
365
     *      name="KunstmaanNodeBundle_nodes_unpublish",
366
     *      methods={"GET", "POST"}
367
     * )
368
     *
369
     * @param Request $request
370
     * @param int     $id
371
     *
372
     * @return RedirectResponse
373
     *
374
     * @throws AccessDeniedException
375
     */
376 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...
377
    {
378
        $this->init($request);
379
        /* @var Node $node */
380
        $node = $this->em->getRepository(Node::class)->find($id);
381
382
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
383
        $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 382 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...
384
385
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $node->getId())));
386
    }
387
388
    /**
389
     * @Route(
390
     *      "/{id}/unschedulepublish",
391
     *      requirements={"id" = "\d+"},
392
     *      name="KunstmaanNodeBundle_nodes_unschedule_publish",
393
     *      methods={"GET", "POST"}
394
     * )
395
     *
396
     * @param Request $request
397
     * @param int     $id
398
     *
399
     * @return RedirectResponse
400
     *
401
     * @throws AccessDeniedException
402
     */
403 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...
404
    {
405
        $this->init($request);
406
407
        /* @var Node $node */
408
        $node = $this->em->getRepository(Node::class)->find($id);
409
410
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
411
        $this->nodePublisher->unSchedulePublish($nodeTranslation);
0 ignored issues
show
Bug introduced by
It seems like $nodeTranslation defined by $node->getNodeTranslation($this->locale, true) on line 410 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...
412
413
        $this->addFlash(
414
            FlashTypes::SUCCESS,
415
            $this->get('translator')->trans('kuma_node.admin.unschedule.flash.success')
416
        );
417
418
        return $this->redirect($this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $id)));
419
    }
420
421
    /**
422
     * @Route(
423
     *      "/{id}/delete",
424
     *      requirements={"id" = "\d+"},
425
     *      name="KunstmaanNodeBundle_nodes_delete",
426
     *      methods={"POST"}
427
     * )
428
     *
429
     * @param Request $request
430
     * @param int     $id
431
     *
432
     * @return RedirectResponse
433
     *
434
     * @throws AccessDeniedException
435
     */
436
    public function deleteAction(Request $request, $id)
437
    {
438
        $this->init($request);
439
        /* @var Node $node */
440
        $node = $this->em->getRepository(Node::class)->find($id);
441
442
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_DELETE, $node);
443
444
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
445
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
446
        $page = $nodeVersion->getRef($this->em);
447
448
        $this->dispatch(
449
            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 444 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...
450
            Events::PRE_DELETE
451
        );
452
453
        $node->setDeleted(true);
454
        $this->em->persist($node);
455
456
        $children = $node->getChildren();
457
        $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 456 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...
458
        $this->em->flush();
459
460
        $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 444 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...
461
        $this->dispatch($event, Events::POST_DELETE);
462
        if (null === $response = $event->getResponse()) {
463
            $nodeParent = $node->getParent();
464
            // Check if we have a parent. Otherwise redirect to pages overview.
465
            if ($nodeParent) {
466
                $url = $this->get('router')->generate(
467
                    'KunstmaanNodeBundle_nodes_edit',
468
                    array('id' => $nodeParent->getId())
469
                );
470
            } else {
471
                $url = $this->get('router')->generate(
472
                    'KunstmaanNodeBundle_nodes'
473
                );
474
            }
475
            $response = new RedirectResponse($url);
476
        }
477
478
        $this->addFlash(
479
            FlashTypes::SUCCESS,
480
            $this->get('translator')->trans('kuma_node.admin.delete.flash.success')
481
        );
482
483
        return $response;
484
    }
485
486
    /**
487
     * @Route("/deleted", name="KunstmaanNodeBundle_deleted_nodes")
488
     * @Template("@KunstmaanNode/Admin/deleted_list.html.twig")
489
     */
490
    public function deletedNodesAction(Request $request): array
491
    {
492
        $this->init($request);
493
494
        if (!$this->isUndoDeletingNodesEnabled) {
495
            throw $this->createAccessDeniedException();
496
        }
497
498
        $nodeAdminListConfigurator = new DeletedNodeAdminListConfigurator(
499
            $this->em,
500
            $this->aclHelper,
501
            $this->locale,
502
            PermissionMap::PERMISSION_DELETE,
503
            $this->authorizationChecker
504
        );
505
        $nodeAdminListConfigurator->addListAction(
506
            new SimpleListAction(
507
                [
508
                    'path' => 'KunstmaanNodeBundle_nodes',
509
                    'params' => [],
510
                ],
511
                'pages.view_action',
512
                null,
513
                '@KunstmaanAdmin/Settings/button_resolve_all.html.twig'
514
            )
515
        );
516
        $nodeAdminListConfigurator->setDomainConfiguration($this->get('kunstmaan_admin.domain_configuration'));
517
        $locale = $this->locale;
518
        $acl = $this->authorizationChecker;
519
520
        $nodeAdminListConfigurator->addSimpleItemAction(
521
            'action.undo_delete',
522 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...
523
                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...
524
                    return [
525
                        'path' => 'KunstmaanNodeBundle_nodes_delete_undo',
526
                        'params' => [
527
                            '_locale' => $locale,
528
                            '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...
529
                        ],
530
                    ];
531
                }
532
533
                return null;
534
            },
535
            'fa fa-undo',
536
            '@KunstmaanNode\Admin\undo_delete_button.html.twig'
537
        );
538
539
        return $this->renderAdminList($request, $nodeAdminListConfigurator);
540
    }
541
542
    /**
543
     * @Route(
544
     *      "/{id}/delete/undo",
545
     *      requirements={"id" = "\d+"},
546
     *      name="KunstmaanNodeBundle_nodes_delete_undo",
547
     * )
548
     */
549
    public function undoDeleteAction(Request $request, int $id): RedirectResponse
550
    {
551
        $this->init($request);
552
553
        if (!$this->isUndoDeletingNodesEnabled) {
554
            throw $this->createAccessDeniedException();
555
        }
556
557
        /* @var Node $node */
558
        $node = $this->em->getRepository(Node::class)->find($id);
559
560
        try {
561
            $this->undoDeleteNode($node);
562
563
            $this->em->flush();
564
565
            $this->addFlash(
566
                FlashTypes::SUCCESS,
567
                $this->get('translator')->trans('kuma_node.admin.undo_delete.flash.success')
568
            );
569
        } catch (AccessDeniedException $exception) {
570
            $this->addFlash(
571
                FlashTypes::SUCCESS,
572
                $this->get('translator')->trans('kuma_node.admin.undo_delete.flash.error')
573
            );
574
        }
575
576
        return $this->redirectToRoute(
577
            'KunstmaanNodeBundle_deleted_nodes'
578
        );
579
    }
580
581
    /**
582
     * @Route(
583
     *      "/{id}/duplicate",
584
     *      requirements={"id" = "\d+"},
585
     *      name="KunstmaanNodeBundle_nodes_duplicate",
586
     *      methods={"POST"}
587
     * )
588
     *
589
     * @param Request $request
590
     * @param int     $id
591
     *
592
     * @return RedirectResponse
593
     *
594
     * @throws AccessDeniedException
595
     */
596
    public function duplicateAction(Request $request, $id)
597
    {
598
        $this->init($request);
599
        /* @var Node $parentNode */
600
        $originalNode = $this->em->getRepository(Node::class)
601
            ->find($id);
602
603
        // Check with Acl
604
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $originalNode);
605
606
        $request = $this->get('request_stack')->getCurrentRequest();
607
608
        $originalNodeTranslations = $originalNode->getNodeTranslation($this->locale, true);
609
        $originalRef = $originalNodeTranslations->getPublicNodeVersion()->getRef($this->em);
610
        $newPage = $this->get('kunstmaan_admin.clone.helper')
611
            ->deepCloneAndSave($originalRef);
612
613
        //set the title
614
        $title = $request->get('title');
615
        if (\is_string($title) && !empty($title)) {
616
            $newPage->setTitle($title);
617
        } else {
618
            $newPage->setTitle('New page');
619
        }
620
621
        //set the parent
622
        $parentNodeTranslation = $originalNode->getParent()->getNodeTranslation($this->locale, true);
623
        $parent = $parentNodeTranslation->getPublicNodeVersion()->getRef($this->em);
624
        $newPage->setParent($parent);
625
        $this->em->persist($newPage);
626
        $this->em->flush();
627
628
        /* @var Node $nodeNewPage */
629
        $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...
630
            $newPage,
631
            $this->locale,
632
            $this->user
633
        );
634
635
        $nodeTranslation = $nodeNewPage->getNodeTranslation($this->locale, true);
636
        if ($newPage->isStructureNode()) {
637
            $nodeTranslation->setSlug('');
638
            $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 635 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...
639
        }
640
        $this->em->flush();
641
642
        $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...
643
644
        $this->addFlash(
645
            FlashTypes::SUCCESS,
646
            $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success')
647
        );
648
649
        return $this->redirect(
650
            $this->generateUrl('KunstmaanNodeBundle_nodes_edit', array('id' => $nodeNewPage->getId()))
651
        );
652
    }
653
654
    /**
655
     * @Route(
656
     *      "/{id}/duplicate-with-children",
657
     *      requirements={"id" = "\d+"},
658
     *      name="KunstmaanNodeBundle_nodes_duplicate_with_children",
659
     *      methods={"POST"}
660
     * )
661
     *
662
     * @throws AccessDeniedException
663
     */
664
    public function duplicateWithChildrenAction(Request $request, $id)
665
    {
666
        if (!$this->getParameter('kunstmaan_node.show_duplicate_with_children')) {
667
            return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $id]);
668
        }
669
670
        $this->init($request);
671
        $title = $request->get('title', null);
672
673
        $nodeNewPage = $this->pageCloningHelper->duplicateWithChildren($id, $this->locale, $this->user, $title);
674
675
        $this->addFlash(FlashTypes::SUCCESS, $this->get('translator')->trans('kuma_node.admin.duplicate.flash.success'));
676
677
        return $this->redirectToRoute('KunstmaanNodeBundle_nodes_edit', ['id' => $nodeNewPage->getId()]);
678
    }
679
680
    /**
681
     * @Route(
682
     *      "/{id}/revert",
683
     *      requirements={"id" = "\d+"},
684
     *      defaults={"subaction" = "public"},
685
     *      name="KunstmaanNodeBundle_nodes_revert",
686
     *      methods={"GET"}
687
     * )
688
     *
689
     * @param Request $request
690
     * @param int     $id      The node id
691
     *
692
     * @return RedirectResponse
693
     *
694
     * @throws AccessDeniedException
695
     * @throws InvalidArgumentException
696
     */
697
    public function revertAction(Request $request, $id)
698
    {
699
        $this->init($request);
700
        /* @var Node $node */
701
        $node = $this->em->getRepository(Node::class)->find($id);
702
703
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
704
705
        $version = $request->get('version');
706
707
        if (empty($version) || !is_numeric($version)) {
708
            throw new InvalidArgumentException('No version was specified');
709
        }
710
711
        /* @var NodeVersionRepository $nodeVersionRepo */
712
        $nodeVersionRepo = $this->em->getRepository(NodeVersion::class);
713
        /* @var NodeVersion $nodeVersion */
714
        $nodeVersion = $nodeVersionRepo->find($version);
715
716
        if (\is_null($nodeVersion)) {
717
            throw new InvalidArgumentException('Version does not exist');
718
        }
719
720
        /* @var NodeTranslation $nodeTranslation */
721
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
722
        $page = $nodeVersion->getRef($this->em);
723
        /* @var HasNodeInterface $clonedPage */
724
        $clonedPage = $this->get('kunstmaan_admin.clone.helper')
725
            ->deepCloneAndSave($page);
726
        $newNodeVersion = $nodeVersionRepo->createNodeVersionFor(
727
            $clonedPage,
728
            $nodeTranslation,
729
            $this->user,
730
            $nodeVersion,
731
            'draft'
732
        );
733
734
        $nodeTranslation->setTitle($clonedPage->getTitle());
735
        $this->em->persist($nodeTranslation);
736
        $this->em->flush();
737
738
        $this->dispatch(
739
            new RevertNodeAction(
740
                $node,
741
                $nodeTranslation,
742
                $newNodeVersion,
743
                $clonedPage,
744
                $nodeVersion,
745
                $page
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 722 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...
746
            ),
747
            Events::REVERT
748
        );
749
750
        $this->addFlash(
751
            FlashTypes::SUCCESS,
752
            $this->get('translator')->trans('kuma_node.admin.revert.flash.success')
753
        );
754
755
        return $this->redirect(
756
            $this->generateUrl(
757
                'KunstmaanNodeBundle_nodes_edit',
758
                array(
759
                    'id' => $id,
760
                    'subaction' => 'draft',
761
                )
762
            )
763
        );
764
    }
765
766
    /**
767
     * @Route(
768
     *      "/{id}/add",
769
     *      requirements={"id" = "\d+"},
770
     *      name="KunstmaanNodeBundle_nodes_add",
771
     *      methods={"POST"}
772
     * )
773
     *
774
     * @param Request $request
775
     * @param int     $id
776
     *
777
     * @return RedirectResponse
778
     *
779
     * @throws AccessDeniedException
780
     * @throws InvalidArgumentException
781
     */
782
    public function addAction(Request $request, $id)
783
    {
784
        $this->init($request);
785
        /* @var Node $parentNode */
786
        $parentNode = $this->em->getRepository(Node::class)->find($id);
787
788
        // Check with Acl
789
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parentNode);
790
791
        $parentNodeTranslation = $parentNode->getNodeTranslation($this->locale, true);
792
        $parentNodeVersion = $parentNodeTranslation->getPublicNodeVersion();
793
        $parentPage = $parentNodeVersion->getRef($this->em);
794
795
        $type = $this->validatePageType($request);
796
        $newPage = $this->createNewPage($request, $type);
797
        $newPage->setParent($parentPage);
798
799
        /* @var Node $nodeNewPage */
800
        $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...
801
            ->createNodeFor($newPage, $this->locale, $this->user);
802
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
803
            $this->locale,
804
            true
805
        );
806
        $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...
807
                ->getMaxChildrenWeight($parentNode, $this->locale) + 1;
808
        $nodeTranslation->setWeight($weight);
809
810
        if ($newPage->isStructureNode()) {
811
            $nodeTranslation->setSlug('');
812
        }
813
814
        $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 802 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...
815
        $this->em->flush();
816
817
        $this->aclManager->updateNodeAcl($parentNode, $nodeNewPage);
818
819
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
820
821
        $this->dispatch(
822
            new NodeEvent(
823
                $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 802 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...
824
            ),
825
            Events::ADD_NODE
826
        );
827
828
        return $this->redirect(
829
            $this->generateUrl(
830
                'KunstmaanNodeBundle_nodes_edit',
831
                array('id' => $nodeNewPage->getId())
832
            )
833
        );
834
    }
835
836
    /**
837
     * @Route("/add-homepage", name="KunstmaanNodeBundle_nodes_add_homepage", methods={"POST"})
838
     *
839
     * @return RedirectResponse
840
     *
841
     * @throws AccessDeniedException
842
     * @throws InvalidArgumentException
843
     */
844
    public function addHomepageAction(Request $request)
845
    {
846
        $this->init($request);
847
848
        // Check with Acl
849
        $this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN');
850
851
        $type = $this->validatePageType($request);
852
853
        $newPage = $this->createNewPage($request, $type);
854
855
        /* @var Node $nodeNewPage */
856
        $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...
857
            ->createNodeFor($newPage, $this->locale, $this->user);
858
        $nodeTranslation = $nodeNewPage->getNodeTranslation(
859
            $this->locale,
860
            true
861
        );
862
        $this->em->flush();
863
864
        // Set default permissions
865
        $this->container->get('kunstmaan_node.acl_permission_creator_service')
866
            ->createPermission($nodeNewPage);
867
868
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
869
870
        $this->dispatch(
871
            new NodeEvent(
872
                $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 858 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...
873
            ),
874
            Events::ADD_NODE
875
        );
876
877
        return $this->redirect(
878
            $this->generateUrl(
879
                'KunstmaanNodeBundle_nodes_edit',
880
                array('id' => $nodeNewPage->getId())
881
            )
882
        );
883
    }
884
885
    /**
886
     * @Route("/reorder", name="KunstmaanNodeBundle_nodes_reorder", methods={"POST"})
887
     *
888
     * @param Request $request
889
     *
890
     * @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...
891
     *
892
     * @throws AccessDeniedException
893
     */
894
    public function reorderAction(Request $request)
895
    {
896
        $this->init($request);
897
        $nodes = array();
898
        $nodeIds = $request->get('nodes');
899
        $changeParents = $request->get('parent');
900
901
        foreach ($nodeIds as $id) {
902
            /* @var Node $node */
903
            $node = $this->em->getRepository(Node::class)->find($id);
904
            $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
905
            $nodes[] = $node;
906
        }
907
908
        $weight = 1;
909
        foreach ($nodes as $node) {
910
            $newParentId = isset($changeParents[$node->getId()]) ? $changeParents[$node->getId()] : null;
911
            if ($newParentId) {
912
                $parent = $this->em->getRepository(Node::class)->find($newParentId);
913
                $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $parent);
914
                $node->setParent($parent);
915
                $this->em->persist($node);
916
                $this->em->flush($node);
917
            }
918
919
            /* @var NodeTranslation $nodeTranslation */
920
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
921
922
            if ($nodeTranslation) {
923
                $nodeVersion = $nodeTranslation->getPublicNodeVersion();
924
                $page = $nodeVersion->getRef($this->em);
925
926
                $this->dispatch(
927
                    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 924 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...
928
                    Events::PRE_PERSIST
929
                );
930
931
                $nodeTranslation->setWeight($weight);
932
                $this->em->persist($nodeTranslation);
933
                $this->em->flush($nodeTranslation);
934
935
                $this->dispatch(
936
                    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 924 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...
937
                    Events::POST_PERSIST
938
                );
939
940
                ++$weight;
941
            }
942
        }
943
944
        return new JsonResponse(
945
            array(
946
                'Success' => 'The node-translations for [' . $this->locale . '] have got new weight values',
947
            )
948
        );
949
    }
950
951
    /**
952
     * @Route(
953
     *      "/{id}/{subaction}",
954
     *      requirements={"id" = "\d+"},
955
     *      defaults={"subaction" = "public"},
956
     *      name="KunstmaanNodeBundle_nodes_edit",
957
     *      methods={"GET", "POST"}
958
     * )
959
     * @Template("@KunstmaanNode/NodeAdmin/edit.html.twig")
960
     *
961
     * @param Request $request
962
     * @param int     $id        The node id
963
     * @param string  $subaction The subaction (draft|public)
964
     *
965
     * @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...
966
     *
967
     * @throws AccessDeniedException
968
     */
969
    public function editAction(Request $request, $id, $subaction)
970
    {
971
        $this->init($request);
972
        /* @var Node $node */
973
        $node = $this->em->getRepository(Node::class)->find($id);
974
975
        $this->denyAccessUnlessGranted(PermissionMap::PERMISSION_EDIT, $node);
976
977
        $tabPane = new TabPane(
978
            'todo',
979
            $request,
980
            $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...
981
        );
982
983
        $nodeTranslation = $node->getNodeTranslation($this->locale, true);
984
        if (!$nodeTranslation) {
985
            return $this->renderNodeNotTranslatedPage($node);
986
        }
987
988
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
989
        $draftNodeVersion = $nodeTranslation->getDraftNodeVersion();
990
        $nodeVersionIsLocked = false;
991
992
        /* @var HasNodeInterface $page */
993
        $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...
994
        $draft = ($subaction == 'draft');
995
        $saveAsDraft = $request->get('saveasdraft');
996
        if ((!$draft && !empty($saveAsDraft)) || ($draft && \is_null($draftNodeVersion))) {
997
            // Create a new draft version
998
            $draft = true;
999
            $subaction = 'draft';
1000
            $page = $nodeVersion->getRef($this->em);
1001
            $nodeVersion = $this->createDraftVersion(
1002
                $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 1000 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...
1003
                $nodeTranslation,
1004
                $nodeVersion
1005
            );
1006
            $draftNodeVersion = $nodeVersion;
1007
        } elseif ($draft) {
1008
            $nodeVersion = $draftNodeVersion;
1009
            $page = $nodeVersion->getRef($this->em);
1010
        } else {
1011
            if (!empty($request->request->get('undo_delete'))) {
1012
                $node->setDeleted(false);
1013
1014
                $this->em->persist($node);
1015
                $this->em->flush();
1016
            }
1017
1018
            if ($request->getMethod() == 'POST') {
1019
                $nodeVersionIsLocked = $this->isNodeVersionLocked($nodeTranslation, true);
1020
1021
                //Check the version timeout and make a new nodeversion if the timeout is passed
1022
                $thresholdDate = date(
1023
                    'Y-m-d H:i:s',
1024
                    time() - $this->getParameter(
1025
                        'kunstmaan_node.version_timeout'
1026
                    )
1027
                );
1028
                $updatedDate = date(
1029
                    'Y-m-d H:i:s',
1030
                    strtotime($nodeVersion->getUpdated()->format('Y-m-d H:i:s'))
1031
                );
1032 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...
1033
                    $page = $nodeVersion->getRef($this->em);
1034
                    if ($nodeVersion === $nodeTranslation->getPublicNodeVersion()) {
1035
                        $this->nodePublisher
1036
                            ->createPublicVersion(
1037
                                $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 1033 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...
1038
                                $nodeTranslation,
1039
                                $nodeVersion,
1040
                                $this->user
1041
                            );
1042
                    } else {
1043
                        $this->createDraftVersion(
1044
                            $page,
0 ignored issues
show
Bug introduced by
It seems like $page defined by $nodeVersion->getRef($this->em) on line 1033 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...
1045
                            $nodeTranslation,
1046
                            $nodeVersion
1047
                        );
1048
                    }
1049
                }
1050
            }
1051
            $page = $nodeVersion->getRef($this->em);
1052
        }
1053
        $isStructureNode = $page->isStructureNode();
1054
1055
        $menubuilder = $this->get('kunstmaan_node.actions_menu_builder');
1056
        $menubuilder->setActiveNodeVersion($nodeVersion);
1057
        $menubuilder->setEditableNode(!$isStructureNode);
1058
1059
        // Building the form
1060
        $propertiesWidget = new FormWidget();
1061
        $propertiesWidget->addType('main', $page->getDefaultAdminType(), $page);
1062
        $propertiesWidget->addType('node', $node->getDefaultAdminType(), $node);
1063
        $tabPane->addTab(new Tab('kuma_node.tab.properties.title', $propertiesWidget));
1064
1065
        // Menu tab
1066
        $menuWidget = new FormWidget();
1067
        $menuWidget->addType(
1068
            'menunodetranslation',
1069
            NodeMenuTabTranslationAdminType::class,
1070
            $nodeTranslation,
1071
            ['slugable' => !$isStructureNode]
1072
        );
1073
        $menuWidget->addType('menunode', NodeMenuTabAdminType::class, $node, ['available_in_nav' => !$isStructureNode]);
1074
        $tabPane->addTab(new Tab('kuma_node.tab.menu.title', $menuWidget));
1075
1076
        $this->dispatch(
1077
            new AdaptFormEvent(
1078
                $request,
1079
                $tabPane,
1080
                $page,
1081
                $node,
1082
                $nodeTranslation,
1083
                $nodeVersion
1084
            ),
1085
            Events::ADAPT_FORM
1086
        );
1087
1088
        $tabPane->buildForm();
1089
1090
        if ($request->getMethod() == 'POST') {
1091
            $tabPane->bindRequest($request);
1092
1093
            // Don't redirect to listing when coming from ajax request, needed for url chooser.
1094
            if ($tabPane->isValid() && !$request->isXmlHttpRequest()) {
1095
                $this->dispatch(
1096
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page),
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 1008 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...
1097
                    Events::PRE_PERSIST
1098
                );
1099
1100
                $nodeTranslation->setTitle($page->getTitle());
1101
                if ($isStructureNode) {
1102
                    $nodeTranslation->setSlug('');
1103
                }
1104
                $nodeVersion->setUpdated(new DateTime());
1105
                if ($nodeVersion->getType() == 'public') {
1106
                    $nodeTranslation->setUpdated($nodeVersion->getUpdated());
1107
                }
1108
                $this->em->persist($nodeTranslation);
1109
                $this->em->persist($nodeVersion);
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 1008 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...
1110
                $tabPane->persist($this->em);
1111
                $this->em->flush();
1112
1113
                $this->dispatch(
1114
                    new NodeEvent($node, $nodeTranslation, $nodeVersion, $page),
0 ignored issues
show
Bug introduced by
It seems like $nodeVersion defined by $draftNodeVersion on line 1008 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...
1115
                    Events::POST_PERSIST
1116
                );
1117
1118
                if ($nodeVersionIsLocked) {
1119
                    $this->addFlash(
1120
                        FlashTypes::SUCCESS,
1121
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.locked_success')
1122
                    );
1123
                } elseif ($request->request->has('publishing') || $request->request->has('publish_later')) {
1124
                    $this->nodePublisher->chooseHowToPublish($request, $nodeTranslation, $this->translator);
1125
                } elseif ($request->request->has('unpublishing') || $request->request->has('unpublish_later')) {
1126
                    $this->nodePublisher->chooseHowToUnpublish($request, $nodeTranslation, $this->translator);
1127
                } else {
1128
                    $this->addFlash(
1129
                        FlashTypes::SUCCESS,
1130
                        $this->get('translator')->trans('kuma_node.admin.edit.flash.success')
1131
                    );
1132
                }
1133
1134
                $params = [
1135
                    'id' => $node->getId(),
1136
                    'subaction' => $subaction,
1137
                    'currenttab' => $tabPane->getActiveTab(),
1138
                ];
1139
                $params = array_merge(
1140
                    $params,
1141
                    $tabPane->getExtraParams($request)
1142
                );
1143
1144
                if ($subaction === 'draft' && ($request->request->has('publishing') || $request->request->has('publish_later'))) {
1145
                    unset($params['subaction']);
1146
                }
1147
1148
                return $this->redirect(
1149
                    $this->generateUrl(
1150
                        'KunstmaanNodeBundle_nodes_edit',
1151
                        $params
1152
                    )
1153
                );
1154
            }
1155
        }
1156
1157
        $nodeVersions = $this->em->getRepository(NodeVersion::class)->findBy(
1158
            ['nodeTranslation' => $nodeTranslation],
1159
            ['updated' => 'DESC']
1160
        );
1161
        $queuedNodeTranslationAction = $this->em->getRepository(QueuedNodeTranslationAction::class)->findOneBy(['nodeTranslation' => $nodeTranslation]);
1162
1163
        return [
1164
            'page' => $page,
1165
            'entityname' => ClassLookup::getClass($page),
1166
            'nodeVersions' => $nodeVersions,
1167
            'node' => $node,
1168
            'nodeTranslation' => $nodeTranslation,
1169
            'draft' => $draft,
1170
            'draftNodeVersion' => $draftNodeVersion,
1171
            'showDuplicateWithChildren' => $this->getParameter('kunstmaan_node.show_duplicate_with_children'),
1172
            'nodeVersion' => $nodeVersion,
1173
            'subaction' => $subaction,
1174
            'tabPane' => $tabPane,
1175
            'editmode' => true,
1176
            '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...
1177
            'queuedNodeTranslationAction' => $queuedNodeTranslationAction,
1178
            'nodeVersionLockCheck' => $this->container->getParameter('kunstmaan_node.lock_enabled'),
1179
            'nodeVersionLockInterval' => $this->container->getParameter('kunstmaan_node.lock_check_interval'),
1180
        ];
1181
    }
1182
1183
    /**
1184
     * @Route(
1185
     *      "checkNodeVersionLock/{id}/{public}",
1186
     *      requirements={"id" = "\d+", "public" = "(0|1)"},
1187
     *      name="KunstmaanNodeBundle_nodes_versionlock_check"
1188
     * )
1189
     *
1190
     * @param Request $request
1191
     * @param $id
1192
     *
1193
     * @return JsonResponse
1194
     */
1195
    public function checkNodeVersionLockAction(Request $request, $id, $public)
1196
    {
1197
        $nodeVersionIsLocked = false;
1198
        $message = '';
1199
        $this->init($request);
1200
1201
        /* @var Node $node */
1202
        $node = $this->em->getRepository(Node::class)->find($id);
1203
1204
        try {
1205
            $this->checkPermission($node, PermissionMap::PERMISSION_EDIT);
1206
1207
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1208
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1209
            $nodeTranslation = $node->getNodeTranslation($this->locale, true);
1210
1211
            if ($nodeTranslation) {
1212
                $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...
1213
1214
                if ($nodeVersionIsLocked) {
1215
                    $users = $nodeVersionLockHelper->getUsersWithNodeVersionLock($nodeTranslation, $public, $this->getUser());
1216
                    $message = $this->get('translator')->trans('kuma_node.admin.edit.flash.locked', array('%users%' => implode(', ', $users)));
1217
                }
1218
            }
1219
        } catch (AccessDeniedException $ade) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1220
        }
1221
1222
        return new JsonResponse(['lock' => $nodeVersionIsLocked, 'message' => $message]);
1223
    }
1224
1225
    /**
1226
     * @param NodeTranslation $nodeTranslation
1227
     * @param bool            $isPublic
1228
     *
1229
     * @return bool
1230
     */
1231
    private function isNodeVersionLocked(NodeTranslation $nodeTranslation, $isPublic)
1232
    {
1233
        if ($this->container->getParameter('kunstmaan_node.lock_enabled')) {
1234
            /** @var NodeVersionLockHelper $nodeVersionLockHelper */
1235
            $nodeVersionLockHelper = $this->get('kunstmaan_node.admin_node.node_version_lock_helper');
1236
            $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...
1237
1238
            return $nodeVersionIsLocked;
1239
        }
1240
1241
        return false;
1242
    }
1243
1244
    /**
1245
     * @param HasNodeInterface $page            The page
1246
     * @param NodeTranslation  $nodeTranslation The node translation
1247
     * @param NodeVersion      $nodeVersion     The node version
1248
     *
1249
     * @return NodeVersion
1250
     */
1251
    private function createDraftVersion(
1252
        HasNodeInterface $page,
1253
        NodeTranslation $nodeTranslation,
1254
        NodeVersion $nodeVersion
1255
    ) {
1256
        $publicPage = $this->get('kunstmaan_admin.clone.helper')
1257
            ->deepCloneAndSave($page);
1258
        /* @var NodeVersion $publicNodeVersion */
1259
1260
        $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...
1261
            NodeVersion::class
1262
        )->createNodeVersionFor(
1263
            $publicPage,
1264
            $nodeTranslation,
1265
            $this->user,
1266
            $nodeVersion->getOrigin(),
1267
            'public',
1268
            $nodeVersion->getCreated()
1269
        );
1270
1271
        $nodeTranslation->setPublicNodeVersion($publicNodeVersion);
1272
        $nodeVersion->setType('draft');
1273
        $nodeVersion->setOrigin($publicNodeVersion);
1274
        $nodeVersion->setCreated(new DateTime());
1275
1276
        $this->em->persist($nodeTranslation);
1277
        $this->em->persist($nodeVersion);
1278
        $this->em->flush();
1279
1280
        $this->dispatch(
1281
            new NodeEvent(
1282
                $nodeTranslation->getNode(),
1283
                $nodeTranslation,
1284
                $nodeVersion,
1285
                $page
1286
            ),
1287
            Events::CREATE_DRAFT_VERSION
1288
        );
1289
1290
        return $nodeVersion;
1291
    }
1292
1293
    /**
1294
     * @param Node   $node       The node
1295
     * @param string $permission The permission to check for
1296
     *
1297
     * @throws AccessDeniedException
1298
     */
1299
    private function checkPermission(Node $node, $permission)
1300
    {
1301
        if (false === $this->authorizationChecker->isGranted($permission, $node)) {
1302
            throw new AccessDeniedException();
1303
        }
1304
    }
1305
1306
    /**
1307
     * @param EntityManager   $em       The Entity Manager
1308
     * @param BaseUser        $user     The user who deletes the children
1309
     * @param string          $locale   The locale that was used
1310
     * @param ArrayCollection $children The children array
1311
     */
1312 View Code Duplication
    private function deleteNodeChildren(
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...
1313
        EntityManager $em,
1314
        BaseUser $user,
1315
        $locale,
1316
        ArrayCollection $children
1317
    ) {
1318
        /* @var Node $childNode */
1319
        foreach ($children as $childNode) {
1320
            $childNodeTranslation = $childNode->getNodeTranslation(
1321
                $this->locale,
1322
                true
1323
            );
1324
1325
            $childNodeVersion = $childNodeTranslation->getPublicNodeVersion();
1326
            $childNodePage = $childNodeVersion->getRef($this->em);
1327
1328
            $this->dispatch(
1329
                new NodeEvent(
1330
                    $childNode,
1331
                    $childNodeTranslation,
1332
                    $childNodeVersion,
1333
                    $childNodePage
1334
                ),
1335
                Events::PRE_DELETE
1336
            );
1337
1338
            $childNode->setDeleted(true);
1339
            $this->em->persist($childNode);
1340
1341
            $children2 = $childNode->getChildren();
1342
            $this->deleteNodeChildren($em, $user, $locale, $children2);
1343
1344
            $this->dispatch(
1345
                new NodeEvent(
1346
                    $childNode,
1347
                    $childNodeTranslation,
1348
                    $childNodeVersion,
1349
                    $childNodePage
1350
                ),
1351
                Events::POST_DELETE
1352
            );
1353
        }
1354
    }
1355
1356
    private function undoDeleteNode(Node $node): void
1357
    {
1358
        if (!$node->isDeleted()) {
1359
            return;
1360
        }
1361
1362
        $this->denyAccessUnlessGranted(
1363
            PermissionMap::PERMISSION_DELETE,
1364
            $node
1365
        );
1366
1367
        $node->setDeleted(false);
1368
1369
        foreach ($node->getNodeTranslations() as $nodeTranslation) {
1370
            if (!$nodeTranslation instanceof NodeTranslation) {
1371
                continue;
1372
            }
1373
1374
            $this->nodePublisher->unPublish($nodeTranslation);
1375
        }
1376
1377
        $this->em->persist($node);
1378
1379
        foreach ($node->getChildren() as $child) {
1380
            $this->undoDeleteNode($child);
1381
        }
1382
    }
1383
1384
    /**
1385
     * @param Request $request
1386
     * @param string  $type
1387
     *
1388
     * @return HasNodeInterface
1389
     */
1390
    private function createNewPage(Request $request, $type)
1391
    {
1392
        /* @var HasNodeInterface $newPage */
1393
        $newPage = new $type();
1394
1395
        $title = $request->get('title');
1396
        if (\is_string($title) && !empty($title)) {
1397
            $newPage->setTitle($title);
1398
        } else {
1399
            $newPage->setTitle($this->get('translator')->trans('kuma_node.admin.new_page.title.default'));
1400
        }
1401
        $this->em->persist($newPage);
1402
        $this->em->flush();
1403
1404
        return $newPage;
1405
    }
1406
1407
    /**
1408
     * @param Request $request
1409
     *
1410
     * @return string
1411
     * @throw InvalidArgumentException
1412
     */
1413
    private function validatePageType($request)
1414
    {
1415
        $type = $request->get('type');
1416
1417
        if (empty($type)) {
1418
            throw new InvalidArgumentException('Please specify a type of page you want to create');
1419
        }
1420
1421
        return $type;
1422
    }
1423
1424
    /**
1425
     * @param Node $node
1426
     *
1427
     * @return \Symfony\Component\HttpFoundation\Response
1428
     */
1429
    private function renderNodeNotTranslatedPage(Node $node)
1430
    {
1431
        //try to find a parent node with the correct translation, if there is none allow copy.
1432
        //if there is a parent but it doesn't have the language to copy to don't allow it
1433
        $parentNode = $node->getParent();
1434
        if ($parentNode) {
1435
            $parentNodeTranslation = $parentNode->getNodeTranslation(
1436
                $this->locale,
1437
                true
1438
            );
1439
            $parentsAreOk = false;
1440
1441
            if ($parentNodeTranslation) {
1442
                $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...
1443
                    NodeTranslation::class
1444
                )->hasParentNodeTranslationsForLanguage(
1445
                    $node->getParent()->getNodeTranslation(
1446
                        $this->locale,
1447
                        true
1448
                    ),
1449
                    $this->locale
1450
                );
1451
            }
1452
        } else {
1453
            $parentsAreOk = true;
1454
        }
1455
1456
        return $this->render(
1457
            '@KunstmaanNode/NodeAdmin/pagenottranslated.html.twig',
1458
            array(
1459
                'node' => $node,
1460
                'nodeTranslations' => $node->getNodeTranslations(
1461
                    true
1462
                ),
1463
                'copyfromotherlanguages' => $parentsAreOk,
1464
            )
1465
        );
1466
    }
1467
1468
    /**
1469
     * @param object $event
1470
     * @param string $eventName
1471
     *
1472
     * @return object
1473
     */
1474 View Code Duplication
    private function dispatch($event, string $eventName)
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...
1475
    {
1476
        $eventDispatcher = $this->container->get('event_dispatcher');
1477
        if (class_exists(LegacyEventDispatcherProxy::class)) {
1478
            $eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher);
1479
1480
            return $eventDispatcher->dispatch($event, $eventName);
1481
        }
1482
1483
        return $eventDispatcher->dispatch($eventName, $event);
1484
    }
1485
1486
    private function renderAdminList(
1487
        Request $request,
1488
        NodeAdminListConfigurator $nodeAdminListConfigurator
1489
    ): array {
1490
        /** @var AdminList $adminList */
1491
        $adminList = $this->get('kunstmaan_adminlist.factory')->createList($nodeAdminListConfigurator);
1492
        $adminList->bindRequest($request);
1493
1494
        return [
1495
            'adminlist' => $adminList,
1496
        ];
1497
    }
1498
}
1499