HttpResponse   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 315
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 99
c 1
b 1
f 0
dl 0
loc 315
rs 9.2
wmc 40

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getJsonPData() 0 3 1
A setStatusCode() 0 7 2
A jsonp() 0 12 3
A json() 0 10 3
A getStatusCode() 0 3 1
A xml() 0 12 3
B composeXML() 0 30 9
A html() 0 9 2
A send() 0 15 4
A init() 0 11 3
A flush() 0 5 1
A arrayToXML() 0 9 1
A redirect() 0 5 1
A getStatusText() 0 3 1
A getContent() 0 22 5

How to fix   Complexity   

Complex Class

Complex classes like HttpResponse often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use HttpResponse, and based on these observations, apply Extract Interface, too.

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.9.7
13
 */
14
15
namespace Quantum\Http\Response;
16
17
use Quantum\Libraries\Lang\Exceptions\LangException;
18
use Quantum\App\Exceptions\StopExecutionException;
19
use Quantum\Http\Exceptions\HttpException;
20
use Quantum\Environment\Environment;
21
use InvalidArgumentException;
22
use SimpleXMLElement;
23
use DOMDocument;
24
use Exception;
25
26
/**
27
 * Class HttpResponse
28
 * @package Quantum\Http\Response
29
 */
30
abstract class HttpResponse
31
{
32
33
    use Header;
34
    use Body;
35
36
    /**
37
     * HTML content type
38
     */
39
    const CONTENT_HTML = 'text/html';
40
41
    /**
42
     * XML content type
43
     */
44
    const CONTENT_XML = 'application/xml';
45
46
    /**
47
     * JSON content type
48
     */
49
    const CONTENT_JSON = 'application/json';
50
51
    /**
52
     * JSONP content type
53
     */
54
    const CONTENT_JSONP = 'application/javascript';
55
56
    /**
57
     * Status code
58
     * @var int
59
     */
60
    private static $__statusCode = 200;
61
62
    /**
63
     * XML root element
64
     * @var string
65
     */
66
    private static $xmlRoot = '<data></data>';
67
68
    /**
69
     * Status texts
70
     * @var array
71
     */
72
    public static $statusTexts = [];
73
74
    /**
75
     * Callback function
76
     * @var string
77
     */
78
    private static $callbackFunction = '';
79
80
81
    /**
82
     * @var bool
83
     */
84
    private static $initialized = false;
85
86
    /**
87
     * Initialize the Response
88
     * @throws HttpException
89
     * @throws LangException
90
     */
91
    public static function init()
92
    {
93
        if (self::$initialized) {
94
            return;
95
        }
96
97
        if (empty(self::$statusTexts)) {
98
            self::$statusTexts = require_once 'statuses.php';
99
        }
100
101
        self::$initialized = true;
102
    }
103
104
    /**
105
     * Flushes the response header and body
106
     */
107
    public static function flush()
108
    {
109
        self::$__statusCode = 200;
110
        self::$__headers = [];
111
        self::$__response = [];
112
    }
113
114
    /**
115
     * Sends all response data to the client and finishes the request.
116
     * @throws Exception
117
     */
118
    public static function send()
119
    {
120
        if (Environment::getInstance()->getAppEnv() != 'testing') {
121
            while (ob_get_level() > 0) {
122
                ob_end_clean();
123
            }
124
        }
125
126
        foreach (self::$__headers as $key => $value) {
127
            header($key . ': ' . $value);
128
        }
129
130
        http_response_code(self::getStatusCode());
131
132
        echo self::getContent();
133
    }
134
135
    /**
136
     * Gets the response content
137
     * @return string
138
     * @throws Exception
139
     */
140
    public static function getContent(): string
141
    {
142
        $content = '';
143
144
        switch (self::getContentType()) {
145
            case self::CONTENT_JSON:
146
                $content = json_encode(self::all());
147
                break;
148
            case self::CONTENT_XML:
149
                $content = self::arrayToXml(self::all());
150
                break;
151
            case self::CONTENT_HTML:
152
                $content = self::get('_qt_rendered_view');
153
                break;
154
            case self::CONTENT_JSONP:
155
                $content = self::getJsonPData(self::all());
156
                break;
157
            default :
158
                break;
159
        }
160
161
        return $content;
162
    }
163
164
    /**
165
     * Set the status code
166
     * @param int $code
167
     */
168
    public static function setStatusCode(int $code)
169
    {
170
        if (!array_key_exists($code, self::$statusTexts)) {
171
            throw new InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
172
        }
173
174
        self::$__statusCode = $code;
175
    }
176
177
    /**
178
     * Gets the status code
179
     * @return int
180
     */
181
    public static function getStatusCode(): int
182
    {
183
        return self::$__statusCode;
184
    }
185
186
    /**
187
     * Gets the status text
188
     * @return string
189
     */
190
    public static function getStatusText(): string
191
    {
192
        return self::$statusTexts[self::$__statusCode];
193
    }
194
195
    /**
196
     * Redirect
197
     * @param string $url
198
     * @param int $code
199
     * @throws StopExecutionException
200
     */
201
    public static function redirect(string $url, int $code = 302)
202
    {
203
        self::setStatusCode($code);
204
        self::setHeader('Location', $url);
205
        stop();
206
    }
207
208
    /**
209
     * Prepares the JSON response
210
     * @param array|null $data
211
     * @param int|null $code
212
     */
213
    public static function json(array $data = null, int $code = null)
214
    {
215
        self::setContentType(self::CONTENT_JSON);
216
217
        if (!is_null($code)) {
218
            self::setStatusCode($code);
219
        }
220
221
        if ($data) {
222
            self::$__response = array_merge(self::$__response, $data);
223
        }
224
    }
225
226
    /**
227
     * Prepares the JSONP response
228
     * @param string $callback
229
     * @param array|null $data
230
     * @param int|null $code
231
     */
232
    public static function jsonp(string $callback, ?array $data = null, int $code = null)
233
    {
234
        self::setContentType(self::CONTENT_JSONP);
235
236
        self::$callbackFunction = $callback;
237
238
        if (!is_null($code)) {
239
            self::setStatusCode($code);
240
        }
241
242
        if ($data) {
243
            self::$__response = array_merge(self::$__response, $data);
244
        }
245
    }
246
247
    /**
248
     * Returns response with function
249
     * @param array $data
250
     * @return string
251
     */
252
    public static function getJsonPData(array $data): string
253
    {
254
        return self::$callbackFunction . '(' . json_encode($data) . ")";
255
    }
256
257
    /**
258
     * Prepares the XML response
259
     * @param array|null $data
260
     * @param int|null $code
261
     */
262
    public static function xml(array $data = null, $root = '<data></data>', int $code = null)
263
    {
264
        self::setContentType(self::CONTENT_XML);
265
266
        if (!is_null($code)) {
267
            self::setStatusCode($code);
268
        }
269
270
        self::$xmlRoot = $root;
271
272
        if ($data) {
273
            self::$__response = array_merge(self::$__response, $data);
274
        }
275
    }
276
277
    /**
278
     * Prepares the HTML content
279
     * @param string $html
280
     * @param int|null $code
281
     */
282
    public static function html(string $html, int $code = null)
283
    {
284
        self::setContentType(self::CONTENT_HTML);
285
286
        if (!is_null($code)) {
287
            self::setStatusCode($code);
288
        }
289
290
        self::$__response['_qt_rendered_view'] = $html;
291
    }
292
293
    /**
294
     * Transforms array to XML
295
     * @param array $arr
296
     * @return string
297
     * @throws Exception
298
     */
299
    private static function arrayToXML(array $arr): string
300
    {
301
        $simpleXML = new SimpleXMLElement(self::$xmlRoot);
302
        self::composeXML($arr, $simpleXML);
303
304
        $dom = new DOMDocument();
305
        $dom->loadXML($simpleXML->asXML());
306
        $dom->formatOutput = true;
307
        return $dom->saveXML();
308
    }
309
310
    /**
311
     * Compose XML
312
     * @param array $arr
313
     * @param SimpleXMLElement $simpleXML
314
     */
315
    private static function composeXML(array $arr, SimpleXMLElement &$simpleXML)
316
    {
317
        foreach ($arr as $key => $value) {
318
            if (is_numeric($key)) {
319
                $key = 'item' . $key;
320
            }
321
322
            $tag = $key;
323
            $attributes = null;
324
325
            if (strpos($key, '@') !== false) {
326
                list($tag, $attributes) = explode('@', $key);
327
                $attributes = json_decode($attributes);
328
            }
329
330
            if (is_array($value)) {
331
                $child = $simpleXML->addChild($tag);
332
                if ($attributes) {
333
                    foreach ($attributes as $attrKey => $attrVal) {
334
                        $child->addAttribute($attrKey, $attrVal);
335
                    }
336
                }
337
338
                self::composeXML($value, $child);
339
            } else {
340
                $child = $simpleXML->addChild($tag, htmlspecialchars($value));
341
342
                if ($attributes) {
343
                    foreach ($attributes as $attrKey => $attrVal) {
344
                        $child->addAttribute($attrKey, $attrVal);
345
                    }
346
                }
347
            }
348
        }
349
    }
350
}
351