PostController   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 15
dl 0
loc 177
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 23 1
A get() 0 18 1
A edit() 0 21 1
A post() 0 22 2
A delete() 0 21 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Explicit Architecture POC,
7
 * which is created on top of the Symfony Demo application.
8
 *
9
 * (c) Herberto Graça <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Acme\App\Presentation\Web\Core\Component\Blog\Admin\Post;
16
17
use Acme\App\Core\Component\Blog\Application\Query\PostQueryInterface;
18
use Acme\App\Core\Component\Blog\Application\Repository\PostRepositoryInterface;
19
use Acme\App\Core\Component\Blog\Application\Service\PostService;
20
use Acme\App\Core\Component\Blog\Domain\Post\PostId;
21
use Acme\App\Core\Port\Auth\Authentication\AuthenticationServiceInterface;
22
use Acme\App\Core\Port\Auth\Authorization\AuthorizationServiceInterface;
23
use Acme\App\Core\Port\Auth\Authorization\ResourceActionVoterInterface;
24
use Acme\App\Core\Port\Router\UrlGeneratorInterface;
25
use Acme\App\Core\Port\TemplateEngine\TemplateEngineInterface;
26
use Acme\App\Presentation\Web\Core\Port\FlashMessage\FlashMessageServiceInterface;
27
use Acme\App\Presentation\Web\Core\Port\Form\FormFactoryInterface;
28
use Acme\App\Presentation\Web\Core\Port\Response\ResponseFactoryInterface;
29
use Psr\Http\Message\ResponseInterface;
30
use Psr\Http\Message\ServerRequestInterface;
31
32
/**
33
 * Controller used to manage blog contents in the backend.
34
 *
35
 * Please note that the application backend is developed manually for learning
36
 * purposes. However, in your real Symfony application you should use any of the
37
 * existing bundles that let you generate ready-to-use backends without effort.
38
 *
39
 * See http://knpbundles.com/keyword/admin
40
 *
41
 * @author Ryan Weaver <[email protected]>
42
 * @author Javier Eguiluz <[email protected]>
43
 * @author Herberto Graca <[email protected]>
44
 */
