DefaultController   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 312
Duplicated Lines 0 %

Test Coverage

Coverage 79.81%

Importance

Changes 0
Metric Value
wmc 31
dl 0
loc 312
ccs 83
cts 104
cp 0.7981
rs 9.8
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getUser() 0 12 3
A showBackButton() 0 11 2
A redirectToRoute() 0 5 1
A imprintAction() 0 3 1
B readTopicAction() 0 23 6
A __construct() 0 11 1
A paywallAction() 0 11 1
A getTextnodeForHitchIndex() 0 12 2
C readTextnodeAction() 0 48 7
A backAction() 0 14 3
A getParentHitch() 0 18 4
1
<?php
2
/* Copyright (C) 2015-2017 Michael Giesler, Stephan Kreutzer
3
 *
4
 * This file is part of Dembelo.
5
 *
6
 * Dembelo is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * Dembelo is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Affero General Public License 3 for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License 3
17
 * along with Dembelo. If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
declare(strict_types = 1);
21
22
namespace DembeloMain\Controller;
23
24
use DembeloMain\Document\Textnode;
25
use DembeloMain\Document\TextnodeHitch;
26
use DembeloMain\Document\User;
27
use DembeloMain\Model\FavoriteManager;
28
use DembeloMain\Model\FeatureToggle;
29
use DembeloMain\Model\Readpath;
30
use DembeloMain\Model\Repository\TextNodeRepositoryInterface;
31
use DembeloMain\Model\Repository\UserRepositoryInterface;
32
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
33
use Symfony\Component\HttpFoundation\RedirectResponse;
34
use Symfony\Component\HttpFoundation\Response;
35
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
36
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
37
use Symfony\Bundle\FrameworkBundle\Routing\Router;
38
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface as Templating;
39
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
40
41
/**
42
 * Class DefaultController
43
 * @Route(service="app.controller_default")
44
 */
