Passed
Push — master ( 25c2e9...26c6a8 )
by Petr
08:32
created

BandController   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 406
Duplicated Lines 13.05 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 88.29%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 11
dl 53
loc 406
ccs 98
cts 111
cp 0.8829
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A viewAction() 0 4 1
A listAction() 0 4 1
A createAction() 14 14 1
A editAction() 0 12 1
A listMembersAction() 13 13 2
B addMemberAction() 0 40 4
B deleteMemberAction() 0 30 4
B updateMemberAction() 0 33 4
A createLocationByNameFieldInForm() 0 6 1
A createResponseFromCreateForm() 0 8 2
A createResponseFromUpdateForm() 0 8 2
A createFormBandCreate() 9 9 1
A createFormUpdateBandMember() 8 8 1
A createFormCreateBandMember() 9 9 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace AppBundle\Controller;
4
5
use AppBundle\Entity\Band;
6
use AppBundle\Entity\BandMember;
7
use AppBundle\Entity\DTO\CreateBandMemberDTO;
8
use AppBundle\Entity\DTO\CreateBand;
9
use AppBundle\Entity\DTO\UpdateBandMemberDTO;
10
use AppBundle\Entity\Repository\BandRepository;
11
use AppBundle\Entity\User;
12
use AppBundle\Form\Ambassador\BandFormType;
13
use AppBundle\Form\FormOptions;
14
use AppBundle\Response\ApiValidationError;
15
use AppBundle\Response\CreatedApiResponse;
16
use AppBundle\Response\EmptyApiResponse;
17
use AppBundle\Response\Infrastructure\AbstractApiResponse;
18
use AppBundle\Service\Entity\BandService;
19
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
20
use AppBundle\Controller\Infrastructure\RestController;
21
use AppBundle\Response\ApiError;
22
use AppBundle\Response\ApiResponse;
23
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
24
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
25
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
26
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
27
use Symfony\Component\Form\Extension\Core\Type\TextType;
28
use Symfony\Component\Form\FormInterface;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\HttpFoundation\Response;
31
use Symfony\Component\Validator\Constraints as Assert;
32
33
/**
34
 * @author Vehsamrak
35
 * @Route("band")
36
 */
