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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 |
||
| 32 | class HttpResponse implements HttpResponseInterface |
||
|
|
|||
| 33 | { |
||
| 34 | /** |
||
| 35 | * Status of the response as integer value. |
||
| 36 | * $statusCode = '200' => 'OK'. |
||
| 37 | * |
||
| 38 | * @var int |
||
| 39 | */ |
||
| 40 | private static $statusCode = '200'; |
||
| 41 | |||
| 42 | /** |
||
| 43 | * @var array Array holding the response headers. |
||
| 44 | */ |
||
| 45 | private static $headers = []; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * @var string String holding the response content (body). |
||
| 49 | */ |
||
| 50 | private static $content = null; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * @var string String holding the content type. |
||
| 54 | */ |
||
| 55 | private static $content_type = 'text/html'; |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Sets the HTTP Status Code for this response. |
||
| 59 | * This method is also used to set the return status code when there |
||
| 60 | * is no error (for example for the status codes 200 (OK) or 301 (Moved permanently) ). |
||
| 61 | * |
||
| 62 | * @param int $statusCode The status code to set |
||
| 63 | */ |
||
| 64 | public static function setStatusCode($statusCode) |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Returns the HTTP Status Code. |
||
| 71 | * |
||
| 72 | * @return int HTTP Status Code. |
||
| 73 | */ |
||
| 74 | public static function getStatusCode() |
||
| 78 | |||
| 79 | /** |
||
| 80 | * Returns the HTTP 1.1 status code description for a given status code. |
||
| 81 | * |
||
| 82 | * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html |
||
| 83 | */ |
||
| 84 | public static function getStatusCodeDescription($statusCode) |
||
| 85 | { |
||
| 86 | /** |
||
| 87 | * Array holding some often occuring status descriptions. |
||
| 88 | * |
||
| 89 | * @var array |
||
| 90 | */ |
||
| 91 | static $statusCodes = [ |
||
| 92 | // Successful |
||
| 93 | '200' => 'OK', |
||
| 94 | '201' => 'Created', |
||
| 95 | '202' => 'Accepted', |
||
| 96 | // Redirection |
||
| 97 | '301' => 'Moved Permanently', |
||
| 98 | '302' => 'Found', |
||
| 99 | '303' => 'See Other', |
||
| 100 | '304' => 'Not Modified', |
||
| 101 | '307' => 'Temporary Redirect', |
||
| 102 | // Client Error |
||
| 103 | '400' => 'Bad Request', |
||
| 104 | '401' => 'Unauthorized', |
||
| 105 | '403' => 'Forbidden', |
||
| 106 | '404' => 'Not Found', |
||
| 107 | // Server Error |
||
| 108 | '500' => 'Internal Server Error', |
||
| 109 | '502' => 'Bad Gateway', |
||
| 110 | '503' => 'Service Temporarily Unavailable', |
||
| 111 | ]; |
||
| 112 | |||
| 113 | return $statusCodes[$statusCode]; |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Adds a header to the response array, which is send to the browser. |
||
| 118 | * |
||
| 119 | * @param string $name the name of the header |
||
| 120 | * @param string $value the value of the header |
||
| 121 | */ |
||
| 122 | public static function addHeader($name, $value) |
||
| 126 | |||
| 127 | /** |
||
| 128 | * setContent appends or replaces the content of the http response buffer. |
||
| 129 | * |
||
| 130 | * appends content to the response body. |
||
| 131 | * when $replace is true, the bodycontent is replaced. |
||
| 132 | * |
||
| 133 | * @param string $content Content to store in the buffer |
||
| 134 | * @param bool $replace Toggle between append or replace. |
||
| 135 | */ |
||
| 136 | public static function setContent($content, $replace = false) |
||
| 147 | |||
| 148 | /** |
||
| 149 | * get content retunrs the response body. |
||
| 150 | */ |
||
| 151 | public static function getContent() |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Set the content type. |
||
| 158 | * |
||
| 159 | * @param string $type Content type: html, txt, xml, json. |
||
| 160 | * |
||
| 161 | * @return string |
||
| 162 | */ |
||
| 163 | public static function setContentType($type = 'html', $charset = 'UTF-8') |
||
| 164 | { |
||
| 165 | $types = [ |
||
| 166 | 'csv' => 'text/csv', |
||
| 167 | 'html' => 'text/html', |
||
| 168 | 'txt' => 'text/plain', |
||
| 169 | 'xml' => 'application/xml', |
||
| 170 | 'rss' => 'application/rss+xml', |
||
| 171 | 'json' => 'application/json', |
||
| 172 | 'js' => 'application/javascript', |
||
| 173 | ]; |
||
| 174 | |||
| 175 | if (isset($types[$type]) === false) { |
||
| 176 | throw new \InvalidArgumentException('Specified type not valid. Use: html, txt, xml or json.'); |
||
| 177 | } |
||
| 178 | |||
| 179 | #addHeader('Content-Type', $type . ($charset ? '; charset='.$charset.': '')); |
||
| 180 | self::$content_type = $types[$type]; |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * Returns the content type for insertion into the header. |
||
| 185 | * |
||
| 186 | * @return string A content type, like "application/json" or "text/html". |
||
| 187 | */ |
||
| 188 | public static function getContentType() |
||
| 192 | |||
| 193 | /** |
||
| 194 | * This flushes the headers and bodydata to the client. |
||
| 195 | */ |
||
| 196 | public static function sendResponse() |
||
| 197 | { |
||
| 198 | // save session before exit |
||
| 199 | if ((bool) session_id()) { |
||
| 200 | session_write_close(); |
||
| 201 | } |
||
| 202 | |||
| 203 | // activateOutputCompression when not in debugging mode |
||
| 204 | if (defined('DEBUG') and DEBUG === false) { |
||
| 205 | \Koch\Http\ResponseCompression::startBuffer(); |
||
| 206 | } |
||
| 207 | |||
| 208 | // Send the status line |
||
| 209 | self::addHeader('HTTP/1.1', self::$statusCode . ' ' . self::getStatusCodeDescription(self::$statusCode)); |
||
| 210 | |||
| 211 | // Suppress Framesets |
||
| 212 | self::addHeader('X-Frame-Options', 'deny'); // not SAMEORIGIN |
||
| 213 | |||
| 214 | // Send our Content-Type with UTF-8 encoding |
||
| 215 | self::addHeader('Content-Type', self::getContentType() . '; charset=UTF-8'); |
||
| 216 | |||
| 217 | // Send user specificed headers from self::$headers array |
||
| 218 | if (false === headers_sent()) { |
||
| 219 | foreach (self::$headers as $name => $value) { |
||
| 220 | header($name . ': ' . $value, false); |
||
| 221 | } |
||
| 222 | } |
||
| 223 | |||
| 224 | // make it possible to attach HTML content to the body directly before flushing the response |
||
| 225 | // \Clansuite\Application::triggerEvent('onBeforeResponse', array('content' => self::$content)); |
||
| 226 | |||
| 227 | // Finally echo the response body |
||
| 228 | echo self::getContent(); |
||
| 229 | |||
| 230 | if (defined('DEBUG') and DEBUG === false) { |
||
| 231 | \Koch\Http\ResponseCompression::flushCompressedBuffer(); |
||
| 232 | } |
||
| 233 | |||
| 234 | // OK, Reset -> Package delivered! Return to Base! |
||
| 235 | self::clearHeaders(); |
||
| 236 | |||
| 237 | return true; |
||
| 238 | } |
||
| 239 | |||
| 240 | /** |
||
| 241 | * Resets the headers and content. |
||
| 242 | * |
||
| 243 | * @return bool true. |
||
| 244 | */ |
||
| 245 | public static function clearHeaders() |
||
| 246 | { |
||
| 247 | self::$headers = []; |
||
| 248 | self::$content = null; |
||
| 249 | |||
| 250 | return true; |
||
| 251 | } |
||
| 252 | /** |
||
| 253 | * A better alternative (RFC 2109 compatible) to the php setcookie() function. |
||
| 254 | * |
||
| 255 | * @param string Name of the cookie |
||
| 256 | * @param string Value of the cookie |
||
| 257 | * @param int Lifetime of the cookie |
||
| 258 | * @param string Path where the cookie can be used |
||
| 259 | * @param string Domain which can read the cookie |
||
| 260 | * @param bool Secure mode? |
||
| 261 | * @param bool Only allow HTTP usage? (PHP 5.2) |
||
| 262 | * |
||
| 263 | * @return bool Cookie set. |
||
| 264 | */ |
||
| 265 | public static function setCookie($name, $value = '', $maxage = 0, $path = '', $domain = '', $secure = false, $HTTPOnly = false) |
||
| 266 | { |
||
| 267 | $ob = ini_get('output_buffering'); |
||
| 268 | |||
| 269 | // Abort the method if headers have already been sent, except when output buffering has been enabled |
||
| 270 | if (headers_sent() && (bool) $ob === false or mb_strtolower($ob) === 'off') { |
||
| 271 | return false; |
||
| 272 | } |
||
| 273 | |||
| 274 | if (false === empty($domain)) { |
||
| 275 | // Fix the domain to accept domains with and without 'www.'. |
||
| 276 | if (mb_strtolower(mb_substr($domain, 0, 4)) === 'www.') { |
||
| 277 | $domain = mb_substr($domain, 4); |
||
| 278 | } |
||
| 279 | |||
| 280 | // Add the dot prefix to ensure compatibility with subdomains |
||
| 281 | if (mb_substr($domain, 0, 1) !== '.') { |
||
| 282 | $domain = '.' . $domain; |
||
| 283 | } |
||
| 284 | |||
| 285 | // Remove port information. |
||
| 286 | $port = mb_strpos($domain, ':'); |
||
| 287 | |||
| 288 | if ($port !== false) { |
||
| 289 | $domain = mb_substr($domain, 0, $port); |
||
| 290 | } |
||
| 291 | } |
||
| 292 | |||
| 293 | header( |
||
| 294 | 'Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value) |
||
| 295 | . (true === empty($domain) ? '' : '; Domain=' . $domain) |
||
| 296 | . (true === empty($maxage) ? '' : '; Max-Age=' . $maxage) |
||
| 297 | . (true === empty($path) ? '' : '; Path=' . $path) |
||
| 298 | . (false === $secure ? '' : '; Secure') |
||
| 299 | . (false === $HTTPOnly ? '' : '; HttpOnly'), |
||
| 300 | false |
||
| 301 | ); |
||
| 302 | |||
| 303 | return true; |
||
| 304 | } |
||
| 305 | |||
| 306 | /** |
||
| 307 | * Deletes a cookie. |
||
| 308 | * |
||
| 309 | * @param string $name Name of the cookie |
||
| 310 | * @param string $path Path where the cookie is used |
||
| 311 | * @param string $domain Domain of the cookie |
||
| 312 | * @param bool Secure mode? |
||
| 313 | * @param bool Only allow HTTP usage? (PHP 5.2) |
||
| 314 | */ |
||
| 315 | public static function deleteCookie($name, $path = '/', $domain = '', $secure = false, $httponly = null) |
||
| 316 | { |
||
| 317 | // expire = 324993600 = 1980-04-19 |
||
| 318 | setcookie($name, '', 324993600, $path, $domain, $secure, $httponly); |
||
| 319 | } |
||
| 320 | |||
| 321 | /** |
||
| 322 | * Sets NoCache Header Values. |
||
| 323 | */ |
||
| 324 | public static function setNoCacheHeader() |
||
| 325 | { |
||
| 326 | // set nocache via session |
||
| 327 | #session_cache_limiter('nocache'); |
||
| 328 | // reset pragma header |
||
| 329 | self::addHeader('Pragma', 'no-cache'); |
||
| 330 | // reset cache-control |
||
| 331 | self::addHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); |
||
| 332 | // append cache-control |
||
| 333 | self::addHeader('Cache-Control', 'post-check=0, pre-check=0'); |
||
| 334 | // force immediate expiration |
||
| 335 | self::addHeader('Expires', '1'); |
||
| 336 | // set date of last modification |
||
| 337 | self::addHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); |
||
| 338 | } |
||
| 339 | |||
| 340 | /** |
||
| 341 | * Detects a flashmessage tunneling via the redirect messagetext. |
||
| 342 | * |
||
| 343 | * @param string $message Redirect Message ("flashmessagetype#message text") |
||
| 344 | */ |
||
| 345 | public static function detectTypeAndSetFlashmessage($message) |
||
| 346 | { |
||
| 347 | // detect if a flashmessage is tunneled |
||
| 348 | if ($message !== null and true === (bool) strpos($message, '#')) { |
||
| 349 | // split at tunneling separator |
||
| 350 | $array = explode('#', $message); |
||
| 351 | // results in: array[0] = type and array[1] = message) |
||
| 352 | \Koch\Session\FlashMessages::setMessage($array[0], $array[1]); |
||
| 353 | // return the message |
||
| 354 | return $array[1]; |
||
| 355 | } |
||
| 356 | } |
||
| 357 | |||
| 358 | /** |
||
| 359 | * Redirect. |
||
| 360 | * |
||
| 361 | * Redirects to another action after disabling the caching. |
||
| 362 | * This avoids the typical reposting after an POST is send by disabling the cache. |
||
| 363 | * This enables the POST-Redirect-GET Workflow. |
||
| 364 | * |
||
| 365 | * @param string Redirect to this URL |
||
| 366 | * @param int seconds before redirecting (for the html tag "meta refresh") |
||
| 367 | * @param int http status code, default: '303' => 'See other' |
||
| 368 | * @param string redirect message |
||
| 369 | */ |
||
| 370 | public static function redirectNoCache($url, $time = 0, $statusCode = 303, $message = '') |
||
| 375 | |||
| 376 | /** |
||
| 377 | * Redirect, redirects to an URL. |
||
| 378 | * This redirects automatically, when headers are not already sent, |
||
| 379 | * else it provides a link to the target URL for manual redirection. |
||
| 380 | * |
||
| 381 | * Time defines how long the redirect screen will be displayed. |
||
| 382 | * Statuscode defines a http status code. The default value is 303. |
||
| 383 | * Text is a message string for the html body of the redirect screen. |
||
| 384 | * |
||
| 385 | * @param string Redirect to this URL |
||
| 386 | * @param int seconds before redirecting (for the html tag "meta refresh") |
||
| 387 | * @param int http status code, default: '303' => 'See other' |
||
| 388 | * @param text text of redirect message |
||
| 389 | * @param string redirect mode LOCATION, REFRESH, JS, HTML |
||
| 390 | * @param string $mode |
||
| 391 | */ |
||
| 392 | public static function redirect($url, $time = 0, $statusCode = 303, $message = null, $mode = null) |
||
| 449 | } |
||
| 450 |
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.