Passed
Push — master ( 8994b4...b44688 )
by Arman
03:12 queued 12s
created

HttpResponse::setStatusCode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.6.0
13
 */
14
15
namespace Quantum\Http\Response;
16
17
use Quantum\Exceptions\HttpException;
18
use Quantum\Bootstrap;
19
use SimpleXMLElement;
20
use DOMDocument;
21
22
/**
23
 * Class HttpResponse
24
 * @package Quantum\Http\Response
25
 */
26
abstract class HttpResponse
27
{
28
29
    use Header;
30
    use Body;
31
32
    /**
33
     * HTML content type
34
     */
35
    const CONTENT_HTML = 'text/html';
36
37
    /**
38
     * XML content type
39
     */
40
    const CONTENT_XML = 'application/xml';
41
42
    /**
43
     * JSON content type
44
     */
45
    const CONTENT_JSON = 'application/json';
46
47
    /**
48
     * JSONP content type
49
     */
50
51
    const CONTENT_JSONP = 'application/javascript';
52
53
    /**
54
     * Status code
55
     * @var int
56
     */
57
    private static $__statusCode = 200;
58
59
    /**
60
     * XML root element
61
     * @var string
62
     */
63
    private static $xmlRoot = '<data></data>';
64
65
    /**
66
     * Status texts
67
     * @var array
68
     */
69
    public static $statusTexts = [];
70
71
    /**
72
     * Callback function
73
     * @var string
74
     */
75
    private static $callbackFunction = '';
76
77
    /**
78
     * Initialize the Response
79
     * @throws \Quantum\Exceptions\HttpException
80
     */
81
    public static function init()
82
    {
83
        if (get_caller_class(3) !== Bootstrap::class) {
0 ignored issues
show
Unused Code introduced by
The call to Quantum\Http\Response\get_caller_class() has too many arguments starting with 3. ( Ignorable by Annotation )

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

83
        if (/** @scrutinizer ignore-call */ get_caller_class(3) !== Bootstrap::class) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
84
            throw HttpException::unexpectedResponseInitialization();
85
        }
86
87
        self::$statusTexts = self::$statusTexts ?: require_once 'statuses.php';
88
    }
89
90
    /**
91
     * Flushes the response header and body
92
     */
93
    public static function flush()
94
    {
95
        self::$__statusCode = 200;
96
        self::$__headers = [];
97
        self::$__response = [];
98
    }
99
100
    /**
101
     * Sends all response data to the client and finishes the request.
102
     * @throws \Exception
103
     */
104
    public static function send()
105
    {
106
        foreach (self::$__headers as $key => $value) {
107
            header($key . ': ' . $value);
108
        }
109
110
        echo self::getContent();
111
    }
112
113
    /**
114
     * Gets the response content
115
     * @return string
116
     * @throws \Exception
117
     */
118
    public static function getContent(): string
119
    {
120
        $content = '';
121
122
        switch (self::getContentType()) {
123
            case self::CONTENT_JSON:
124
                $content = json_encode(self::all());
125
                break;
126
            case self::CONTENT_XML:
127
                $content = self::arrayToXml(self::all());
128
                break;
129
            case self::CONTENT_HTML:
130
                $content = self::get('_qt_rendered_view');
131
                break;
132
            case self::CONTENT_JSONP:
133
                $content = self::getJsonPData(self::all());
134
                break;
135
            default :
136
                break;
137
        }
138
139
        return $content;
140
    }
141
142
    /**
143
     * Set the status code
144
     * @param int $code
145
     */
146
    public static function setStatusCode(int $code)
147
    {
148
        if (!array_key_exists($code, self::$statusTexts)) {
149
            throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
150
        }
151
152
        self::$__statusCode = $code;
153
    }
154
155
    /**
156
     * Gets the status code
157
     * @return int
158
     */
159
    public static function getStatusCode(): int
160
    {
161
        return self::$__statusCode;
162
    }
163
164
    /**
165
     * Gets the status text
166
     * @return string
167
     */
168
    public static function getStatusText(): string
169
    {
170
        return self::$statusTexts[self::$__statusCode];
171
    }
172
173
    /**
174
     * Redirect
175
     * @param string $url
176
     * @param int|null $code
177
     * @throws \Quantum\Exceptions\StopExecutionException
178
     */
179
    public static function redirect(string $url, int $code = null)
180
    {
181
        if (!is_null($code)) {
182
            self::setStatusCode($code);
183
        }
184
185
        self::setHeader('Location', $url);
186
187
        stop();
188
    }
189
190
    /**
191
     * Prepares the JSON response
192
     * @param array|null $data
193
     * @param int|null $code
194
     */
195
    public static function json(array $data = null, int $code = null)
196
    {
197
        self::setContentType(self::CONTENT_JSON);
198
199
        if (!is_null($code)) {
200
            self::setStatusCode($code);
201
        }
202
203
        if ($data) {
204
            foreach ($data as $key => $value) {
205
                self::$__response[$key] = $value;
206
            }
207
        }
208
    }
209
210
    /**
211
     * Prepares the JSONP response
212
     * @param array|null $data
213
     * @param string|null $callback
214
     * @param int|null $code
215
     */
216
    public static function jsonp($data = null, string $callback, int $code = null)
217
    { 
218
        self::setContentType(self::CONTENT_JSONP);
219
220
        self::$callbackFunction = $callback;
221
222
        if (!is_null($code)) {
223
            self::setStatusCode($code);
224
        }
225
226
        if ($data) {
227
            foreach ($data as $key => $value) {
228
                self::$__response[$key] = $value;
229
            }
230
        }
231
232
    }
233
234
    /**
235
     * Returnes response with function
236
     * @param array $data
237
     * @return string
238
     */
239
    public static function getJsonPData($data){
240
        return  self::$callbackFunction.'('.json_encode($data).")";
241
    }
242
243
    /**
244
     * Prepares the XML response
245
     * @param array|null $data
246
     * @param int|null $code
247
     */
248
    public static function xml(array $data = null, $root = '<data></data>', int $code = null)
249
    {
250
        self::setContentType(self::CONTENT_XML);
251
252
        self::$xmlRoot = $root;
253
254
        if (!is_null($code)) {
255
            self::setStatusCode($code);
256
        }
257
258
        if ($data) {
259
            foreach ($data as $key => $value) {
260
                self::$__response[$key] = $value;
261
            }
262
        }
263
    }
264
265
    /**
266
     * Prepares the HTML content
267
     * @param string $html
268
     * @param int|null $code
269
     */
270
    public static function html(string $html, int $code = null)
271
    {
272
        self::setContentType(self::CONTENT_HTML);
273
274
        if (!is_null($code)) {
275
            self::setStatusCode($code);
276
        }
277
278
        self::$__response['_qt_rendered_view'] = $html;
279
    }
280
281
    /**
282
     * Transforms array to XML
283
     * @param array $arr
284
     * @return string
285
     * @throws \Exception
286
     */
287
    private static function arrayToXML(array $arr): string
288
    {
289
        $simpleXML = new SimpleXMLElement(self::$xmlRoot);
290
        self::composeXML($arr, $simpleXML);
291
292
        $dom = new DOMDocument();
293
        $dom->loadXML($simpleXML->asXML());
294
        $dom->formatOutput = true;
295
        return $dom->saveXML();
296
    }
297
298
    /**
299
     * Compose XML
300
     * @param array $arr
301
     * @param \SimpleXMLElement $simpleXML
302
     */
303
    private static function composeXML(array $arr, SimpleXMLElement &$simpleXML)
304
    {
305
        foreach ($arr as $key => $value) {
306
            if (is_numeric($key)) {
307
                $key = 'item' . $key;
308
            }
309
310
            $tag = $key;
311
            $attributes = null;
312
313
            if (strpos($key, '@') !== false) {
314
                list($tag, $attributes) = explode('@', $key);
315
                $attributes = json_decode($attributes);
316
            }
317
318
            if (is_array($value)) {
319
                $child = $simpleXML->addChild($tag);
320
                if ($attributes) {
321
                    foreach ($attributes as $attrKey => $attrVal) {
322
                        $child->addAttribute($attrKey, $attrVal);
323
                    }
324
                }
325
326
                self::composeXML($value, $child);
327
            } else {
328
                $child = $simpleXML->addChild($tag, htmlspecialchars($value));
329
330
                if ($attributes) {
331
                    foreach ($attributes as $attrKey => $attrVal) {
332
                        $child->addAttribute($attrKey, $attrVal);
333
                    }
334
                }
335
            }
336
        }
337
    }
338
339
}
340