37
class BandController extends RestController
38
{
39
40
    /**
41
     * List all registered bands
42
     * @Route("s/{limit}/{offset}", name="bands_list")
43
     * @Method("GET")
44
     * @ApiDoc(
45
     *     section="Band",
46
     *     statusCodes={
47
     *         200="OK",
48
     *     }
49
     * )
50
     * @param int $limit Limit results. Default is 50
51
     * @param int $offset Starting serial number of result collection. Default is 0
52
     */
53 2
    public function listAction($limit = null, $offset = null): Response
54
    {
55 2
        return $this->listEntities($this->get('rockparade.band_repository'), $limit, $offset);
56
    }
57
58
    /**
59
     * View band by name
60
     * @Route("/{id}", name="band_view")
61
     * @Method("GET")
62
     * @ApiDoc(
63
     *     section="Band",
64
     *     statusCodes={
65
     *         200="Band was found",
66
     *         404="Band with given name was not found",
67
     *     }
68
     * )
69
     * @param string $id band name
70
     */
71 3
    public function viewAction(string $id): Response
72
    {
73 3
        return $this->viewEntity($this->get('rockparade.band_repository'), $id);
74
    }
75
76
    /**
77
     * Create new band
78
     * @Route("", name="band_create")
79
     * @Method("POST")
80
     * @Security("has_role('ROLE_USER')")
81
     * @ApiDoc(
82
     *     section="Band",
83
     *     requirements={
84
     *         {
85
     *             "name"="name",
86
     *             "dataType"="string",
87
     *             "requirement"="true",
88
     *             "description"="band name"
89
     *         },
90
     *         {
91
     *             "name"="description",
92
     *             "dataType"="string",
93
     *             "requirement"="true",
94
     *             "description"="band description"
95
     *         },
96
     *         {
97
     *             "name"="members",
98
     *             "dataType"="array",
99
     *             "requirement"="false",
100
     *             "description"="logins and short descriptions of band musicians"
101
     *         },
102
     *     },
103
     *     statusCodes={
104
     *         201="New band was created. Link to new resource provided in header 'Location'",
105
     *         400="Validation error",
106
     *     }
107
     * )
108
     */
109 2 View Code Duplication
    public function createAction(Request $request): Response
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
110
    {
111 2
        $form = $this->createAndProcessForm($request, BandFormType::class);
112
113 2
        $apiResponseFactory = $this->get('rockparade.api_response_factory');
114 2
        $response = $apiResponseFactory->createResponse(
115 2
            $this->createApiOperation($request),
116
            $form,
117 2
            $this->getUser(),
118 2
            Band::class
119
        );
120
121 2
        return $this->respond($response);
122
    }
123
124
    /**
125
     * Edit band
126
     * @Route("/{bandName}", name="band_edit")
127
     * @Method("PUT")
128
     * @Security("has_role('ROLE_USER')")
129
     * @ApiDoc(
130
     *     section="Band",
131
     *     requirements={
132
     *         {
133
     *             "name"="name",
134
     *             "dataType"="string",
135
     *             "requirement"="true",
136
     *             "description"="band name"
137
     *         },
138
     *         {
139
     *             "name"="description",
140
     *             "dataType"="string",
141
     *             "requirement"="true",
142
     *             "description"="band description"
143
     *         },
144
     *         {
145
     *             "name"="users",
146
     *             "dataType"="array",
147
     *             "requirement"="true",
148
     *             "description"="logins of band musicians"
149
     *         },
150
     *     },
151
     *     statusCodes={
152
     *         204="Band was edited with new data",
153
     *         400="Validation error",
154
     *     }
155
     * )
156
     * @param string $bandName band name
157
     */
158 2
    public function editAction(Request $request, string $bandName): Response
159
    {
160
        /** @var BandRepository $bandRepository */
161 2
        $bandRepository = $this->get('rockparade.band_repository');
162 2
        $band = $bandRepository->findOneByName($bandName);
163
164 2
        $form = $this->createFormBandCreate();
165 2
        $this->processForm($request, $form);
166 2
        $form = $this->get('rockparade.band')->processFormAndUpdateBand($form, $band, $this->getUser());
167
168 2
        return $this->respond($this->createResponseFromUpdateForm($form));
169
    }
170
171
    /**
172
     * List all band members
173
     * @Route("/{bandName}/members", name="band_members")
174
     * @Method("GET")
175
     * @ApiDoc(
176
     *     section="Band",
177
     *     statusCodes={
178
     *         200="OK",
179
     *         404="Band was not found",
180
     *     }
181
     * )
182
     */
183 4 View Code Duplication
    public function listMembersAction(string $bandName): Response
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
184
    {
185 4
        $bandRepository = $this->get('rockparade.band_repository');
186 4
        $band = $bandRepository->findOneByName($bandName);
187
188 4
        if (!$band) {
189
            $response = $this->createEntityNotFoundResponse(Band::class, $bandName);
190
        } else {
191 4
            $response = new ApiResponse($band->getMembers(), Response::HTTP_OK);
192
        }
193
194 4
        return $this->respond($response);
195
    }
196
197
    /**
198
     * Add member to band
199
     * @Route("/{bandName}/members", name="band_member_add")
200
     * @Method("POST")
201
     * @Security("has_role('ROLE_USER')")
202
     * @ApiDoc(
203
     *     section="Band",
204
     *     requirements={
205
     *         {
206
     *             "name"="login",
207
     *             "dataType"="string",
208
     *             "requirement"="true",
209
     *             "description"="user login"
210
     *         },
211
     *         {
212
     *             "name"="short_description",
213
     *             "dataType"="string",
214
     *             "requirement"="true",
215
     *             "description"="short description of musicians role in band"
216
     *         },
217
     *         {
218
     *             "name"="description",
219
     *             "dataType"="string",
220
     *             "requirement"="false",
221
     *             "description"="long description of musician"
222
     *         },
223
     *     },
224
     *     statusCodes={
225
     *         200="Member was added to the band",
226
     *         400="Validation error",
227
     *     }
228
     * )
229
     * @param string $bandName band name
230
     */
231 1
    public function addMemberAction(Request $request, string $bandName): Response
232
    {
233 1
        $form = $this->createFormCreateBandMember();
234 1
        $this->processForm($request, $form);
235
236 1
        if ($form->isValid()) {
237 1
            $bandRepository = $this->get('rockparade.band_repository');
238 1
            $band = $bandRepository->findOneByName($bandName);
239
240 1
            if (!$band) {
241
                $response = $this->createEntityNotFoundResponse(Band::class, $bandName);
242
            } else {
243 1
                $newUserLogin = $form->get('login')->getData();
244 1
                $newUser = $this->get('rockparade.user_repository')->findOneByLogin($newUserLogin);
245
246 1
                if (!$newUser) {
247
                    $response = $this->createEntityNotFoundResponse(User::class, $newUserLogin);
248
                } else {
249 1
                    $bandMemberRepository = $this->get('rockparade.band_member_repository');
250 1
                    $shortDescription = (string) $form->get('short_description')->getData();
251 1
                    $description = (string) $form->get('description')->getData();
252 1
                    $bandMember = $bandMemberRepository->getOrCreateByBandAndUser(
253
                        $band,
254
                        $newUser,
255
                        $shortDescription,
256
                        $description
257
                    );
258
259 1
                    $band->addMember($bandMember);
260 1
                    $bandRepository->flush();
261
262 1
                    $response = new EmptyApiResponse(Response::HTTP_OK);
263
                }
264
            }
265
        } else {
266
            $response = new ApiValidationError($form);
267
        }
268
269 1
        return $this->respond($response);
270
    }
271
272
    /**
273
     * Delete member from band
274
     * @Route("/{bandName}/member/{userLogin}", name="band_member_delete")
275
     * @Method("DELETE")
276
     * @Security("has_role('ROLE_USER')")
277
     * @ApiDoc(
278
     *     section="Band",
279
     *     statusCodes={
280
     *         204="Member was deleted from the band",
281
     *         404="Band or user was not found",
282
     *     }
283
     * )
284
     * @param string $bandName band name
285
     * @param string $userLogin member login
286
     */
287 1
    public function deleteMemberAction(string $bandName, string $userLogin)
288
    {
289 1
        $bandRepository = $this->get('rockparade.band_repository');
290 1
        $band = $bandRepository->findOneByName($bandName);
291
292 1
        if ($band) {
293 1
            $userRepository = $this->get('rockparade.user_repository');
294 1
            $user = $userRepository->findOneByLogin($userLogin);
295
296 1
            if ($user) {
297 1
                $bandMemberRepository = $this->get('rockparade.band_member_repository');
298 1
                $bandMember = $bandMemberRepository->findByBandAndUser($band, $user);
299
300 1
                if ($bandMember) {
301 1
                    $band->removeMember($bandMember);
302 1
                    $bandRepository->flush();
303
304 1
                    $response = new EmptyApiResponse(Response::HTTP_NO_CONTENT);
305
                } else {
306 1
                    $response = $this->createEntityNotFoundResponse(BandMember::class, $userLogin);
307
                }
308
            } else {
309 1
                $response = $this->createEntityNotFoundResponse(User::class, $userLogin);
310
            }
311
        } else {
312
            $response = $this->createEntityNotFoundResponse(Band::class, $bandName);
313
        }
314
315 1
        return $this->respond($response);
316
    }
317
    
318
    /**
319
     * Update band member
320
     * @Route("/{bandName}/member/{userLogin}", name="band_member_update")
321
     * @Method("PUT")
322
     * @Security("has_role('ROLE_USER')")
323
     * @ApiDoc(
324
     *     section="Band",
325
     *     requirements={
326
     *         {
327
     *             "name"="short_description",
328
     *             "dataType"="string",
329
     *             "requirement"="true",
330
     *             "description"="short description of role in band"
331
     *         },
332
     *         {
333
     *             "name"="description",
334
     *             "dataType"="string",
335
     *             "requirement"="false",
336
     *             "description"="long description of musician"
337
     *         },
338
     *     },
339
     *     statusCodes={
340
     *         204="Band member was successfully updated",
341
     *         404="Band or user was not found",
342
     *     }
343
     * )
344
     * @param string $bandName band name
345
     * @param string $userLogin member login
346
     */
347 1
    public function updateMemberAction(Request $request, string $bandName, string $userLogin)
348
    {
349 1
        $bandRepository = $this->get('rockparade.band_repository');
350 1
        $band = $bandRepository->findOneByName($bandName);
351
352 1
        if ($band) {
353 1
            $userRepository = $this->get('rockparade.user_repository');
354 1
            $user = $userRepository->findOneByLogin($userLogin);
355
356 1
            if ($user) {
357 1
                $bandMemberRepository = $this->get('rockparade.band_member_repository');
358 1
                $bandMember = $bandMemberRepository->findByBandAndUser($band, $user);
359
                
360 1
                if ($bandMember) {
361 1
                    $form = $this->createFormUpdateBandMember();
362 1
                    $this->processForm($request, $form);
363 1
                    $form = $this->get('rockparade.band')->processFormAndUpdateBandMember($form, $bandMember);
364
                    
365 1
                    $bandRepository->flush();
366
367 1
                    $response = $this->createResponseFromUpdateForm($form);
368
                } else {
369 1
                    $response = $this->createEntityNotFoundResponse(BandMember::class, $userLogin);
370
                }
371
            } else {
372 1
                $response = $this->createEntityNotFoundResponse(User::class, $userLogin);
373
            }
374
        } else {
375
            $response = $this->createEntityNotFoundResponse(Band::class, $bandName);
376
        }
377
378 1
        return $this->respond($response);
379
    }
380
381
    private function createLocationByNameFieldInForm(FormInterface $form): string
382
    {
383
        $bandName = $form->get('name')->getData();
384
385
        return $this->generateUrl('band_view', ['bandName' => $bandName]);
386
    }
387
388
    /**
389
     * @param $form
390
     * @param $band
391
     * @return ApiError|CreatedApiResponse|EmptyApiResponse
392
     */
393
    private function createResponseFromCreateForm(FormInterface $form): AbstractApiResponse
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
394
    {
395
        if ($form->isValid()) {
396
            return new CreatedApiResponse($this->createLocationByNameFieldInForm($form));
397
        } else {
398
            return new ApiValidationError($form);
399
        }
400
    }
401
402
    /**
403
     * @return ApiError|CreatedApiResponse|EmptyApiResponse
404
     */
405 3
    private function createResponseFromUpdateForm(FormInterface $form): AbstractApiResponse
406
    {
407 3
        if ($form->isValid()) {
408 2
            return new EmptyApiResponse(Response::HTTP_NO_CONTENT);
409
        } else {
410 1
            return new ApiValidationError($form);
411
        }
412
    }
413
414 2 View Code Duplication
    private function createFormBandCreate(): FormInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
415
    {
416 2
        $formBuilder = $this->createFormBuilder(new CreateBand());
417 2
        $formBuilder->add('name', TextType::class);
418 2
        $formBuilder->add(BandService::ATTRIBUTE_MEMBERS, TextType::class);
419 2
        $formBuilder->add('description', TextareaType::class);
420
421 2
        return $formBuilder->getForm();
422
    }
423
424 1 View Code Duplication
    private function createFormUpdateBandMember(): FormInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
425
    {
426 1
        $formBuilder = $this->createFormBuilder(new UpdateBandMemberDTO());
427 1
        $formBuilder->add('short_description', TextType::class);
428 1
        $formBuilder->add('description', TextareaType::class);
429
430 1
        return $formBuilder->getForm();
431
    }
432
433 1 View Code Duplication
    private function createFormCreateBandMember(): FormInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
434
    {
435 1
        $formBuilder = $this->createFormBuilder(new CreateBandMemberDTO());
436 1
        $formBuilder->add('login', TextType::class);
437 1
        $formBuilder->add('short_description', TextType::class);
438 1
        $formBuilder->add('description', TextareaType::class);
439
440 1
        return $formBuilder->getForm();
441
    }
442
}
443