45
class PostController
46
{
47
    /**
48
     * @var PostService
49
     */
50
    private $postService;
51
52
    /**
53
     * @var FlashMessageServiceInterface
54
     */
55
    private $flashMessageService;
56
57
    /**
58
     * @var UrlGeneratorInterface
59
     */
60
    private $urlGenerator;
61
62
    /**
63
     * @var TemplateEngineInterface
64
     */
65
    private $templateEngine;
66
67
    /**
68
     * @var ResponseFactoryInterface
69
     */
70
    private $responseFactory;
71
72
    /**
73
     * @var FormFactoryInterface
74
     */
75
    private $formFactory;
76
77
    /**
78
     * @var PostRepositoryInterface
79
     */
80
    private $postRepository;
81
82
    /**
83
     * @var AuthorizationServiceInterface
84
     */
85
    private $authorizationService;
86
87
    /**
88
     * @var AuthenticationServiceInterface
89
     */
90
    private $authenticationService;
91
92
    /**
93
     * @var PostQueryInterface
94
     */
95
    private $postQuery;
96
97
    public function __construct(
98
        PostService $postService,
99
        PostRepositoryInterface $postRepository,
100
        FlashMessageServiceInterface $flashMessageService,
101
        UrlGeneratorInterface $urlGenerator,
102
        TemplateEngineInterface $templateEngine,
103
        ResponseFactoryInterface $responseFactory,
104
        FormFactoryInterface $formFactory,
105
        AuthorizationServiceInterface $authorizationService,
106
        AuthenticationServiceInterface $authenticationService,
107
        PostQueryInterface $postQuery
108
    ) {
109
        $this->postService = $postService;
110
        $this->flashMessageService = $flashMessageService;
111
        $this->urlGenerator = $urlGenerator;
112
        $this->templateEngine = $templateEngine;
113
        $this->responseFactory = $responseFactory;
114
        $this->formFactory = $formFactory;
115
        $this->postRepository = $postRepository;
116
        $this->authorizationService = $authorizationService;
117
        $this->authenticationService = $authenticationService;
118
        $this->postQuery = $postQuery;
119
    }
120
121
    /**
122
     * Finds and displays a Post entity.
123
     */
124
    public function get(ServerRequestInterface $request): ResponseInterface
125
    {
126
        $this->authorizationService->denyAccessUnlessGranted(
127
            [],
128
            ResourceActionVoterInterface::SHOW,
129
            'When the user is authenticated, posts can only be shown to their authors.',
130
            $this->postRepository->find(new PostId($request->getAttribute('id')))
131
        );
132
133
        return $this->templateEngine->renderResponse(
134
            '@Blog/Admin/Post/get.html.twig',
135
            $this->postQuery
136
                ->includeAuthor()
137
                ->includeTags()
138
                ->execute(new PostId($request->getAttribute('id')))
139
                ->hydrateSingleResultAs(GetViewModel::class)
140
        );
141
    }
142
143
    /**
144
     * Displays a form to edit an existing Post entity.
145
     */
146
    public function edit(ServerRequestInterface $request): ResponseInterface
147
    {
148
        $post = $this->postRepository->find(new PostId($request->getAttribute('id')));
149
150
        $this->authorizationService->denyAccessUnlessGranted(
151
            [],
152
            ResourceActionVoterInterface::EDIT,
153
            'Posts can only be edited by their authors.',
154
            $post
155
        );
156
157
        $form = $this->formFactory->createEditPostForm(
158
            $post,
159
            ['action' => $this->urlGenerator->generateUrl('admin_post_post', ['id' => (string) $post->getId()])]
160
        );
161
162
        return $this->templateEngine->renderResponse(
163
            '@Blog/Admin/Post/edit.html.twig',
164
            EditViewModel::fromPostAndForm($post, $form)
165
        );
166
    }
167
168
    /**
169
     * Receives data from the form to edit an existing Post entity.
170
     */
171
    public function post(ServerRequestInterface $request): ResponseInterface
172
    {
173
        $post = $this->postRepository->find(new PostId($request->getAttribute('id')));
174
175
        $this->authorizationService->denyAccessUnlessGranted(
176
            [],
177
            ResourceActionVoterInterface::EDIT,
178
            'Posts can only be edited by their authors.',
179
            $post
180
        );
181
182
        $form = $this->formFactory->createEditPostForm($post);
183
        $form->handleRequest($request);
184
185
        if (!($form->shouldBeProcessed())) {
186
            return $this->responseFactory->redirectToRoute('admin_post_edit', ['id' => (string) $post->getId()]);
187
        }
188
189
        $this->flashMessageService->success('post.updated_successfully');
190
191
        return $this->responseFactory->redirectToRoute('admin_post_edit', ['id' => (string) $post->getId()]);
192
    }
193
194
    /**
195
     * Deletes a Post entity.
196
     *
197
     * The Security annotation value is an expression (if it evaluates to false,
198
     * the authorization mechanism will prevent the user accessing this resource).
199
     */
200
    public function delete(ServerRequestInterface $request): ResponseInterface
201
    {
202
        $post = $this->postRepository->find(new PostId($request->getAttribute('id')));
203
204
        $this->authorizationService->denyAccessUnlessGranted(
205
            [],
206
            ResourceActionVoterInterface::DELETE,
207
            'Posts can only be deleted by an admin or the author.',
208
            $post
209
        );
210
211
        if (!$this->authenticationService->isCsrfTokenValid('delete', $request->getParsedBody()['token'] ?? '')) {
212
            return $this->responseFactory->redirectToRoute('admin_post_list');
213
        }
214
215
        $this->postService->delete($post);
216
217
        $this->flashMessageService->success('post.deleted_successfully');
218
219
        return $this->responseFactory->redirectToRoute('admin_post_list');
220
    }
221
}
222