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\PostList; |
16
|
|
|
|
17
|
|
|
use Acme\App\Core\Component\Blog\Application\Query\PostDto; |
18
|
|
|
use Acme\App\Core\Component\Blog\Application\Query\PostListQueryInterface; |
19
|
|
|
use Acme\App\Core\Component\Blog\Application\Service\PostService; |
20
|
|
|
use Acme\App\Core\Component\Blog\Domain\Post\Post; |
21
|
|
|
use Acme\App\Core\Port\Auth\Authentication\AuthenticationServiceInterface; |
22
|
|
|
use Acme\App\Core\Port\Router\UrlGeneratorInterface; |
23
|
|
|
use Acme\App\Core\Port\TemplateEngine\TemplateEngineInterface; |
24
|
|
|
use Acme\App\Presentation\Web\Core\Port\FlashMessage\FlashMessageServiceInterface; |
25
|
|
|
use Acme\App\Presentation\Web\Core\Port\Form\FormFactoryInterface; |
26
|
|
|
use Acme\App\Presentation\Web\Core\Port\Form\FormInterface; |
27
|
|
|
use Acme\App\Presentation\Web\Core\Port\Response\ResponseFactoryInterface; |
28
|
|
|
use Psr\Http\Message\ResponseInterface; |
29
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Controller used to manage blog contents in the backend. |
33
|
|
|
* |
34
|
|
|
* Please note that the application backend is developed manually for learning |
35
|
|
|
* purposes. However, in your real Symfony application you should use any of the |
36
|
|
|
* existing bundles that let you generate ready-to-use backends without effort. |
37
|
|
|
* |
38
|
|
|
* See http://knpbundles.com/keyword/admin |
39
|
|
|
* |
40
|
|
|
* @author Ryan Weaver <[email protected]> |
41
|
|
|
* @author Javier Eguiluz <[email protected]> |
42
|
|
|
* @author Herberto Graca <[email protected]> |
43
|
|
|
*/ |
44
|
|
|
class PostListController |
45
|
|
|
{ |
46
|
|
|
/** |
47
|
|
|
* @var PostService |
48
|
|
|
*/ |
49
|
|
|
private $postService; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var FlashMessageServiceInterface |
53
|
|
|
*/ |
54
|
|
|
private $flashMessageService; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var UrlGeneratorInterface |
58
|
|
|
*/ |
59
|
|
|
private $urlGenerator; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var TemplateEngineInterface |
63
|
|
|
*/ |
64
|
|
|
private $templateEngine; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var ResponseFactoryInterface |
68
|
|
|
*/ |
69
|
|
|
private $responseFactory; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @var FormFactoryInterface |
73
|
|
|
*/ |
74
|
|
|
private $formFactory; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @var AuthenticationServiceInterface |
78
|
|
|
*/ |
79
|
|
|
private $authenticationService; |
80
|
|
|
|
81
|
|
View Code Duplication |
public function __construct( |
|
|
|
|
82
|
|
|
PostService $postService, |
83
|
|
|
FlashMessageServiceInterface $flashMessageService, |
84
|
|
|
UrlGeneratorInterface $urlGenerator, |
85
|
|
|
TemplateEngineInterface $templateEngine, |
86
|
|
|
ResponseFactoryInterface $responseFactory, |
87
|
|
|
FormFactoryInterface $formFactory, |
88
|
|
|
AuthenticationServiceInterface $authenticationService |
89
|
|
|
) { |
90
|
|
|
$this->postService = $postService; |
91
|
|
|
$this->flashMessageService = $flashMessageService; |
92
|
|
|
$this->urlGenerator = $urlGenerator; |
93
|
|
|
$this->templateEngine = $templateEngine; |
94
|
|
|
$this->responseFactory = $responseFactory; |
95
|
|
|
$this->formFactory = $formFactory; |
96
|
|
|
$this->authenticationService = $authenticationService; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Lists all Post entities. |
101
|
|
|
* |
102
|
|
|
* This controller responds to two different routes with the same URL: |
103
|
|
|
* 'admin_post_list' is the route with a name that follows the same |
104
|
|
|
* structure as the rest of the controllers of this class. |
105
|
|
|
* 'admin_index' is a nice shortcut to the backend homepage. This allows |
106
|
|
|
* to create simpler links in the templates. Moreover, in the future we |
107
|
|
|
* could move this annotation to any other controller while maintaining |
108
|
|
|
* the route name and therefore, without breaking any existing link. |
109
|
|
|
*/ |
110
|
|
|
public function get(PostListQueryInterface $postListQuery): ResponseInterface |
111
|
|
|
{ |
112
|
|
|
$postDtoList = $postListQuery->execute($this->authenticationService->getLoggedInUserId()) |
113
|
|
|
->hydrateResultItemsAs(PostDto::class); |
114
|
|
|
|
115
|
|
|
return $this->templateEngine->renderResponse( |
116
|
|
|
'@Blog/Admin/PostList/get.html.twig', |
117
|
|
|
GetViewModel::fromPostDtoList(...$postDtoList) |
118
|
|
|
); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Shows the form to create a new Post entity. |
123
|
|
|
* |
124
|
|
|
* NOTE: the Method annotation is optional, but it's a recommended practice |
125
|
|
|
* to constraint the HTTP methods each controller responds to (by default |
126
|
|
|
* it responds to all methods). |
127
|
|
|
*/ |
128
|
|
|
public function new(): ResponseInterface |
129
|
|
|
{ |
130
|
|
|
$form = $this->createCreatePostForm(new Post()); |
131
|
|
|
|
132
|
|
|
return $this->renderCreatePost($form); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* Creates a new Post entity. |
137
|
|
|
* |
138
|
|
|
* NOTE: the Method annotation is optional, but it's a recommended practice |
139
|
|
|
* to constraint the HTTP methods each controller responds to (by default |
140
|
|
|
* it responds to all methods). |
141
|
|
|
*/ |
142
|
|
|
public function post(ServerRequestInterface $request): ResponseInterface |
143
|
|
|
{ |
144
|
|
|
$post = new Post(); |
145
|
|
|
|
146
|
|
|
$form = $this->createCreatePostForm($post); |
147
|
|
|
|
148
|
|
|
$form->handleRequest($request); |
149
|
|
|
|
150
|
|
|
// the isSubmitted() method is completely optional because the other |
151
|
|
|
// isValid() method already checks whether the form is submitted. |
152
|
|
|
// However, we explicitly add it to improve code readability. |
153
|
|
|
// See https://symfony.com/doc/current/best_practices/forms.html#handling-form-submits |
154
|
|
|
if (!$form->shouldBeProcessed()) { |
155
|
|
|
return $this->renderCreatePost($form); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$this->postService->create($post, $this->authenticationService->getLoggedInUserId()); |
159
|
|
|
|
160
|
|
|
// Flash messages are used to notify the user about the result of the |
161
|
|
|
// actions. They are deleted automatically from the session as soon |
162
|
|
|
// as they are accessed. |
163
|
|
|
// See https://symfony.com/doc/current/book/controller.html#flash-messages |
164
|
|
|
$this->flashMessageService->success('post.created_successfully'); |
165
|
|
|
|
166
|
|
|
// See https://symfony.com/doc/current/book/forms.html#submitting-forms-with-multiple-buttons |
167
|
|
|
if ($form->clickedButton(FormInterface::BUTTON_NAME_SAVE_AND_CREATE_NEW)) { |
168
|
|
|
return $this->responseFactory->redirectToRoute('admin_post_new'); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return $this->responseFactory->redirectToRoute('admin_post_list'); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
protected function createCreatePostForm(Post $post): FormInterface |
175
|
|
|
{ |
176
|
|
|
return $this->formFactory->createCreatePostForm( |
177
|
|
|
$post, |
178
|
|
|
['action' => $this->urlGenerator->generateUrl('admin_post_new_post')] |
179
|
|
|
); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
protected function renderCreatePost(FormInterface $form): ResponseInterface |
183
|
|
|
{ |
184
|
|
|
return $this->templateEngine->renderResponse( |
185
|
|
|
'@Blog/Admin/PostList/new.html.twig', |
186
|
|
|
NewViewModel::fromPostAndForm($form) |
187
|
|
|
); |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
|
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.