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

NodeBundle/Helper/NodeAdmin/NodeAdminPublisher.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

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

1
<?php
2
3
namespace Kunstmaan\NodeBundle\Helper\NodeAdmin;
4
5
use Doctrine\ORM\EntityManager;
6
use Kunstmaan\AdminBundle\Entity\BaseUser;
7
use Kunstmaan\AdminBundle\Helper\CloneHelper;
8
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
9
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
10
use Kunstmaan\NodeBundle\Entity\Node;
11
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
12
use Kunstmaan\NodeBundle\Entity\NodeVersion;
13
use Kunstmaan\NodeBundle\Entity\QueuedNodeTranslationAction;
14
use Kunstmaan\NodeBundle\Event\Events;
15
use Kunstmaan\NodeBundle\Event\NodeEvent;
16
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Session\Session;
19
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
20
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
22
use Symfony\Component\Translation\TranslatorInterface;
23
use Kunstmaan\AdminBundle\FlashMessages\FlashTypes;
24
25
class NodeAdminPublisher
26
{
27
    /**
28
     * @var EntityManager
29
     */
30
    private $em;
31
32
    /**
33
     * @var TokenStorageInterface
34
     */
35
    private $tokenStorage;
36
37
    /**
38
     * @var AuthorizationCheckerInterface
39
     */
40
    private $authorizationChecker;
41
42
    /**
43
     * @var EventDispatcherInterface
44
     */
45
    private $eventDispatcher;
46
47
    /**
48
     * @var CloneHelper
49
     */
50
    private $cloneHelper;
51
52
    /**
53
     * @param EntityManager                 $em                   The entity manager
54
     * @param TokenStorageInterface         $tokenStorage         The security token storage
55
     * @param AuthorizationCheckerInterface $authorizationChecker The security authorization checker
56
     * @param EventDispatcherInterface      $eventDispatcher      The Event dispatcher
57
     * @param CloneHelper                   $cloneHelper          The clone helper
58
     */
59 View Code Duplication
    public function __construct(
60
        EntityManager $em,
61
        TokenStorageInterface $tokenStorage,
62
        AuthorizationCheckerInterface $authorizationChecker,
63
        EventDispatcherInterface $eventDispatcher,
64
        CloneHelper $cloneHelper
65
    ) {
66
        $this->em = $em;
67
        $this->tokenStorage = $tokenStorage;
68
        $this->authorizationChecker = $authorizationChecker;
69
        $this->eventDispatcher = $eventDispatcher;
70
        $this->cloneHelper = $cloneHelper;
71
    }
72
73
    /**
74
     * If there is a draft version it'll try to publish the draft first. Makse snese because if you want to publish the public version you don't publish but you save.
75
     *
76
     * @param NodeTranslation $nodeTranslation
77
     * @param null|BaseUser   $user
78
     *
79
     *  @throws AccessDeniedException
80
     */
81
    public function publish(NodeTranslation $nodeTranslation, $user = null)
82
    {
83
        if (false === $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_PUBLISH, $nodeTranslation->getNode())) {
84
            throw new AccessDeniedException();
85
        }
86
87
        if (\is_null($user)) {
88
            $user = $this->tokenStorage->getToken()->getUser();
89
        }
90
91
        $node = $nodeTranslation->getNode();
92
93
        $nodeVersion = $nodeTranslation->getNodeVersion('draft');
94
        if (!\is_null($nodeVersion)) {
95
            $page = $nodeVersion->getRef($this->em);
96
            /** @var NodeVersion $nodeVersion */
97
            $nodeVersion = $this->createPublicVersion($page, $nodeTranslation, $nodeVersion, $user);
98
            $nodeTranslation = $nodeVersion->getNodeTranslation();
99
        } else {
100
            $nodeVersion = $nodeTranslation->getPublicNodeVersion();
101
        }
102
103
        $page = $nodeVersion->getRef($this->em);
104
105
        $this->eventDispatcher->dispatch(
106
            Events::PRE_PUBLISH,
107
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
108
        );
109
        $nodeTranslation
110
            ->setOnline(true)
111
            ->setPublicNodeVersion($nodeVersion)
112
            ->setUpdated(new \DateTime());
113
        $this->em->persist($nodeTranslation);
114
        $this->em->flush();
115
116
        // Remove scheduled task
117
        $this->unSchedulePublish($nodeTranslation);
118
119
        $this->eventDispatcher->dispatch(
120
            Events::POST_PUBLISH,
121
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
122
        );
123
    }
