1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AppBundle\Controller; |
4
|
|
|
|
5
|
|
|
use AppBundle\Controller\Infrastructure\RestController; |
6
|
|
|
use AppBundle\Entity\DTO\CreateEventDTO; |
7
|
|
|
use AppBundle\Entity\Event; |
8
|
|
|
use AppBundle\Entity\Repository\EventRepository; |
9
|
|
|
use AppBundle\Exception\UnsupportedTypeException; |
10
|
|
|
use AppBundle\Response\ApiError; |
11
|
|
|
use AppBundle\Response\CollectionApiResponse; |
12
|
|
|
use AppBundle\Response\CreatedApiResponse; |
13
|
|
|
use AppBundle\Response\EmptyApiResponse; |
14
|
|
|
use AppBundle\Response\LocationApiResponse; |
15
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException; |
16
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
17
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
18
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
19
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; |
20
|
|
|
use Symfony\Component\Form\Extension\Core\Type\DateType; |
21
|
|
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType; |
22
|
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType; |
23
|
|
|
use Symfony\Component\Form\FormBuilder; |
24
|
|
|
use Symfony\Component\Form\FormError; |
25
|
|
|
use Symfony\Component\Form\FormInterface; |
26
|
|
|
use Symfony\Component\HttpFoundation\Request; |
27
|
|
|
use Symfony\Component\HttpFoundation\Response; |
28
|
|
|
use AppBundle\Response\ApiResponse; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @Route("event") |
32
|
|
|
* @author Vehsamrak |
33
|
|
|
*/ |
34
|
|
|
class EventController extends RestController |
35
|
|
|
{ |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Find events by name part |
39
|
|
|
* @Route("s/like/{searchString}/{limit}/{offset}", name="events_find_like") |
40
|
|
|
* @Method("GET") |
41
|
|
|
* @ApiDoc( |
42
|
|
|
* section="Event", |
43
|
|
|
* statusCodes={ |
44
|
|
|
* 200="OK", |
45
|
|
|
* } |
46
|
|
|
* ) |
47
|
|
|
* @param string $searchString Search string |
48
|
|
|
* @param int $limit Limit results. Default is 50 |
49
|
4 |
|
* @param int $offset Starting serial number of result collection. Default is 0 |
50
|
|
|
*/ |
51
|
4 |
|
public function findLikeAction($searchString = null, $limit = null, $offset = null) |
52
|
4 |
|
{ |
53
|
4 |
|
$eventRepository = $this->get('rockparade.event_repository'); |
54
|
|
|
$events = $eventRepository->findLike($searchString); |
55
|
4 |
|
$total = $events->count(); |
56
|
4 |
|
|
57
|
|
|
$limit = (int) filter_var($limit, FILTER_VALIDATE_INT); |
58
|
4 |
|
$offset = (int) filter_var($offset, FILTER_VALIDATE_INT); |
59
|
2 |
|
|
60
|
|
|
if ($limit || $offset) { |
61
|
|
|
$events = $events->slice($offset, $limit ?: null); |
62
|
4 |
|
} |
63
|
|
|
|
64
|
4 |
|
$response = new CollectionApiResponse( |
65
|
|
|
$events, |
66
|
|
|
Response::HTTP_OK, |
67
|
|
|
$total, |
68
|
|
|
$limit, |
69
|
|
|
$offset |
70
|
4 |
|
); |
71
|
|
|
|
72
|
|
|
return $this->respond($response); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* List all events |
77
|
|
|
* @Route("s/{limit}/{offset}", name="events_list") |
78
|
|
|
* @Method("GET") |
79
|
|
|
* @ApiDoc( |
80
|
|
|
* section="Event", |
81
|
|
|
* statusCodes={ |
82
|
|
|
* 200="OK", |
83
|
|
|
* } |
84
|
|
|
* ) |
85
|
|
|
* @param int $limit Limit results. Default is 50 |
86
|
1 |
|
* @param int $offset Starting serial number of result collection. Default is 0 |
87
|
|
|
*/ |
88
|
1 |
|
public function listAction($limit = null, $offset = null): Response |
89
|
1 |
|
{ |
90
|
1 |
|
return $this->respond( |
91
|
|
|
$this->createCollectionResponse( |
92
|
|
|
$this->get('rockparade.event_repository'), |
93
|
|
|
$limit, |
94
|
|
|
$offset |
95
|
|
|
) |
96
|
|
|
); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* View event by id |
101
|
|
|
* @Route("/{eventId}", name="event_view") |
102
|
|
|
* @Method("GET") |
103
|
|
|
* @ApiDoc( |
104
|
|
|
* section="Event", |
105
|
|
|
* statusCodes={ |
106
|
|
|
* 200="Event was found", |
107
|
|
|
* 404="Event with given id was not found", |
108
|
|
|
* } |
109
|
|
|
* ) |
110
|
3 |
|
* @param string $eventId event id |
111
|
|
|
*/ |
112
|
|
View Code Duplication |
public function viewAction(string $eventId): Response |
|
|
|
|
113
|
3 |
|
{ |
114
|
3 |
|
/** @var EventRepository $eventRepository */ |
115
|
|
|
$eventRepository = $this->get('rockparade.event_repository'); |
116
|
3 |
|
$event = $eventRepository->findOneById($eventId); |
117
|
2 |
|
|
118
|
|
|
if ($event) { |
119
|
1 |
|
$response = new ApiResponse($event, Response::HTTP_OK); |
120
|
|
|
} else { |
121
|
|
|
$response = $this->createEventNotFoundErrorResult($eventId); |
122
|
3 |
|
} |
123
|
|
|
|
124
|
|
|
return $this->respond($response); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Create new event |
129
|
|
|
* @Route("") |
130
|
|
|
* @Method("POST") |
131
|
|
|
* @Security("has_role('ROLE_USER')") |
132
|
|
|
* @ApiDoc( |
133
|
|
|
* section="Event", |
134
|
|
|
* requirements={ |
135
|
|
|
* { |
136
|
|
|
* "name"="name", |
137
|
|
|
* "dataType"="string", |
138
|
|
|
* "requirement"="true", |
139
|
|
|
* "description"="event name" |
140
|
|
|
* }, |
141
|
|
|
* { |
142
|
|
|
* "name"="date", |
143
|
|
|
* "dataType"="date (dd-MM-yyyy HH:mm)", |
144
|
|
|
* "requirement"="true", |
145
|
|
|
* "description"="event date" |
146
|
|
|
* }, |
147
|
|
|
* { |
148
|
|
|
* "name"="description", |
149
|
|
|
* "dataType"="text", |
150
|
|
|
* "requirement"="true", |
151
|
|
|
* "description"="event description" |
152
|
|
|
* }, |
153
|
|
|
* }, |
154
|
|
|
* statusCodes={ |
155
|
|
|
* 201="New event was created. Link to new resource in header 'Location'", |
156
|
|
|
* 400="Validation error", |
157
|
|
|
* } |
158
|
2 |
|
* ) |
159
|
|
|
*/ |
160
|
2 |
|
public function createAction(Request $request): Response |
161
|
2 |
|
{ |
162
|
|
|
$form = $this->createEventCreationForm(); |
163
|
2 |
|
$this->processForm($request, $form); |
164
|
1 |
|
|
165
|
|
|
if ($form->isValid()) { |
166
|
|
|
$newEvent = $this->createEventByForm($form); |
167
|
1 |
|
|
168
|
1 |
|
/** @var EventRepository $eventRepository */ |
169
|
|
|
$eventRepository = $this->get('rockparade.event_repository'); |
170
|
|
|
$eventRepository->persist($newEvent); |
171
|
1 |
|
|
172
|
1 |
|
try { |
173
|
|
|
$eventRepository->flush(); |
174
|
|
|
$response = new CreatedApiResponse($this->createLocationById($newEvent->getId())); |
175
|
1 |
|
} catch (UniqueConstraintViolationException $exception) { |
176
|
|
|
$form->addError(new FormError('Event must have unique name and date.')); |
177
|
|
|
$response = new ApiError($this->getFormErrors($form), Response::HTTP_BAD_REQUEST); |
178
|
|
|
} |
179
|
1 |
|
|
180
|
|
|
} else { |
181
|
|
|
$response = new ApiError($this->getFormErrors($form), Response::HTTP_BAD_REQUEST); |
182
|
2 |
|
} |
183
|
|
|
|
184
|
|
|
return $this->respond($response); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Edit event |
189
|
|
|
* @Route("/{eventId}", name="event_edit") |
190
|
|
|
* @Method("PUT") |
191
|
|
|
* @Security("has_role('ROLE_USER')") |
192
|
|
|
* @ApiDoc( |
193
|
|
|
* section="Event", |
194
|
|
|
* requirements={ |
195
|
|
|
* { |
196
|
|
|
* "name"="name", |
197
|
|
|
* "dataType"="string", |
198
|
|
|
* "requirement"="true", |
199
|
|
|
* "description"="event name" |
200
|
|
|
* }, |
201
|
|
|
* { |
202
|
|
|
* "name"="date", |
203
|
|
|
* "dataType"="date (dd-MM-yyyy HH:mm)", |
204
|
|
|
* "requirement"="true", |
205
|
|
|
* "description"="event date" |
206
|
|
|
* }, |
207
|
|
|
* { |
208
|
|
|
* "name"="description", |
209
|
|
|
* "dataType"="string", |
210
|
|
|
* "requirement"="true", |
211
|
|
|
* "description"="event description" |
212
|
|
|
* }, |
213
|
|
|
* }, |
214
|
|
|
* statusCodes={ |
215
|
|
|
* 204="Event was edited with new data", |
216
|
|
|
* 400="Validation error", |
217
|
|
|
* 404="Event with given id was not found", |
218
|
|
|
* } |
219
|
|
|
* ) |
220
|
2 |
|
* @param string $eventId event id |
221
|
|
|
*/ |
222
|
2 |
|
public function editAction(Request $request, string $eventId): Response |
223
|
2 |
|
{ |
224
|
|
|
$form = $this->createEventCreationForm(); |
225
|
2 |
|
$this->processForm($request, $form); |
226
|
|
|
|
227
|
1 |
|
if ($form->isValid()) { |
228
|
|
|
/** @var EventRepository $eventRepository */ |
229
|
1 |
|
$eventRepository = $this->get('rockparade.event_repository'); |
230
|
|
|
/** @var Event $event */ |
231
|
1 |
|
$event = $eventRepository->findOneById($eventId); |
232
|
|
|
|
233
|
|
|
if (!$event) { |
234
|
1 |
|
$response = $this->createEventNotFoundErrorResult($eventId); |
235
|
|
|
} else { |
236
|
1 |
|
$eventName = $form->get('name')->getData(); |
237
|
1 |
|
/** @var \DateTime $eventDate */ |
238
|
|
|
$eventDate = $form->get('date')->getData(); |
239
|
1 |
|
$eventDescription = $form->get('description')->getData(); |
240
|
1 |
|
|
241
|
1 |
|
$event->setName($eventName); |
242
|
|
|
$event->setDate($eventDate); |
243
|
|
|
$event->setDescription($eventDescription); |
244
|
1 |
|
|
245
|
1 |
|
try { |
246
|
|
|
$eventRepository->flush(); |
247
|
1 |
|
$response = new EmptyApiResponse(Response::HTTP_NO_CONTENT); |
248
|
|
|
} catch (UniqueConstraintViolationException $exception) { |
249
|
|
|
$response = new ApiError(['Event must have unique name and date.'], Response::HTTP_BAD_REQUEST); |
250
|
|
|
} |
251
|
|
|
} |
252
|
1 |
|
|
253
|
|
|
} else { |
254
|
|
|
$response = new ApiError($this->getFormErrors($form), Response::HTTP_BAD_REQUEST); |
255
|
2 |
|
} |
256
|
|
|
|
257
|
|
|
return $this->respond($response); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Delete event |
262
|
|
|
* @Route("/{eventId}", name="event_delete") |
263
|
|
|
* @Method("DELETE") |
264
|
|
|
* @Security("has_role('ROLE_USER')") |
265
|
|
|
* @ApiDoc( |
266
|
|
|
* section="Event", |
267
|
|
|
* statusCodes={ |
268
|
|
|
* 204="Event was deleted", |
269
|
|
|
* 404="Event with given id was not found", |
270
|
|
|
* } |
271
|
|
|
* ) |
272
|
1 |
|
* @param string $eventId event id |
273
|
|
|
*/ |
274
|
|
View Code Duplication |
public function deleteEvent(string $eventId): Response |
|
|
|
|
275
|
1 |
|
{ |
276
|
1 |
|
/** @var EventRepository $eventRepository */ |
277
|
|
|
$eventRepository = $this->get('rockparade.event_repository'); |
278
|
1 |
|
$event = $eventRepository->findOneById($eventId); |
279
|
1 |
|
|
280
|
1 |
|
if ($event) { |
281
|
|
|
$eventRepository->remove($event); |
282
|
1 |
|
$eventRepository->flush(); |
283
|
|
|
|
284
|
|
|
$response = new EmptyApiResponse(Response::HTTP_NO_CONTENT); |
285
|
|
|
} else { |
286
|
|
|
$response = $this->createEventNotFoundErrorResult($eventId); |
287
|
|
|
} |
288
|
1 |
|
|
289
|
|
|
return $this->respond($response); |
290
|
|
|
} |
291
|
1 |
|
|
292
|
|
|
/** |
293
|
1 |
|
* Add image to event |
294
|
1 |
|
* @Route("/{eventId}/image", name="event_image_add") |
295
|
1 |
|
* @Method("POST") |
296
|
|
|
* @Security("has_role('ROLE_USER')") |
297
|
|
|
* @ApiDoc( |
298
|
|
|
* section="Event", |
299
|
4 |
|
* statusCodes={ |
300
|
|
|
* 404="Event with given id was not found", |
301
|
|
|
* } |
302
|
4 |
|
* ) |
303
|
4 |
|
* @param string $eventId event id |
304
|
4 |
|
*/ |
305
|
4 |
|
public function addImageAction(Request $request, string $eventId): Response |
306
|
4 |
|
{ |
307
|
|
|
/** @var EventRepository $eventRepository */ |
308
|
4 |
|
$eventRepository = $this->get('rockparade.event_repository'); |
309
|
|
|
$event = $eventRepository->findOneById($eventId); |
310
|
|
|
|
311
|
|
|
if ($event) { |
312
|
4 |
|
$image = $request->get('image'); |
313
|
|
|
|
314
|
4 |
|
$imageName = $image['name'] ?: null; |
315
|
|
|
$imageContent = $image['content'] ?? null; |
316
|
|
|
|
317
|
1 |
|
if (!$image || !$imageName || !$imageContent) { |
318
|
|
|
$response = new ApiError( |
319
|
1 |
|
'Parameters are mandatory: image[name] and image[content].', |
320
|
|
|
Response::HTTP_BAD_REQUEST |
321
|
|
|
); |
322
|
1 |
|
} else { |
323
|
|
|
try { |
324
|
|
|
$imageExtensionChecker = $this->get('rockparade.image_extension_checker'); |
325
|
1 |
|
$imageExtension = $imageExtensionChecker->getExtensionFromBase64File($imageContent); |
326
|
1 |
|
$imageName = sprintf('%s.%s', $imageName, $imageExtension); |
327
|
|
|
|
328
|
1 |
|
$imageLocation = $this->generateUrl( |
329
|
|
|
'event_image_view', |
330
|
|
|
[ |
331
|
|
|
'eventId' => $eventId, |
332
|
|
|
'imageName' => $imageName, |
333
|
|
|
] |
334
|
|
|
); |
335
|
|
|
|
336
|
|
|
$fileService = $this->get('rockparade.file_service'); |
337
|
|
|
$fileService->createBase64Image($imageName, $imageContent, $event); |
338
|
|
|
|
339
|
|
|
$response = new LocationApiResponse(Response::HTTP_OK, $imageLocation); |
340
|
|
|
} catch (UnsupportedTypeException $exception) { |
341
|
|
|
$response = new ApiError( |
342
|
|
|
'Only images of types png, gif and jpeg are supported.', |
343
|
|
|
Response::HTTP_BAD_REQUEST |
344
|
|
|
); |
345
|
|
|
} |
346
|
|
|
} |
347
|
|
|
} else { |
348
|
|
|
$response = $this->createEventNotFoundErrorResult($eventId); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
return $this->respond($response); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Get event image |
356
|
|
|
* @Route("/{eventId}/image/{imageName}", name="event_image_view") |
357
|
|
|
* @Method("GET") |
358
|
|
|
* @ApiDoc( |
359
|
|
|
* section="Event", |
360
|
|
|
* statusCodes={ |
361
|
|
|
* 404="Event with given id was not found", |
362
|
|
|
* 404="Image with given name was not found", |
363
|
|
|
* } |
364
|
|
|
* ) |
365
|
|
|
* @param string $eventId event id |
366
|
|
|
* @param string $imageName image name |
367
|
|
|
*/ |
368
|
|
|
public function viewImageAction(string $eventId, string $imageName): Response |
369
|
|
|
{ |
370
|
|
|
/** @var EventRepository $eventRepository */ |
371
|
|
|
$eventRepository = $this->get('rockparade.event_repository'); |
372
|
|
|
$event = $eventRepository->findOneById($eventId); |
373
|
|
|
|
374
|
|
|
if ($event) { |
375
|
|
|
$image = $event->getImageWithName($imageName); |
376
|
|
|
$apiResponseFactory = $this->get('rockparade.api_response_factory'); |
377
|
|
|
|
378
|
|
|
if ($image) { |
379
|
|
|
$response = $apiResponseFactory->createResponse($image); |
380
|
|
|
} else { |
381
|
|
|
$response = $apiResponseFactory->createNotFoundResponse(); |
382
|
|
|
} |
383
|
|
|
} else { |
384
|
|
|
$response = $this->createEventNotFoundErrorResult($eventId); |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
return $this->respond($response); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
private function createEventNotFoundErrorResult(string $eventId): ApiError |
391
|
|
|
{ |
392
|
|
|
return new ApiError( |
393
|
|
|
sprintf('Event with id "%s" was not found.', $eventId), |
394
|
|
|
Response::HTTP_NOT_FOUND |
395
|
|
|
); |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
private function createEventCreationForm(): FormInterface |
399
|
|
|
{ |
400
|
|
|
/** @var FormBuilder $formBuilder */ |
401
|
|
|
$formBuilder = $this->createFormBuilder(new CreateEventDTO()); |
402
|
|
|
$formBuilder->add('name', TextType::class); |
403
|
|
|
$formBuilder->add( |
404
|
|
|
'date', |
405
|
|
|
DateType::class, |
406
|
|
|
[ |
407
|
|
|
'widget' => 'single_text', |
408
|
|
|
'format' => 'yyyy-MM-dd HH:mm', |
409
|
|
|
] |
410
|
|
|
); |
411
|
|
|
$formBuilder->add('description', TextareaType::class); |
412
|
|
|
|
413
|
|
|
return $formBuilder->getForm(); |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
private function createLocationById(string $eventId): string |
417
|
|
|
{ |
418
|
|
|
return $this->generateUrl('event_view', ['eventId' => $eventId]); |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
private function createEventByForm(FormInterface $form): Event |
422
|
|
|
{ |
423
|
|
|
/** @var CreateEventDTO $createEventDTO */ |
424
|
|
|
$createEventDTO = $form->getData(); |
425
|
|
|
$creator = $this->getUser(); |
426
|
|
|
|
427
|
|
|
return new Event($createEventDTO->name, $creator, $createEventDTO->date, $createEventDTO->description); |
|
|
|
|
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
|
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.