Passed
Push — master ( 931773...5af452 )
by Peter
03:08
created

ApiAbstract::isEntityNotFound()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Http\Controllers\Admin;
6
7
use AbterPhp\Framework\Domain\Entities\IStringerEntity;
8
use AbterPhp\Framework\Domain\Entities\IToJsoner;
0 ignored issues
show
Bug introduced by
The type AbterPhp\Framework\Domain\Entities\IToJsoner was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use AbterPhp\Framework\Http\Service\Execute\RepoServiceAbstract;
10
use Opulence\Http\Responses\Response;
11
use Opulence\Http\Responses\ResponseHeaders;
12
use Opulence\Orm\IEntity;
13
use Opulence\Orm\OrmException;
14
use Opulence\Routing\Controller;
15
use Psr\Log\LoggerInterface;
16
17
abstract class ApiAbstract extends Controller
18
{
19
    const LOG_MSG_CREATE_FAILURE = 'Creating %1$s failed.';
20
    const LOG_MSG_CREATE_SUCCESS = 'Creating %1$s was successful.';
21
    const LOG_MSG_UPDATE_FAILURE = 'Updating %1$s with id "%2$s" failed.';
22
    const LOG_MSG_UPDATE_SUCCESS = 'Updating %1$s with id "%2$s" was successful.';
23
    const LOG_MSG_DELETE_FAILURE = 'Deleting %1$s with id "%2$s" failed.';
24
    const LOG_MSG_DELETE_SUCCESS = 'Deleting %1$s with id "%2$s" was successful.';
25
26
    const LOG_CONTEXT_EXCEPTION  = 'Exception';
27
    const LOG_PREVIOUS_EXCEPTION = 'Previous exception #%d';
28
29
    const ENTITY_TITLE_SINGULAR = '';
30
    const ENTITY_TITLE_PLURAL   = '';
31
32
    /** @var LoggerInterface */
33
    protected $logger;
34
35
    /** @var RepoService */
0 ignored issues
show
Bug introduced by
The type AbterPhp\Framework\Http\...llers\Admin\RepoService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
36
    protected $repoService;
37
38
    /**
39
     * ApiAbstract constructor.
40
     *
41
     * @param LoggerInterface     $logger
42
     * @param RepoServiceAbstract $repoService
43
     */
44
    public function __construct(LoggerInterface $logger, RepoServiceAbstract $repoService)
45
    {
46
        $this->logger      = $logger;
47
        $this->repoService = $repoService;
0 ignored issues
show
Documentation Bug introduced by
It seems like $repoService of type AbterPhp\Framework\Http\...ute\RepoServiceAbstract is incompatible with the declared type AbterPhp\Framework\Http\...llers\Admin\RepoService of property $repoService.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
48
    }
49
50
    /**
51
     * @return Response
52
     */
53
    public function create(): Response
54
    {
55
        $data = $this->getCreateData();
56
57
        $errors = $this->repoService->validateForm($data);
58
59
        if (count($errors) > 0) {
60
            $msg = sprintf(static::LOG_MSG_CREATE_FAILURE, static::ENTITY_SINGULAR);
0 ignored issues
show
Bug introduced by
The constant AbterPhp\Framework\Http\...stract::ENTITY_SINGULAR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
61
62
            return $this->handleErrors($msg, $errors);
63
        }
64
65
        try {
66
            $entity = $this->repoService->create($data, []);
67
        } catch (\Exception $e) {
68
            $msg = sprintf(static::LOG_MSG_CREATE_FAILURE, static::ENTITY_SINGULAR);
69
70
            return $this->handleException($msg, $e);
71
        }
72
73
        return $this->handleCreateSuccess($entity);
74
    }
75
76
    /**
77
     * @param string $entityId
78
     *
79
     * @return Response
80
     */
81
    public function update(string $entityId): Response
82
    {
83
        $data = $this->getUpdateData();
84
85
        $errors = $this->repoService->validateForm($data);
86
87
        if (count($errors) > 0) {
88
            $msg = sprintf(static::LOG_MSG_UPDATE_FAILURE, static::ENTITY_SINGULAR, $entityId);
0 ignored issues
show
Bug introduced by
The constant AbterPhp\Framework\Http\...stract::ENTITY_SINGULAR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
89
90
            return $this->handleErrors($msg, $errors);
91
        }
92
93
94
        try {
95
            $entity = $this->repoService->retrieveEntity($entityId);
96
            $this->repoService->update($entity, $data, []);
97
        } catch (\Exception $e) {
98
            if ($this->isEntityNotFound($e)) {
99
                return $this->handleNotFound();
100
            }
101
102
            $msg = sprintf(static::LOG_MSG_UPDATE_FAILURE, static::ENTITY_SINGULAR, $entityId);
103
104
            return $this->handleException($msg, $e);
105
        }
106
107
        return $this->handleUpdateSuccess($entity);
108
    }
109
110
    /**
111
     * @param string $entityId
112
     *
113
     * @return Response
114
     */
115
    public function delete(string $entityId): Response
116
    {
117
118
        try {
119
            $entity = $this->repoService->retrieveEntity($entityId);
120
            $this->repoService->delete($entity);
121
        } catch (\Exception $e) {
122
            if ($this->isEntityNotFound($e)) {
123
                return $this->handleNotFound();
124
            }
125
126
            $msg = sprintf(static::LOG_MSG_DELETE_FAILURE, static::ENTITY_SINGULAR, $entityId);
0 ignored issues
show
Bug introduced by
The constant AbterPhp\Framework\Http\...stract::ENTITY_SINGULAR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
127
128
            return $this->handleException($msg, $e);
129
        }
130
131
        return $this->handleDeleteSuccess();
132
    }
133
134
    /**
135
     * @param \Exception $e
136
     *
137
     * @return bool
138
     */
139
    protected function isEntityNotFound(\Exception $e): bool
140
    {
141
        if (!($e instanceof OrmException)) {
142
            return false;
143
        }
144
145
        return $e->getMessage() === 'Failed to find entity';
146
    }
147
148
    /**
149
     * @return array
150
     */
151
    public function getCreateData(): array
152
    {
153
        return $this->getSharedData();
154
    }
155
156
    /**
157
     * @return array
158
     */
159
    public function getUpdateData(): array
160
    {
161
        return $this->getSharedData();
162
    }
163
164
    /**
165
     * @return array
166
     */
167
    public function getSharedData(): array
168
    {
169
        return $this->request->getJsonBody();
170
    }
171
172
    /**
173
     * @param string $msg
174
     * @param array  $errors
175
     *
176
     * @return Response
177
     */
178
    protected function handleErrors(string $msg, array $errors): Response
179
    {
180
        $this->logger->debug($msg);
181
182
        $response = new Response();
183
184
        $response->setStatusCode(ResponseHeaders::HTTP_BAD_REQUEST);
185
186
        $response->setContent(json_encode(['errors' => $errors]));
187
188
        return $response;
189
    }
190
191
    /**
192
     * @param string     $msg
193
     * @param \Exception $exception
194
     *
195
     * @return Response
196
     */
197
    protected function handleException(string $msg, \Exception $exception): Response
198
    {
199
        $this->logger->error($msg, $this->getExceptionContext($exception));
200
201
        $response = new Response();
202
203
        $response->setStatusCode(ResponseHeaders::HTTP_INTERNAL_SERVER_ERROR);
204
205
        $response->setContent(json_encode(['errors' => [$msg]]));
206
207
        return $response;
208
    }
209
210
    /**
211
     * @param \Exception $exception
212
     *
213
     * @return array
214
     */
215
    protected function getExceptionContext(\Exception $exception): array
216
    {
217
        $result = [static::LOG_CONTEXT_EXCEPTION => $exception->getMessage()];
218
219
        $i = 1;
220
        while ($exception = $exception->getPrevious()) {
221
            $result[sprintf(static::LOG_PREVIOUS_EXCEPTION, $i++)] = $exception->getMessage();
222
        }
223
224
        return $result;
225
    }
226
227
    /**
228
     * @param IStringerEntity $entity
229
     *
230
     * @return Response
231
     */
232
    protected function handleCreateSuccess(IStringerEntity $entity): Response
233
    {
234
        $response = new Response();
235
236
        $response->setStatusCode(ResponseHeaders::HTTP_CREATED);
237
238
        $response->setContent($entity->toJSON());
239
240
        return $response;
241
    }
242
243
    /**
244
     * @param IStringerEntity $entity
245
     *
246
     * @return Response
247
     */
248
    protected function handleUpdateSuccess(IStringerEntity $entity): Response
249
    {
250
        $response = new Response();
251
252
        $response->setStatusCode(ResponseHeaders::HTTP_OK);
253
254
        $response->setContent($entity->toJSON());
255
256
        return $response;
257
    }
258
259
    /**
260
     * @return Response
261
     */
262
    protected function handleDeleteSuccess(): Response
263
    {
264
        $response = new Response();
265
266
        $response->setStatusCode(ResponseHeaders::HTTP_NO_CONTENT);
267
268
        return $response;
269
    }
270
271
    /**
272
     * @return Response
273
     */
274
    protected function handleNotFound(): Response
275
    {
276
        $response = new Response();
277
278
        $response->setStatusCode(ResponseHeaders::HTTP_NOT_FOUND);
279
280
        return $response;
281
    }
282
}
283