45
class DefaultController
46
{
47
    /**
48
     * @var FeatureToggle
49
     */
50
    private $featureToggle;
51
52
    /**
53
     * @var AuthorizationCheckerInterface
54
     */
55
    private $authorizationChecker;
56
57
    /**
58
     * @var UserRepositoryInterface
59
     */
60
    private $userRepository;
61
62
    /**
63
     * @var TextNodeRepositoryInterface
64
     */
65
    private $textnodeRepository;
66
67
    /**
68
     * @var Templating
69
     */
70
    private $templating;
71
72
    /**
73
     * @var Router
74
     */
75
    private $router;
76
77
    /**
78
     * @var TokenStorage
79
     */
80
    private $tokenStorage;
81
82
    /**
83
     * @var Readpath
84
     */
85
    private $readpath;
86
87
    /**
88
     * @var FavoriteManager
89
     */
90
    private $favoriteManager;
91
92
    /**
93
     * DefaultController constructor.
94
     * @param FeatureToggle                 $featureToggle
95
     * @param AuthorizationCheckerInterface $authorizationChecker
96
     * @param UserRepositoryInterface       $userRepository
97
     * @param TextNodeRepositoryInterface   $textNodeRepository
98
     * @param Templating                    $templating
99
     * @param Router                        $router
100
     * @param TokenStorage                  $tokenStorage
101
     * @param Readpath                      $readpath
102
     * @param FavoriteManager               $favoriteManager
103
     */
104 16
    public function __construct(FeatureToggle $featureToggle, AuthorizationCheckerInterface $authorizationChecker, UserRepositoryInterface $userRepository, TextNodeRepositoryInterface $textNodeRepository, Templating $templating, Router $router, TokenStorage $tokenStorage, Readpath $readpath, FavoriteManager $favoriteManager)
105
    {
106 16
        $this->featureToggle = $featureToggle;
107 16
        $this->authorizationChecker = $authorizationChecker;
108 16
        $this->userRepository = $userRepository;
109 16
        $this->textnodeRepository = $textNodeRepository;
110 16
        $this->templating = $templating;
111 16
        $this->router = $router;
112 16
        $this->tokenStorage = $tokenStorage;
113 16
        $this->readpath = $readpath;
114 16
        $this->favoriteManager = $favoriteManager;
115 16
    }
116
117
    /**
118
     * @Route("/themenfeld/{topicId}", name="themenfeld")
119
     *
120
     * @param string $topicId Topic ID from URL
121
     *
122
     * @return RedirectResponse
123
     *
124
     * @throws NotFoundHttpException
125
     */
126 5
    public function readTopicAction($topicId): RedirectResponse
127
    {
128 5
        if ($this->featureToggle->hasFeature('login_needed') && !$this->authorizationChecker->isGranted('ROLE_USER')) {
129 1
            return $this->redirectToRoute('login_route');
130
        }
131
132 4
        $textnode = $this->textnodeRepository->getTextnodeToRead($topicId);
133
134 4
        if (null === $textnode) {
135 1
            throw new NotFoundHttpException(sprintf('No Textnode for Topic \'%s\' found.', $topicId));
136
        }
137
138 3
        $user = $this->getUser();
139 3
        if ($user instanceof User) {
140 1
            $user->setLastTopicId($topicId);
141 1
            $this->userRepository->save($user);
142
        }
143
144 3
        if ($textnode->isFinanceNode()) {
145 1
            return $this->redirectToRoute('financenode', ['textnodeArbitraryId' => $textnode->getArbitraryId()]);
146
        }
147
148 2
        return $this->redirectToRoute('text', array('textnodeArbitraryId' => $textnode->getArbitraryId()));
149
    }
150
151
    /**
152
     * @Route("/text/{textnodeArbitraryId}", name="text")
153
     *
154
     * @param string $textnodeArbitraryId Textnode arbitrary ID from URL
155
     *
156
     * @return Response
157
     *
158
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
159
     */
160 4
    public function readTextnodeAction($textnodeArbitraryId): Response
161
    {
162 4
        if ($this->featureToggle->hasFeature('login_needed') && !$this->authorizationChecker->isGranted('ROLE_USER')) {
163 1
            return $this->redirectToRoute('login_route');
164
        }
165
166 3
        $textnode = $this->textnodeRepository->findOneActiveByArbitraryId($textnodeArbitraryId);
167
168 3
        if (null === $textnode) {
169 1
            throw new NotFoundHttpException(sprintf('No Textnode with arbitrary ID \'%s\' found.', $textnodeArbitraryId));
170
        }
171
172 2
        if ($textnode->isFinanceNode()) {
173 1
            return $this->redirectToRoute('financenode', ['textnodeArbitraryId' => $textnode->getArbitraryId()]);
174
        }
175
176 1
        $user = $this->getUser();
177
178 1
        $this->readpath->storeReadpath($textnode, $user);
179 1
        $this->favoriteManager->setFavorite($textnode, $user);
180
181 1
        if ($user instanceof User) {
182
            $this->userRepository->save($user);
183
        }
184
185 1
        $hitches = [];
186
187 1
        $childHitches = $textnode->getChildHitches();
188 1
        $index = 0;
189 1
        foreach ($childHitches as $childHitch) {
190
            $hitchedTextnode = $childHitch->getTargetTextnode();
191
            $hitches[] = [
192
                'index' => $index,
193
                'description' => $childHitch->getDescription(),
194
                'arbitraryId' => $hitchedTextnode->getArbitraryId(),
195
                'isFinanceNode' => $hitchedTextnode->isFinanceNode(),
196
            ];
197
            ++$index;
198
        }
199
200 1
        $showBackButton = $this->showBackButton($textnode);
201
202 1
        return $this->templating->renderResponse(
203 1
            'DembeloMain::default/read.html.twig',
204
            [
205 1
                'textnode' => $textnode,
206 1
                'hitches' => $hitches,
207 1
                'showBackButton' => $showBackButton,
208
            ]
209
        );
210
    }
211
212
    /**
213
     * @Route("/paywall/{textnodeId}/{hitchIndex}", name="paywall")
214
     *
215
     * @param string $textnodeId Textnode ID from URL
216
     * @param string $hitchIndex hitch index
217
     *
218
     * @return Response
219
     */
220
    public function paywallAction($textnodeId, $hitchIndex): Response
221
    {
222
        $hitchedTextnode = $this->getTextnodeForHitchIndex($textnodeId, $hitchIndex);
0 ignored issues
show
Bug introduced by
$hitchIndex of type string is incompatible with the type integer expected by parameter $hitchIndex of DembeloMain\Controller\D...TextnodeForHitchIndex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

222
        $hitchedTextnode = $this->getTextnodeForHitchIndex($textnodeId, /** @scrutinizer ignore-type */ $hitchIndex);
Loading history...
223
224
        $url = $this->router->generate('text', ['textnodeArbitraryId' => $hitchedTextnode->getArbitraryId()]);
225
226
        $output = [
227
            'url' => $url,
228
        ];
229
230
        return new Response(\json_encode($output));
231
    }
232
233
    /**
234
     * @Route("/back", name="back")
235
     *
236
     * @return RedirectResponse
237
     */
238 6
    public function backAction(): RedirectResponse
239
    {
240 6
        $parentHitch = $this->getParentHitch();
241 6
        if (null === $parentHitch) {
242 4
            return $this->redirectToRoute('mainpage');
243
        }
244 2
        $parentTextnode = $parentHitch->getSourceTextnode();
245 2
        if ($parentTextnode->getAccess()) {
246 1
            return $this->redirectToRoute('themenfeld', ['topicId' => $parentTextnode->getTopicId()]);
247
        }
248
249 1
        return $this->redirectToRoute(
250 1
            'text',
251 1
            array('textnodeArbitraryId' => $parentTextnode->getArbitraryId())
252
        );
253
    }
254
255
    /**
256
     * @Route("/imprint", name="imprint")
257
     *
258
     * @return Response
259
     */
260 1
    public function imprintAction(): Response
261
    {
262 1
        return $this->templating->renderResponse('DembeloMain::default/imprint.html.twig');
263
    }
264
265
    /**
266
     * @param string $route
267
     * @param array  $parameters
268
     * @param int    $status
269
     *
270
     * @return RedirectResponse
271
     */
272 12
    protected function redirectToRoute($route, array $parameters = array(), $status = 302): RedirectResponse
273
    {
274 12
        $url = $this->router->generate($route, $parameters);
275
276 12
        return new RedirectResponse($url, $status);
277
    }
278
279
    /**
280
     * @return User|null
281
     */
282 10
    protected function getUser(): ?User
283
    {
284 10
        if (null === $token = $this->tokenStorage->getToken()) {
285 9
            return null;
286
        }
287
288 1
        if (!\is_object($user = $token->getUser())) {
289
            // e.g. anonymous authentication
290
            return null;
291
        }
292
293 1
        return $user;
294
    }
295
296
    /**
297
     * @param string $textnodeId
298
     * @param int    $hitchIndex
299
     *
300
     * @return Textnode|null
301
     *
302
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
303
     */
304
    private function getTextnodeForHitchIndex($textnodeId, $hitchIndex): ?Textnode
305
    {
306
        $textnode = $this->textnodeRepository->findOneActiveById($textnodeId);
307
308
        if (null === $textnode) {
309
            throw new NotFoundHttpException(sprintf('No Textnode with ID \'%s\' found.', $textnodeId));
310
        }
311
312
        /* @var $hitch TextnodeHitch */
313
        $hitch = $textnode->getChildHitches()->get($hitchIndex);
314
315
        return $hitch->getTargetTextnode();
316
    }
317
318
    /**
319
     * @param Textnode $textnode
320
     *
321
     * @return bool
322
     */
323 1
    private function showBackButton(Textnode $textnode): bool
324
    {
325 1
        if (false === $textnode->getAccess()) {
326
            return true;
327
        }
328
        $criteria = [
329 1
            'topic_id' => $textnode->getTopicId(),
330
        ];
331 1
        $accessNodes = $this->textnodeRepository->findBy($criteria);
332
333 1
        return (count($accessNodes) >= 2);
334
    }
335
336
    /**
337
     * @return TextnodeHitch|null
338
     */
339 6
    private function getParentHitch(): ?TextnodeHitch
340
    {
341 6
        $user = $this->getUser();
342 6
        $lastTextnodeId = $this->readpath->getCurrentTextnodeId($user);
343
344 6
        if (null === $lastTextnodeId) {
345 1
            return null;
346
        }
347 5
        $lastTextnode = $this->textnodeRepository->find($lastTextnodeId);
348 5
        if (null === $lastTextnode) {
349 1
            return null;
350
        }
351 4
        $parentHitches = $lastTextnode->getParentHitches();
352 4
        if ($parentHitches->isEmpty()) {
353 1
            return null;
354
        }
355
356 3
        return $parentHitches->first();
357
    }
358
}
359