]> Raphaël G. Git Repositories - blogbundle/blob - Controller/ArticleController.php
Add article controller with index and view member functions
[blogbundle] / Controller / ArticleController.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys BlogBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\BlogBundle\Controller;
13
14 use Symfony\Component\HttpFoundation\Request;
15 use Symfony\Component\HttpFoundation\Response;
16
17 use Rapsys\BlogBundle\Entity\Article;
18 use Rapsys\BlogBundle\Entity\Keyword;
19
20 /**
21 * {@inheritdoc}
22 */
23 class ArticleController extends AbstractController {
24 /**
25 * The article index
26 *
27 * Display articles
28 *
29 * @param Request $request The request instance
30 * @return Response The rendered view
31 */
32 public function index(Request $request): Response {
33 //With articles
34 if ($count = $this->doctrine->getRepository(Article::class)->findCountAsInt()) {
35 //Negative page or over page
36 if (($page = (int) $request->get('page', 0)) < 0 || $page > $count / $this->limit) {
37 //Throw 404
38 throw $this->createNotFoundException($this->translator->trans('Unable to find articles (page: %page%)', ['%page%' => $page]));
39 }
40
41 //Without articles
42 if (empty($this->context['articles'] = $this->doctrine->getRepository(Article::class)->findAllAsArray($page, $this->limit))) {
43 //Throw 404
44 throw $this->createNotFoundException($this->translator->trans('Unable to find articles'));
45 }
46
47 //With prev link
48 if ($page > 0) {
49 //Set articles older
50 $this->context['head']['prev'] = $this->context['articles_prev'] = $this->generateUrl($request->attributes->get('_route'), ['page' => $page - 1]+$request->attributes->get('_route_params'));
51 }
52
53 //With next link
54 if ($count > ($page + 1) * $this->limit) {
55 //Set articles newer
56 $this->context['head']['next'] = $this->context['articles_next'] = $this->generateUrl($request->attributes->get('_route'), ['page' => $page + 1]+$request->attributes->get('_route_params'));
57 }
58
59 //Set modified
60 $this->modified = max(array_map(function ($v) { return $v['modified']; }, $this->context['articles']));
61 //Without articles
62 } else {
63 //Set empty articles
64 $this->context['articles'] = [];
65
66 //Set empty modified
67 $this->modified = new \DateTime('-1 year');
68 }
69
70 //Create response
71 $response = new Response();
72
73 //With logged user
74 if ($this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
75 //Set last modified
76 $response->setLastModified(new \DateTime('-1 year'));
77
78 //Set as private
79 $response->setPrivate();
80 //Without logged user
81 } else {
82 //Set etag
83 //XXX: only for public to force revalidation by last modified
84 $response->setEtag(md5(serialize($this->context['articles'])));
85
86 //Set last modified
87 $response->setLastModified($this->modified);
88
89 //Set as public
90 $response->setPublic();
91
92 //Without role and modification
93 if ($response->isNotModified($request)) {
94 //Return 304 response
95 return $response;
96 }
97 }
98
99 //Set keywords
100 $this->context['head']['keywords'] = implode(
101 ', ',
102 //Use closure to extract each unique article keywords sorted
103 (function ($t) {
104 //Return array
105 $r = [];
106
107 //Iterate on articles
108 foreach($t as $a) {
109 //Non empty keywords
110 if (!empty($a['keywords'])) {
111 //Iterate on keywords
112 foreach($a['keywords'] as $k) {
113 //Set keyword
114 $r[$k['title']] = $k['title'];
115 }
116 }
117 }
118
119 //Sort array
120 sort($r);
121
122 //Return array
123 return $r;
124 })($this->context['articles'])
125 );
126
127 //Set title
128 $this->context['title'] = $this->translator->trans('Articles list');
129
130 //Set description
131 $this->context['description'] = $this->translator->trans('Welcome to raphaël\'s developer diary article listing');
132
133 //Render the view
134 return $this->render('@RapsysBlog/article/index.html.twig', $this->context, $response);
135 }
136
137 /**
138 * The article view
139 *
140 * Display article and keywords
141 *
142 * @param Request $request The request instance
143 * @param integer $id The article id
144 * @param ?string $slug The article slug
145 * @return Response The rendered view
146 */
147 public function view(Request $request, int $id, ?string $slug): Response {
148 //Without article
149 if (empty($this->context['article'] = $this->doctrine->getRepository(Article::class)->findByIdAsArray($id))) {
150 //Throw 404
151 throw $this->createNotFoundException($this->translator->trans('Unable to find article: %id%', ['%id%' => $id]));
152 }
153
154 //With invalid slug
155 if ($slug !== $this->context['article']['slug']) {
156 //Redirect on correctly spelled article
157 return $this->redirectToRoute('rapsys_blog_article_view', ['id' => $this->context['article']['id'], 'slug' => $this->context['article']['slug']], Response::HTTP_MOVED_PERMANENTLY);
158 }
159
160 //Set modified
161 $this->modified = $this->context['article']['modified'];
162
163 //Create response
164 $response = new Response();
165
166 //With logged user
167 if ($this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
168 //Set last modified
169 $response->setLastModified(new \DateTime('-1 year'));
170
171 //Set as private
172 $response->setPrivate();
173 //Without logged user
174 } else {
175 //Set etag
176 //XXX: only for public to force revalidation by last modified
177 $response->setEtag(md5(serialize($this->context['article'])));
178
179 //Set last modified
180 $response->setLastModified($this->modified);
181
182 //Set as public
183 $response->setPublic();
184
185 //Without role and modification
186 if ($response->isNotModified($request)) {
187 //Return 304 response
188 return $response;
189 }
190 }
191
192 //Set keywords
193 $this->context['head']['keywords'] = implode(
194 ', ',
195 array_map(
196 function ($v) {
197 return $v['title'];
198 },
199 $this->context['article']['keywords']
200 )
201 );
202
203 //Set keywords
204 $this->context['head']['keywords'] = implode(
205 ', ',
206 //Use closure to extract each unique article keywords sorted
207 (function ($a) {
208 //Return array
209 $r = [];
210
211 //Non empty keywords
212 if (!empty($a['keywords'])) {
213 //Iterate on keywords
214 foreach($a['keywords'] as $k) {
215 //Set keyword
216 $r[$k['title']] = $k['title'];
217 }
218 }
219
220 //Sort array
221 sort($r);
222
223 //Return array
224 return $r;
225 })($this->context['article'])
226 );
227
228 //Set title
229 $this->context['title'] = $this->context['article']['title'];
230
231 //Set description
232 $this->context['description'] = $this->context['article']['description'];
233
234 //Render the view
235 return $this->render('@RapsysBlog/article/view.html.twig', $this->context, $response);
236 }
237 }