1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AppBundle\Controller; |
4
|
|
|
|
5
|
|
|
use AppBundle\Entity\DTO\CreateBandMemberDTO; |
6
|
|
|
use AppBundle\Entity\DTO\CreateBand; |
7
|
|
|
use AppBundle\Entity\DTO\UpdateBandMemberDTO; |
8
|
|
|
use AppBundle\Entity\Repository\BandRepository; |
9
|
|
|
use AppBundle\Response\ApiValidationError; |
10
|
|
|
use AppBundle\Response\CreatedApiResponse; |
11
|
|
|
use AppBundle\Response\EmptyApiResponse; |
12
|
|
|
use AppBundle\Response\Infrastructure\AbstractApiResponse; |
13
|
|
|
use AppBundle\Service\BandService; |
14
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; |
15
|
|
|
use Symfony\Component\Form\Form; |
16
|
|
|
use AppBundle\Controller\Infrastructure\RestController; |
17
|
|
|
use AppBundle\Response\ApiError; |
18
|
|
|
use AppBundle\Response\ApiResponse; |
19
|
|
|
use Nelmio\ApiDocBundle\Annotation\ApiDoc; |
20
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
21
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
22
|
|
|
use Symfony\Component\Form\Extension\Core\Type\TextareaType; |
23
|
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType; |
24
|
|
|
use Symfony\Component\Form\FormInterface; |
25
|
|
|
use Symfony\Component\HttpFoundation\Request; |
26
|
|
|
use Symfony\Component\HttpFoundation\Response; |
27
|
|
|
use Symfony\Component\Validator\Constraints as Assert; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @Route("band") |
31
|
|
|
* @author Vehsamrak |
32
|
|
|
*/ |
33
|
|
|
class BandController extends RestController |
34
|
|
|
{ |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* List all registered bands |
38
|
|
|
* @Route("s/{limit}/{offset}", name="bands_list") |
39
|
|
|
* @Method("GET") |
40
|
|
|
* @ApiDoc( |
41
|
|
|
* section="Band", |
42
|
|
|
* statusCodes={ |
43
|
|
|
* 200="OK", |
44
|
|
|
* } |
45
|
|
|
* ) |
46
|
|
|
* @param int $limit Limit results. Default is 50 |
47
|
|
|
* @param int $offset Starting serial number of result collection. Default is 0 |
48
|
|
|
*/ |
49
|
2 |
|
public function listAction($limit = null, $offset = null): Response |
50
|
|
|
{ |
51
|
2 |
|
return $this->respond( |
52
|
2 |
|
$this->createCompleteCollectionResponse($this->get('rockparade.band_repository'), $limit, $offset) |
53
|
|
|
); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* View band by name |
58
|
|
|
* @Route("/{bandName}", name="band_view") |
59
|
|
|
* @Method("GET") |
60
|
|
|
* @ApiDoc( |
61
|
|
|
* section="Band", |
62
|
|
|
* statusCodes={ |
63
|
|
|
* 200="Band was found", |
64
|
|
|
* 404="Band with given name was not found", |
65
|
|
|
* } |
66
|
|
|
* ) |
67
|
|
|
* @param string $bandName band name |
68
|
|
|
*/ |
69
|
3 |
View Code Duplication |
public function viewAction(string $bandName): Response |
|
|
|
|
70
|
|
|
{ |
71
|
3 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
72
|
3 |
|
$band = $bandRepository->findOneByName($bandName); |
73
|
|
|
|
74
|
3 |
|
if ($band) { |
75
|
2 |
|
$response = new ApiResponse($band, Response::HTTP_OK); |
76
|
|
|
} else { |
77
|
2 |
|
$response = $this->createBandNotFoundErrorResult($bandName); |
78
|
|
|
} |
79
|
|
|
|
80
|
3 |
|
return $this->respond($response); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Create new band |
85
|
|
|
* @Route("", name="band_create") |
86
|
|
|
* @Method("POST") |
87
|
|
|
* @Security("has_role('ROLE_USER')") |
88
|
|
|
* @ApiDoc( |
89
|
|
|
* section="Band", |
90
|
|
|
* requirements={ |
91
|
|
|
* { |
92
|
|
|
* "name"="name", |
93
|
|
|
* "dataType"="string", |
94
|
|
|
* "requirement"="true", |
95
|
|
|
* "description"="band name" |
96
|
|
|
* }, |
97
|
|
|
* { |
98
|
|
|
* "name"="description", |
99
|
|
|
* "dataType"="string", |
100
|
|
|
* "requirement"="true", |
101
|
|
|
* "description"="band description" |
102
|
|
|
* }, |
103
|
|
|
* { |
104
|
|
|
* "name"="members", |
105
|
|
|
* "dataType"="array", |
106
|
|
|
* "requirement"="true", |
107
|
|
|
* "description"="logins and short descriptions of band musicians" |
108
|
|
|
* }, |
109
|
|
|
* }, |
110
|
|
|
* statusCodes={ |
111
|
|
|
* 201="New band was created. Link to new resource in header 'Location'", |
112
|
|
|
* 400="Validation error", |
113
|
|
|
* } |
114
|
|
|
* ) |
115
|
|
|
*/ |
116
|
2 |
|
public function createAction(Request $request): Response |
117
|
|
|
{ |
118
|
2 |
|
$form = $this->createFormBandCreate(); |
119
|
2 |
|
$this->processForm($request, $form); |
120
|
2 |
|
$form = $this->get('rockparade.band')->processFormAndCreateBand($form, $this->getUser()); |
121
|
|
|
|
122
|
2 |
|
return $this->respond($this->createResponseFromCreateForm($form)); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Edit band |
127
|
|
|
* @Route("/{bandName}", name="band_edit") |
128
|
|
|
* @Method("PUT") |
129
|
|
|
* @Security("has_role('ROLE_USER')") |
130
|
|
|
* @ApiDoc( |
131
|
|
|
* section="Band", |
132
|
|
|
* requirements={ |
133
|
|
|
* { |
134
|
|
|
* "name"="name", |
135
|
|
|
* "dataType"="string", |
136
|
|
|
* "requirement"="true", |
137
|
|
|
* "description"="band name" |
138
|
|
|
* }, |
139
|
|
|
* { |
140
|
|
|
* "name"="description", |
141
|
|
|
* "dataType"="string", |
142
|
|
|
* "requirement"="true", |
143
|
|
|
* "description"="band description" |
144
|
|
|
* }, |
145
|
|
|
* { |
146
|
|
|
* "name"="users", |
147
|
|
|
* "dataType"="array", |
148
|
|
|
* "requirement"="true", |
149
|
|
|
* "description"="logins of band musicians" |
150
|
|
|
* }, |
151
|
|
|
* }, |
152
|
|
|
* statusCodes={ |
153
|
|
|
* 204="Band was edited with new data", |
154
|
|
|
* 400="Validation error", |
155
|
|
|
* } |
156
|
|
|
* ) |
157
|
|
|
* @param string $bandName band name |
158
|
|
|
*/ |
159
|
2 |
|
public function editAction(Request $request, string $bandName): Response |
160
|
|
|
{ |
161
|
|
|
/** @var BandRepository $bandRepository */ |
162
|
2 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
163
|
2 |
|
$band = $bandRepository->findOneByName($bandName); |
164
|
|
|
|
165
|
2 |
|
$form = $this->createFormBandCreate(); |
166
|
2 |
|
$this->processForm($request, $form); |
167
|
2 |
|
$form = $this->get('rockparade.band')->processFormAndUpdateBand($form, $band, $this->getUser()); |
168
|
|
|
|
169
|
2 |
|
return $this->respond($this->createResponseFromUpdateForm($form)); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* List all band members |
174
|
|
|
* @Route("/{bandName}/members", name="band_members") |
175
|
|
|
* @Method("GET") |
176
|
|
|
* @ApiDoc( |
177
|
|
|
* section="Band", |
178
|
|
|
* statusCodes={ |
179
|
|
|
* 200="OK", |
180
|
|
|
* 404="Band was not found", |
181
|
|
|
* } |
182
|
|
|
* ) |
183
|
|
|
*/ |
184
|
4 |
View Code Duplication |
public function listMembersAction(string $bandName): Response |
|
|
|
|
185
|
|
|
{ |
186
|
4 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
187
|
4 |
|
$band = $bandRepository->findOneByName($bandName); |
188
|
|
|
|
189
|
4 |
|
if (!$band) { |
190
|
|
|
$response = $this->createBandNotFoundErrorResult($bandName); |
191
|
|
|
} else { |
192
|
4 |
|
$response = new ApiResponse($band->getMembers(), Response::HTTP_OK); |
193
|
|
|
} |
194
|
|
|
|
195
|
4 |
|
return $this->respond($response); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Add member to band |
200
|
|
|
* @Route("/{bandName}/members", name="band_member_add") |
201
|
|
|
* @Method("POST") |
202
|
|
|
* @Security("has_role('ROLE_USER')") |
203
|
|
|
* @ApiDoc( |
204
|
|
|
* section="Band", |
205
|
|
|
* requirements={ |
206
|
|
|
* { |
207
|
|
|
* "name"="login", |
208
|
|
|
* "dataType"="string", |
209
|
|
|
* "requirement"="true", |
210
|
|
|
* "description"="user login" |
211
|
|
|
* }, |
212
|
|
|
* { |
213
|
|
|
* "name"="short_description", |
214
|
|
|
* "dataType"="string", |
215
|
|
|
* "requirement"="true", |
216
|
|
|
* "description"="short description of musicians role in band" |
217
|
|
|
* }, |
218
|
|
|
* { |
219
|
|
|
* "name"="description", |
220
|
|
|
* "dataType"="string", |
221
|
|
|
* "requirement"="false", |
222
|
|
|
* "description"="long description of musician" |
223
|
|
|
* }, |
224
|
|
|
* }, |
225
|
|
|
* statusCodes={ |
226
|
|
|
* 200="Member was added to the band", |
227
|
|
|
* 400="Validation error", |
228
|
|
|
* } |
229
|
|
|
* ) |
230
|
|
|
* @param string $bandName band name |
231
|
|
|
*/ |
232
|
1 |
|
public function addMemberAction(Request $request, string $bandName): Response |
233
|
|
|
{ |
234
|
1 |
|
$form = $this->createFormCreateBandMember(); |
235
|
1 |
|
$this->processForm($request, $form); |
236
|
|
|
|
237
|
1 |
|
if ($form->isValid()) { |
238
|
1 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
239
|
1 |
|
$band = $bandRepository->findOneByName($bandName); |
240
|
|
|
|
241
|
1 |
|
if (!$band) { |
242
|
|
|
$response = $this->createBandNotFoundErrorResult($bandName); |
243
|
|
|
} else { |
244
|
1 |
|
$newUserLogin = $form->get('login')->getData(); |
245
|
1 |
|
$newUser = $this->get('rockparade.user_repository')->findOneByLogin($newUserLogin); |
246
|
|
|
|
247
|
1 |
|
if (!$newUser) { |
248
|
|
|
$response = $this->createUserNotFoundErrorResult($newUserLogin); |
249
|
|
|
} else { |
250
|
1 |
|
$bandMemberRepository = $this->get('rockparade.band_member_repository'); |
251
|
1 |
|
$shortDescription = (string) $form->get('short_description')->getData(); |
252
|
1 |
|
$description = (string) $form->get('description')->getData(); |
253
|
1 |
|
$bandMember = $bandMemberRepository->getOrCreateByBandAndUser( |
254
|
|
|
$band, |
255
|
|
|
$newUser, |
256
|
|
|
$shortDescription, |
257
|
|
|
$description |
258
|
|
|
); |
259
|
|
|
|
260
|
1 |
|
$band->addMember($bandMember); |
261
|
1 |
|
$bandRepository->flush(); |
262
|
|
|
|
263
|
1 |
|
$response = new EmptyApiResponse(Response::HTTP_OK); |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
} else { |
267
|
|
|
$response = new ApiValidationError($form); |
268
|
|
|
} |
269
|
|
|
|
270
|
1 |
|
return $this->respond($response); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Delete member from band |
275
|
|
|
* @Route("/{bandName}/member/{userLogin}", name="band_member_delete") |
276
|
|
|
* @Method("DELETE") |
277
|
|
|
* @Security("has_role('ROLE_USER')") |
278
|
|
|
* @ApiDoc( |
279
|
|
|
* section="Band", |
280
|
|
|
* statusCodes={ |
281
|
|
|
* 204="Member was deleted from the band", |
282
|
|
|
* 404="Band or user was not found", |
283
|
|
|
* } |
284
|
|
|
* ) |
285
|
|
|
* @param string $bandName band name |
286
|
|
|
* @param string $userLogin member login |
287
|
|
|
*/ |
288
|
1 |
|
public function deleteMemberAction(string $bandName, string $userLogin) |
289
|
|
|
{ |
290
|
1 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
291
|
1 |
|
$band = $bandRepository->findOneByName($bandName); |
292
|
|
|
|
293
|
1 |
|
if ($band) { |
294
|
1 |
|
$userRepository = $this->get('rockparade.user_repository'); |
295
|
1 |
|
$user = $userRepository->findOneByLogin($userLogin); |
296
|
|
|
|
297
|
1 |
|
if ($user) { |
298
|
1 |
|
$bandMemberRepository = $this->get('rockparade.band_member_repository'); |
299
|
1 |
|
$bandMember = $bandMemberRepository->findByBandAndUser($band, $user); |
300
|
|
|
|
301
|
1 |
|
if ($bandMember) { |
302
|
1 |
|
$band->removeMember($bandMember); |
303
|
1 |
|
$bandRepository->flush(); |
304
|
|
|
|
305
|
1 |
|
$response = new EmptyApiResponse(Response::HTTP_NO_CONTENT); |
306
|
|
|
} else { |
307
|
1 |
|
$response = $this->createBandMemberNotFoundErrorResult($userLogin, $bandName); |
308
|
|
|
} |
309
|
|
|
} else { |
310
|
1 |
|
$response = $this->createUserNotFoundErrorResult($userLogin); |
311
|
|
|
} |
312
|
|
|
} else { |
313
|
|
|
$response = $this->createBandNotFoundErrorResult($bandName); |
314
|
|
|
} |
315
|
|
|
|
316
|
1 |
|
return $this->respond($response); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* Update band member |
321
|
|
|
* @Route("/{bandName}/member/{userLogin}", name="band_member_update") |
322
|
|
|
* @Method("PUT") |
323
|
|
|
* @Security("has_role('ROLE_USER')") |
324
|
|
|
* @ApiDoc( |
325
|
|
|
* section="Band", |
326
|
|
|
* requirements={ |
327
|
|
|
* { |
328
|
|
|
* "name"="short_description", |
329
|
|
|
* "dataType"="string", |
330
|
|
|
* "requirement"="true", |
331
|
|
|
* "description"="short description of role in band" |
332
|
|
|
* }, |
333
|
|
|
* { |
334
|
|
|
* "name"="description", |
335
|
|
|
* "dataType"="string", |
336
|
|
|
* "requirement"="false", |
337
|
|
|
* "description"="long description of musician" |
338
|
|
|
* }, |
339
|
|
|
* }, |
340
|
|
|
* statusCodes={ |
341
|
|
|
* 204="Band member was successfully updated", |
342
|
|
|
* 404="Band or user was not found", |
343
|
|
|
* } |
344
|
|
|
* ) |
345
|
|
|
* @param string $bandName band name |
346
|
|
|
* @param string $userLogin member login |
347
|
|
|
*/ |
348
|
1 |
|
public function updateMemberAction(Request $request, string $bandName, string $userLogin) |
349
|
|
|
{ |
350
|
1 |
|
$bandRepository = $this->get('rockparade.band_repository'); |
351
|
1 |
|
$band = $bandRepository->findOneByName($bandName); |
352
|
|
|
|
353
|
1 |
|
if ($band) { |
354
|
1 |
|
$userRepository = $this->get('rockparade.user_repository'); |
355
|
1 |
|
$user = $userRepository->findOneByLogin($userLogin); |
356
|
|
|
|
357
|
1 |
|
if ($user) { |
358
|
1 |
|
$bandMemberRepository = $this->get('rockparade.band_member_repository'); |
359
|
1 |
|
$bandMember = $bandMemberRepository->findByBandAndUser($band, $user); |
360
|
|
|
|
361
|
1 |
|
if ($bandMember) { |
362
|
1 |
|
$form = $this->createFormUpdateBandMember(); |
363
|
1 |
|
$this->processForm($request, $form); |
364
|
1 |
|
$form = $this->get('rockparade.band')->processFormAndUpdateBandMember($form, $bandMember); |
365
|
|
|
|
366
|
1 |
|
$bandRepository->flush(); |
367
|
|
|
|
368
|
1 |
|
$response = $this->createResponseFromUpdateForm($form); |
369
|
|
|
} else { |
370
|
1 |
|
$response = $this->createBandMemberNotFoundErrorResult($userLogin, $bandName); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
} else { |
374
|
1 |
|
$response = $this->createUserNotFoundErrorResult($userLogin); |
375
|
|
|
} |
376
|
|
|
} else { |
377
|
|
|
$response = $this->createBandNotFoundErrorResult($bandName); |
378
|
|
|
} |
379
|
|
|
|
380
|
1 |
|
return $this->respond($response); |
381
|
|
|
} |
382
|
|
|
|
383
|
2 |
|
private function createBandNotFoundErrorResult(string $bandName): ApiError |
384
|
|
|
{ |
385
|
2 |
|
return new ApiError( |
386
|
2 |
|
sprintf('Band with name "%s" was not found.', $bandName), |
387
|
2 |
|
Response::HTTP_NOT_FOUND |
388
|
|
|
); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
private function createUserNotFoundErrorResult(string $userLogin): ApiError |
392
|
|
|
{ |
393
|
|
|
return new ApiError( |
394
|
|
|
sprintf('User with login "%s" was not found.', $userLogin), |
395
|
|
|
Response::HTTP_NOT_FOUND |
396
|
|
|
); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
private function createBandMemberNotFoundErrorResult(string $userLogin, string $bandName): ApiError |
400
|
|
|
{ |
401
|
|
|
return new ApiError( |
402
|
|
|
sprintf('Band member with login "%s" was not found for band "%s".', $userLogin, $bandName), |
403
|
|
|
Response::HTTP_NOT_FOUND |
404
|
|
|
); |
405
|
|
|
} |
406
|
|
|
|
407
|
4 |
|
private function createFormBandCreate(): Form |
408
|
|
|
{ |
409
|
4 |
|
$formBuilder = $this->createFormBuilder(new CreateBand()); |
410
|
4 |
|
$formBuilder->add('name', TextType::class); |
411
|
4 |
|
$formBuilder->add(BandService::ATTRIBUTE_MEMBERS, TextType::class); |
412
|
4 |
|
$formBuilder->add('description', TextareaType::class); |
413
|
|
|
|
414
|
4 |
|
return $formBuilder->getForm(); |
415
|
|
|
} |
416
|
|
|
|
417
|
1 |
|
private function createLocationByNameFieldInForm(FormInterface $form): string |
418
|
|
|
{ |
419
|
1 |
|
$bandName = $form->get('name')->getData(); |
420
|
|
|
|
421
|
1 |
|
return $this->generateUrl('band_view', ['bandName' => $bandName]); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
/** |
425
|
|
|
* @param $form |
426
|
|
|
* @param $band |
427
|
|
|
* @return ApiError|CreatedApiResponse|EmptyApiResponse |
428
|
|
|
*/ |
429
|
2 |
|
private function createResponseFromCreateForm(FormInterface $form): AbstractApiResponse |
430
|
|
|
{ |
431
|
2 |
|
if ($form->isValid()) { |
432
|
1 |
|
return new CreatedApiResponse($this->createLocationByNameFieldInForm($form)); |
433
|
|
|
} else { |
434
|
1 |
|
return new ApiValidationError($form); |
435
|
|
|
} |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* @return ApiError|CreatedApiResponse|EmptyApiResponse |
440
|
|
|
*/ |
441
|
3 |
|
private function createResponseFromUpdateForm(FormInterface $form): AbstractApiResponse |
442
|
|
|
{ |
443
|
3 |
|
if ($form->isValid()) { |
444
|
2 |
|
return new EmptyApiResponse(Response::HTTP_NO_CONTENT); |
445
|
|
|
} else { |
446
|
1 |
|
return new ApiValidationError($form); |
447
|
|
|
} |
448
|
|
|
} |
449
|
|
|
|
450
|
1 |
View Code Duplication |
private function createFormUpdateBandMember(): FormInterface |
|
|
|
|
451
|
|
|
{ |
452
|
1 |
|
$formBuilder = $this->createFormBuilder(new UpdateBandMemberDTO()); |
453
|
1 |
|
$formBuilder->add('short_description', TextType::class); |
454
|
1 |
|
$formBuilder->add('description', TextareaType::class); |
455
|
|
|
|
456
|
1 |
|
return $formBuilder->getForm(); |
457
|
|
|
} |
458
|
|
|
|
459
|
1 |
View Code Duplication |
private function createFormCreateBandMember(): FormInterface |
|
|
|
|
460
|
|
|
{ |
461
|
1 |
|
$formBuilder = $this->createFormBuilder(new CreateBandMemberDTO()); |
462
|
1 |
|
$formBuilder->add('login', TextType::class); |
463
|
1 |
|
$formBuilder->add('short_description', TextType::class); |
464
|
1 |
|
$formBuilder->add('description', TextareaType::class); |
465
|
|
|
|
466
|
1 |
|
return $formBuilder->getForm(); |
467
|
|
|
} |
468
|
|
|
} |
469
|
|
|
|
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.