LoanController::update()   A
last analyzed

Complexity

Conditions 3
Paths 6

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 20
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 26
ccs 0
cts 25
cp 0
crap 12
rs 9.6
1
<?php
2
3
namespace App\Controller\Api;
4
5
use App\Command\CreateLoanCommand;
6
use App\Command\UpdateLoanCommand;
7
use App\Command\DeleteLoanCommand;
8
use App\Error\ApiError;
9
use App\Repository\Exception\LoanNotFoundException;
10
use App\Repository\LoanRepository;
11
use App\Request\CreateLoanRequest;
12
use App\Request\UpdateLoanRequest;
13
use App\Traits\JsonErrorResponse;
14
use Psr\Log\LoggerInterface;
15
use Ramsey\Uuid\Uuid;
16
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
17
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
18
use Symfony\Component\HttpFoundation\JsonResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\Messenger\MessageBusInterface;
22
use Symfony\Component\Routing\Annotation\Route;
23
use Symfony\Component\Validator\ConstraintViolationListInterface;
24
use Swagger\Annotations as SWG;
25
use App\CommandHandler\Exception\LoanNotDeletedException;
26
use Nelmio\ApiDocBundle\Annotation\Model;
27
28
class LoanController extends AbstractController
29
{
30
    use JsonErrorResponse;
31
32
    /**
33
     * @var MessageBusInterface
34
     */
35
    private $commandBus;    
36
    /**
37
     * @var LoggerInterface
38
     */
39
    private $logger;
40
    /**
41
     * @var LoanRepository
42
     */
43
    private $repository;
44
45
    /**
46
     * @param MessageBusInterface $commandBus
47
     * @param LoggerInterface $logger
48
     * @param LoanRepository $repository
49
     */
50
    public function __construct(
51
        MessageBusInterface $commandBus,
52
        LoggerInterface $logger,
53
        LoanRepository $repository
54
    )
55
    {
56
        $this->commandBus = $commandBus;
57
        $this->logger = $logger;
58
        $this->repository = $repository;
59
    }
60
61
    /**
62
     * @Route("/api/loan", name="create_loan", methods={"POST"})
63
     *
64
     * @ParamConverter("request", converter="fos_rest.request_body")
65
     * 
66
     * @SWG\Tag(name="Loan")
67
     * @SWG\Post(
68
     *     @SWG\Parameter(
69
     *          name="body",
70
     *          in="body",
71
     *          required=true,
72
     *          format="application/json",
73
     *          @SWG\Schema(
74
     *              required={"name"},
75
     *              @SWG\Property(property="itemId", type="string", format="UUID"),
76
     *              @SWG\Property(property="loaner", type="string", maxLength=255),
77
     *              @SWG\Property(property="loanDate", type="string", format="Y-m-d H:i"),
78
     *              @SWG\Property(property="returnDate", type="string", format="Y-m-d H:i"),
79
     *          )
80
     *     )
81
     * )
82
     * @SWG\Response(
83
     *     response=201,
84
     *     description="Returns ID of created Loan",
85
     *     @SWG\Schema(
86
     *          @SWG\Property(property="id", type="string", format="UUID")
87
     *     )
88
     * )
89
     * @SWG\Response(
90
     *     response=422,
91
     *     description="Loan was not created"
92
     * )
93
     * 
94
     * @param CreateLoanRequest $request
95
     * @param ConstraintViolationListInterface $validationErrors
96
     * @return JsonResponse
97
     */
98
    public function create(CreateLoanRequest $request, ConstraintViolationListInterface $validationErrors): JsonResponse
99
    {
100
        if ($validationErrors->count()) {
101
            $response = $this->jsonError(ApiError::ENTITY_VALIDATION_ERROR,
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
102
                'Validations errors for create Loan',
103
                Response::HTTP_BAD_REQUEST,
104
                $this->parseFormErrors($validationErrors)
105
            );
106
        }
107
108
        try {
109
            $id = Uuid::uuid4();
110
            $command = new CreateLoanCommand(
111
                $id,
112
                $request->getItemId(),
113
                $request->getLoaner(),
114
                $request->getLoanDate(),
115
                $request->getReturnDate()
116
            );
117
            $this->commandBus->dispatch($command);
118
            return $this->json(['id' => $id], Response::HTTP_CREATED);
119
        } catch (\Exception $e) {
120
            $this->logger->critical($e->getMessage());
121
            return $this->jsonError(ApiError::ENTITY_CREATE_ERROR,
122
                $e->getMessage(),
123
                Response::HTTP_UNPROCESSABLE_ENTITY
124
            );
125
        }
126
    }
127
128
    /**
129
     * @Route("/api/loan", name="update_loan", methods={"PATCH"})
130
     *
131
     * @ParamConverter("request", converter="fos_rest.request_body")
132
     *
133
     * @SWG\Tag(name="Loan")
134
     * @SWG\Patch(
135
     *     @SWG\Parameter(
136
     *          name="body",
137
     *          in="body",
138
     *          required=true,
139
     *          format="application/json",
140
     *          @SWG\Schema(
141
     *              required={"name"},
142
     *              @SWG\Property(property="id", type="string", format="UUID"),
143
     *              @SWG\Property(property="itemId", type="string", format="UUID"),
144
     *              @SWG\Property(property="loaner", type="string", maxLength=255),
145
     *              @SWG\Property(property="loanDate", type="string", format="Y-m-d H:i"),
146
     *              @SWG\Property(property="returnDate", type="string", format="Y-m-d H:i"),
147
     *          )
148
     *     )
149
     * )
150
     * @SWG\Response(
151
     *     response=201,
152
     *     description="Returns ID of updated Loan",
153
     *     @SWG\Schema(
154
     *          @SWG\Property(property="id", type="string", format="UUID")
155
     *     )
156
     * )
157
     * @SWG\Response(
158
     *     response=422,
159
     *     description="Loan was not updated"
160
     * )
161
     *
162
     * @param UpdateLoanRequest $request
163
     * @param ConstraintViolationListInterface $validationErrors
164
     * @return JsonResponse
165
     */
166
    public function update(UpdateLoanRequest $request, ConstraintViolationListInterface $validationErrors): JsonResponse
167
    {
168
        if ($validationErrors->count()) {
169
            return $this->jsonError(ApiError::ENTITY_VALIDATION_ERROR,
170
                'Validations errors for update Loan',
171
                Response::HTTP_BAD_REQUEST,
172
                $this->parseFormErrors($validationErrors)
173
                );
174
        }
175
        
176
        try {
177
            $command = new UpdateLoanCommand(
178
                $request->getId(),
179
                $request->getItemId(),
180
                $request->getLoaner(),
181
                $request->getLoanDate(),
182
                $request->getReturnDate()
183
                );
184
            $this->commandBus->dispatch($command);
185
            $loan = $this->repository->getLoan($command->getId());
186
            return $this->json($loan, Response::HTTP_OK);
187
        } catch (\Exception $e) {
188
            $this->logger->critical($e->getMessage());
189
            return $this->jsonError(ApiError::ENTITY_CREATE_ERROR,
190
                $e->getMessage(),
191
                Response::HTTP_UNPROCESSABLE_ENTITY
192
                );
193
        }
194
    }
195
196
    /**
197
     * Delete Loan
198
     *
199
     * @SWG\Tag(name="Loan")
200
     * @SWG\Response(
201
     *     response="204",
202
     *     description="Loan was deleted"
203
     * )
204
     * @SWG\Response(
205
     *     response="404",
206
     *     description="Loan not found",
207
     * )
208
     *
209
     * @SWG\Response(
210
     *     response="422",
211
     *     description="Loan was not deleted",
212
     * )
213
     *
214
     * @Route("/api/loan/{id}", name="loan_delete", methods={"DELETE"})
215
     * @param string $id
216
     * @return JsonResponse
217
     */
218
    public function delete(string $id): JsonResponse
219
    {
220
        try {
221
            $uuid = Uuid::fromString($id);
222
            $command = new DeleteLoanCommand($uuid);
223
            $this->commandBus->dispatch($command);
224
            return $this->json(null, Response::HTTP_NO_CONTENT);
225
        } catch (\Ramsey\Uuid\Exception\InvalidUuidStringException $e) {
226
            $response = $this->jsonError(ApiError::ENTITY_UUID_ERROR,
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
227
                $e->getMessage(),
228
                Response::HTTP_UNPROCESSABLE_ENTITY
229
                );
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\JsonResponse. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
230
        } catch (LoanNotFoundException $e) {
231
            $response = $this->jsonError(ApiError::ENTITY_READ_ERROR,
232
                $e->getMessage(),
233
                Response::HTTP_NOT_FOUND
234
                );
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\JsonResponse. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
235
        } catch (LoanNotDeletedException $e) {
236
            $response = $this->jsonError(ApiError::ENTITY_DELETE_ERROR,
237
                $e->getMessage(),
238
                Response::HTTP_BAD_REQUEST
239
                );
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Symfony\Component\HttpFoundation\JsonResponse. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
240
        }
241
    }
242
    
243
    /**
244
     * List loaned items
245
     *
246
     * @SWG\Tag(name="Loan")
247
     * @SWG\Response(
248
     *     response=200,
249
     *     description="List of loaned items",
250
     *     @SWG\Schema(
251
     *          type="array",
252
     *          @SWG\Items(ref=@Model(type=App\Entity\Item::class))
253
     *     )
254
     * )
255
     *
256
     * @param Request $request
257
     * @Route("/api/loaned", name="loaned-items-list", methods={"GET"})
258
     * @return JsonResponse
259
     */
260
    public function getLoanedItems(Request $request): JsonResponse
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

260
    public function getLoanedItems(/** @scrutinizer ignore-unused */ Request $request): JsonResponse

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
261
    {
262
        try {
263
            return $this->json($this->repository->listLoans());
264
        } catch (\Exception$e) {
265
            $this->logger->critical($e->getMessage());
266
            return $this->jsonError(ApiError::ENTITY_CREATE_ERROR,
267
                $e->getMessage(),
268
                Response::HTTP_UNPROCESSABLE_ENTITY
269
                );
270
        }
271
    }
272
}
273