Passed
Pull Request — master (#349)
by Maximo
01:38
created

Response   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Test Coverage

Coverage 42.42%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
eloc 84
dl 0
loc 184
ccs 14
cts 33
cp 0.4242
rs 10
c 3
b 0
f 1
wmc 15

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