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

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

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