124
125
    /**
126
     * @param NodeTranslation $nodeTranslation The NodeTranslation
127
     * @param \DateTime       $date            The date to publish
128
     *
129
     * @throws AccessDeniedException
130
     */
131 View Code Duplication
    public function publishLater(NodeTranslation $nodeTranslation, \DateTime $date)
132
    {
133
        $node = $nodeTranslation->getNode();
134
        if (false === $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_PUBLISH, $node)) {
135
            throw new AccessDeniedException();
136
        }
137
138
        //remove existing first
139
        $this->unSchedulePublish($nodeTranslation);
140
141
        $user = $this->tokenStorage->getToken()->getUser();
142
        $queuedNodeTranslationAction = new QueuedNodeTranslationAction();
143
        $queuedNodeTranslationAction
144
            ->setNodeTranslation($nodeTranslation)
145
            ->setAction(QueuedNodeTranslationAction::ACTION_PUBLISH)
146
            ->setUser($user)
147
            ->setDate($date);
148
        $this->em->persist($queuedNodeTranslationAction);
149
        $this->em->flush();
150
    }
151
152
    /**
153
     * @param NodeTranslation $nodeTranslation
154
     *
155
     * @throws AccessDeniedException
156
     */
157
    public function unPublish(NodeTranslation $nodeTranslation)
158
    {
159
        if (false === $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_UNPUBLISH, $nodeTranslation->getNode())) {
160
            throw new AccessDeniedException();
161
        }
162
163
        $node = $nodeTranslation->getNode();
164
        $nodeVersion = $nodeTranslation->getPublicNodeVersion();
165
        $page = $nodeVersion->getRef($this->em);
166
167
        $this->eventDispatcher->dispatch(
168
            Events::PRE_UNPUBLISH,
169
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
170
        );
171
        $nodeTranslation->setOnline(false);
172
        $this->em->persist($nodeTranslation);
173
        $this->em->flush();
174
175
        // Remove scheduled task
176
        $this->unSchedulePublish($nodeTranslation);
177
178
        $this->eventDispatcher->dispatch(
179
            Events::POST_UNPUBLISH,
180
            new NodeEvent($node, $nodeTranslation, $nodeVersion, $page)
181
        );
182
    }
183
184
    /**
185
     * @param NodeTranslation $nodeTranslation The NodeTranslation
186
     * @param \DateTime       $date            The date to unpublish
187
     *
188
     * @throws AccessDeniedException
189
     */
190 View Code Duplication
    public function unPublishLater(NodeTranslation $nodeTranslation, \DateTime $date)
191
    {
192
        $node = $nodeTranslation->getNode();
193
        if (false === $this->authorizationChecker->isGranted(PermissionMap::PERMISSION_UNPUBLISH, $node)) {
194
            throw new AccessDeniedException();
195
        }
196
197
        //remove existing first
198
        $this->unSchedulePublish($nodeTranslation);
199
        $user = $this->tokenStorage->getToken()->getUser();
200
        $queuedNodeTranslationAction = new QueuedNodeTranslationAction();
201
        $queuedNodeTranslationAction
202
            ->setNodeTranslation($nodeTranslation)
203
            ->setAction(QueuedNodeTranslationAction::ACTION_UNPUBLISH)
204
            ->setUser($user)
205
            ->setDate($date);
206
        $this->em->persist($queuedNodeTranslationAction);
207
        $this->em->flush();
208
    }
209
210
    /**
211
     * @param NodeTranslation $nodeTranslation
212
     */
213
    public function unSchedulePublish(NodeTranslation $nodeTranslation)
214
    {
215
        /* @var Node $node */
216
        $queuedNodeTranslationAction = $this->em->getRepository('KunstmaanNodeBundle:QueuedNodeTranslationAction')
217
            ->findOneBy(array('nodeTranslation' => $nodeTranslation));
218
219
        if (!\is_null($queuedNodeTranslationAction)) {
220
            $this->em->remove($queuedNodeTranslationAction);
221
            $this->em->flush();
222
        }
223
    }
