Total Complexity | 40 |
Total Lines | 315 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 1 | Features | 0 |
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 |
||
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 |
||
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) |
||
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) |
||
345 | } |
||
346 | } |
||
347 | } |
||
348 | } |
||
349 | } |
||
350 | } |
||
351 |