Response   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Test Coverage

Coverage 42.42%

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 88
dl 0
loc 189
ccs 14
cts 33
cp 0.4242
rs 10
c 4
b 0
f 1
wmc 19

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getHttpCodeDescription() 0 7 2
A setPayloadSuccess() 0 8 3
A send() 0 39 2
A setPayloadError() 0 10 1
B handleException() 0 32 9
A setPayloadErrors() 0 10 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Canvas\Http;
6
7
use Phalcon\Http\Response as PhResponse;
0 ignored issues
show
Bug introduced by
The type Phalcon\Http\Response 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...
8
use Phalcon\Mvc\Model\MessageInterface as ModelMessage;
0 ignored issues
show
Bug introduced by
The type Phalcon\Mvc\Model\MessageInterface 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 Phalcon\Validation\Message\Group as ValidationMessage;
0 ignored issues
show
Bug introduced by
The type Phalcon\Validation\Message\Group 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...
10
use Canvas\Exception\ServerErrorHttpException;
11
use Canvas\Constants\Flags;
12
use Canvas\Http\Exception\InternalServerErrorException;
13
use Error;
14
use Phalcon\Di;
15
use Throwable;
16
17
class Response extends PhResponse
18
{
19
    const OK = 200;
20
    const CREATED = 201;
21
    const ACCEPTED = 202;
22
    const MOVED_PERMANENTLY = 301;
23
    const FOUND = 302;
24
    const TEMPORARY_REDIRECT = 307;
25
    const PERMANENTLY_REDIRECT = 308;
26
    const BAD_REQUEST = 400;
27
    const UNAUTHORIZED = 401;
28
    const FORBIDDEN = 403;
29
    const NOT_FOUND = 404;
30
    const NOT_ACCEPTABLE = 406;
31
    const INTERNAL_SERVER_ERROR = 500;
32
    const NOT_IMPLEMENTED = 501;
33
    const BAD_GATEWAY = 502;
34
    const UNPROCESSABLE_ENTITY = 422;
35
36
    private $codes = [
37
        200 => 'OK',
38
        301 => 'Moved Permanently',
39
        302 => 'Found',
40
        307 => 'Temporary Redirect',
41
        308 => 'Permanent Redirect',
42
        400 => 'Bad Request',
43
        401 => 'Unauthorized',
44
        403 => 'Forbidden',
45
        404 => 'Not Found',
46
        422 => 'Unprocessable Entity',
47
        500 => 'Internal Server Error',
48
        501 => 'Not Implemented',
49
        502 => 'Bad Gateway',
50 1
    ];
51
52 1
    /**
53 1
     * Returns the http code description or if not found the code itself.
54
     * @param int $code
55
     *
56 1
     * @return int|string
57
     */
58
    public function getHttpCodeDescription(int $code)
59
    {
60
        if (true === isset($this->codes[$code])) {
61
            return sprintf('%d (%s)', $code, $this->codes[$code]);
62
        }
63
64
        return $code;
65
    }
66
67
    /**
68
     * Send the response back.
69
     *
70
     * @return PhResponse
71
     */
72
    public function send(): PhResponse
73
    {
74
        $content = $this->getContent();
75
        $data = $content;
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
76
        $eTag = sha1($content);
77
78
        /**
79
         * At the moment we are only using this format for error msg.
80
         * @todo change in the future to implemente other formats
81
         */
82
        if ($this->getStatusCode() != 200) {
83
            $timestamp = date('c');
84
            $hash = sha1($timestamp . $content);
85
86
            /** @var array $content */
87
            $content = json_decode($this->getContent(), true);
88
89
            $jsonapi = [
90
                'jsonapi' => [
91
                    'version' => '1.0',
92
                ],
93
            ];
94
            $meta = [
95
                'meta' => [
96
                    'timestamp' => $timestamp,
97
                    'hash' => $hash,
98
                ]
99
            ];
100
101
            /**
102
             * Join the array again.
103
             */
104 1
            $data = $jsonapi + $content + $meta;
105
            $this->setJsonContent($data);
106 1
        }
107
108 1
        $this->setHeader('E-Tag', $eTag);
109 1
110
        return parent::send();
111
    }
112
113 1
    /**
114
     * Sets the payload code as Error.
115
     *
116
     * @param string $detail
117
     *
118
     * @return Response
119
     */
120
    public function setPayloadError(string $detail = ''): Response
121
    {
122
        $this->setJsonContent([
123
            'errors' => [
124
                'message' => $detail,
125
                'type' => $this->codes[404]
126
            ]
127
        ]);
128
129
        return $this;
130
    }
131
132
    /**
133
     * Traverses the errors collection and sets the errors in the payload.
134
     *
135
     * @param ModelMessage[]|ValidationMessage $errors
136
     *
137
     * @return Response
138
     */
139
    public function setPayloadErrors($errors): Response
140
    {
141
        $data = [];
142 1
        foreach ($errors as $error) {
143
            $data[] = $error->getMessage();
144 1
        }
145 1
146
        $this->setJsonContent(['errors' => $data]);
147 1
148
        return $this;
149 1
    }
150
151
    /**
152
     * Sets the payload code as Success.
153
     *
154
     * @param null|string|array $content The content
155
     *
156
     * @return Response
157
     */
158
    public function setPayloadSuccess($content = []): Response
159
    {
160
        $data = (true === is_array($content)) ? $content : ['data' => $content];
161
        $data = (true === isset($data['data'])) ? $data : ['data' => $data];
162
163
        $this->setJsonContent($data);
164
165
        return $this;
166
    }
167
168
    /**
169
     * Handle the exception we throw from our api.
170
     *
171
     * @param Throwable $e
172
     * @return Response
173
     */
174
    public function handleException(Throwable $e): Response
175
    {
176
        $request = new Request();
177
        $identifier = $request->getServerAddress();
178
        $config = Di::getDefault()->getConfig();
179
180
        $httpCode = (method_exists($e, 'getHttpCode')) ? $e->getHttpCode() : 404;
181
        $httpMessage = (method_exists($e, 'getHttpMessage')) ? $e->getHttpMessage() : 'Not Found';
182
        $data = (method_exists($e, 'getData')) ? $e->getData() : [];
183
184
        $this->setHeader('Access-Control-Allow-Origin', '*'); //@todo check why this fails on nginx
185
        $this->setStatusCode($httpCode, $httpMessage);
186
        $this->setContentType('application/json');
187
        $this->setJsonContent([
188
            'errors' => [
189
                'type' => $httpMessage,
190
                'identifier' => $identifier,
191
                'message' => $e->getMessage(),
192
                'trace' => strtolower($config->app->env) != Flags::PRODUCTION ? $e->getTraceAsString() : null,
193
                'data' => $data,
194
            ],
195
        ]);
196
197
        //Log Errors or Internal Servers Errors in Production
198
        if ($e instanceof ServerErrorHttpException ||
199
            $e instanceof InternalServerErrorException ||
200
            $e instanceof Error ||
201
            strtolower($config->app->env) != Flags::PRODUCTION) {
202
            Di::getDefault()->getLog()->error($e->getMessage(), [$e->getTraceAsString()]);
203
        }
204
205
        return $this;
206
    }
207
}
208