224
225
    /**
226
     * This shouldn't be here either but it's an improvement.
227
     *
228
     * @param HasNodeInterface $page            The page
229
     * @param NodeTranslation  $nodeTranslation The node translation
230
     * @param NodeVersion      $nodeVersion     The node version
231
     * @param BaseUser         $user            The user
232
     *
233
     * @return mixed
234
     */
235
    public function createPublicVersion(
236
        HasNodeInterface $page,
237
        NodeTranslation $nodeTranslation,
238
        NodeVersion $nodeVersion,
239
        BaseUser $user
240
    ) {
241
        $newPublicPage = $this->cloneHelper->deepCloneAndSave($page);
242
        $newNodeVersion = $this->em->getRepository('KunstmaanNodeBundle:NodeVersion')->createNodeVersionFor(
0 ignored issues
show
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...
243
            $newPublicPage,
244
            $nodeTranslation,
245
            $user,
246
            $nodeVersion
247
        );
248
249
        $newNodeVersion
250
            ->setOwner($nodeVersion->getOwner())
251
            ->setUpdated($nodeVersion->getUpdated())
252
            ->setCreated($nodeVersion->getCreated());
253
254
        $nodeVersion
255
            ->setOwner($user)
256
            ->setCreated(new \DateTime())
257
            ->setOrigin($newNodeVersion);
258
259
        $this->em->persist($newNodeVersion);
260
        $this->em->persist($nodeVersion);
261
        $this->em->persist($nodeTranslation);
262
        $this->em->flush();
263
        $this->eventDispatcher->dispatch(
264
            Events::CREATE_PUBLIC_VERSION,
265
            new NodeEvent($nodeTranslation->getNode(), $nodeTranslation, $nodeVersion, $newPublicPage)
266
        );
267
268
        return $newNodeVersion;
269
    }
270
271
    /**
272
     * @param Request         $request
273
     * @param NodeTranslation $nodeTranslation
274
     */
275 View Code Duplication
    public function chooseHowToPublish(Request $request, NodeTranslation $nodeTranslation, TranslatorInterface $translator)
276
    {
277
        /** @var Session $session */
278
        $session = $request->getSession();
279
280
        if ($request->request->has('publish_later') && $request->get('pub_date')) {
281
            $date = new \DateTime(
282
                $request->get('pub_date') . ' ' . $request->get('pub_time')
283
            );
284
            $this->publishLater($nodeTranslation, $date);
285
            $session->getFlashBag()->add(
286
                FlashTypes::SUCCESS,
287
                $translator->trans('kuma_node.admin.publish.flash.success_scheduled')
288
            );
289
        } else {
290
            $this->publish($nodeTranslation);
291
            $session->getFlashBag()->add(
292
                FlashTypes::SUCCESS,
293
                $translator->trans('kuma_node.admin.publish.flash.success_published')
294
            );
295
        }
296
    }
297
298
    /**
299
     * @param Request         $request
300
     * @param NodeTranslation $nodeTranslation
301
     */
302 View Code Duplication
    public function chooseHowToUnpublish(Request $request, NodeTranslation $nodeTranslation, TranslatorInterface $translator)
303
    {
304
        /** @var Session $session */
305
        $session = $request->getSession();
306
307
        if ($request->request->has('unpublish_later') && $request->get('unpub_date')) {
308
            $date = new \DateTime($request->get('unpub_date') . ' ' . $request->get('unpub_time'));
309
            $this->unPublishLater($nodeTranslation, $date);
310
            $session->getFlashBag()->add(
311
                FlashTypes::SUCCESS,
312
                $translator->trans('kuma_node.admin.unpublish.flash.success_scheduled')
313
            );
314
        } else {
315
            $this->unPublish($nodeTranslation);
316
            $session->getFlashBag()->add(
317
                FlashTypes::SUCCESS,
318
                $translator->trans('kuma_node.admin.unpublish.flash.success_unpublished')
319
            );
320
        }
321
    }
322
}
323