Passed
Push — master ( 11c67b...955441 )
by Atanas
02:20
created

Response::respond()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 6
1
<?php
2
3
namespace WPEmerge;
4
5
use GuzzleHttp\Psr7;
6
use GuzzleHttp\Psr7\Response as Psr7Response;
7
use WPEmerge;
8
use WPEmerge\Helpers\Mixed;
9
use Psr\Http\Message\ResponseInterface;
10
11
/**
12
 * A collection of tools for the creation of responses
13
 */
14
class Response {
15
	/**
16
	 * Create a new response object
17
	 *
18
	 * @return ResponseInterface
19
	 */
20 1
	public static function response() {
21 1
		return new Psr7Response();
22
	}
23
24
	/**
25
	 * Send output based on a response object
26
	 * @credit modified version of slimphp/slim - Slim/App.php
27
	 *
28
	 * @codeCoverageIgnore
29
	 * @param  ResponseInterface $response
30
	 * @return void
31
	 */
32
	public static function respond( ResponseInterface $response ) {
33
		if ( ! headers_sent() ) {
34
			static::sendHeaders( $response );
35
		}
36
		static::sendBody( $response );
37
	}
38
39
	/**
40
	 * Send a request's headers to the client
41
	 *
42
	 * @codeCoverageIgnore
43
	 * @param  ResponseInterface $response
44
	 * @return void
45
	 */
46
	protected static function sendHeaders( ResponseInterface $response ) {
47
		// Status
48
		header( sprintf(
49
			'HTTP/%s %s %s',
50
			$response->getProtocolVersion(),
51
			$response->getStatusCode(),
52
			$response->getReasonPhrase()
53
		) );
54
55
		// Headers
56
		foreach ( $response->getHeaders() as $name => $values ) {
57
			foreach ( $values as $value ) {
58
				header( sprintf( '%s: %s', $name, $value ), false );
59
			}
60
		}
61
	}
62
63
	/**
64
	 * Get a response's body stream so it is ready to be read
65
	 *
66
	 * @codeCoverageIgnore
67
	 * @param  ResponseInterface                 $response
68
	 * @return \Psr\Http\Message\StreamInterface
69
	 */
70
	protected static function getBody( ResponseInterface $response ) {
71
		$body = $response->getBody();
72
		if ( $body->isSeekable() ) {
73
			$body->rewind();
74
		}
75
		return $body;
76
	}
77
78
	/**
79
	 * Get a response's body's content length
80
	 *
81
	 * @codeCoverageIgnore
82
	 * @param  ResponseInterface $response
83
	 * @return integer
84
	 */
85
	protected static function getBodyContentLength( ResponseInterface $response ) {
86
		$content_length = $response->getHeaderLine( 'Content-Length' );
87
88
		if ( ! $content_length ) {
89
			$body = static::getBody( $response );
90
			$content_length = $body->getSize();
91
		}
92
93
		if ( ! is_numeric( $content_length ) ) {
94
			$content_length = 0;
95
		}
96
97
		return (integer) $content_length;
98
	}
99
100
	/**
101
	 * Send a request's body to the client
102
	 *
103
	 * @codeCoverageIgnore
104
	 * @param  ResponseInterface $response
105
	 * @param  integer           $chunk_size
106
	 * @return void
107
	 */
108
	protected static function sendBody( ResponseInterface $response, $chunk_size = 4096 ) {
109
		$body = static::getBody( $response );
110
		$content_length = static::getBodyContentLength( $response );
111
112
		$content_left = $content_length ? $content_length : -1;
113
		$amount_to_read = $content_left > -1 ? min( $chunk_size, $content_left ) : $chunk_size;
114
115
		while ( ! $body->eof() && $amount_to_read > 0 ) {
116
			echo $body->read( $amount_to_read );
117
118
			if ( $content_left > -1 ) {
119
				$content_left -= $amount_to_read;
120
			}
121
122
			if ( connection_status() != CONNECTION_NORMAL ) {
123
				break;
124
			}
125
		}
126
	}
127
128
	/**
129
	 * Get a cloned response with the passed string as the body
130
	 *
131
	 * @param  ResponseInterface $response
132
	 * @param  string            $output
133
	 * @return ResponseInterface
134
	 */
135 1
	public static function output( ResponseInterface $response, $output ) {
136 1
		$response = $response->withBody( Psr7\stream_for( $output ) );
137 1
		return $response;
138
	}
139
140
	/**
141
	 * Get a cloned response, resolving and rendering a view as the body
142
	 *
143
	 * @param  ResponseInterface $response
144
	 * @param  string|string[]   $views
145
	 * @param  array             $context
146
	 * @return ResponseInterface
147
	 */
148 1
	public static function view( ResponseInterface $response, $views, $context = array() ) {
149 1
		$views = Mixed::toArray( $views );
150 1
		$engine = WPEmerge::resolve( WPEMERGE_VIEW_ENGINE_KEY );
151 1
		$html = $engine->render( $views, $context );
152
153 1
		$response = $response->withHeader( 'Content-Type', 'text/html' );
154 1
		$response = $response->withBody( Psr7\stream_for( $html ) );
155 1
		return $response;
156
	}
157
158
	/**
159
	 * Get a cloned response, json encoding the passed data as the body
160
	 *
161
	 * @param  ResponseInterface $response
162
	 * @param  mixed             $data
163
	 * @return ResponseInterface
164
	 */
165 1
	public static function json( ResponseInterface $response, $data ) {
166 1
		$response = $response->withHeader( 'Content-Type', 'application/json' );
167 1
		$response = $response->withBody( Psr7\stream_for( wp_json_encode( $data ) ) );
168 1
		return $response;
169
	}
170
171
	/**
172
	 * Get a cloned response, with location and status headers
173
	 *
174
	 * @param  ResponseInterface $response
175
	 * @param  string            $url
176
	 * @param  integer           $status
177
	 * @return ResponseInterface
178
	 */
179 2
	public static function redirect( ResponseInterface $response, $url, $status = 302 ) {
180 2
		$response = $response->withStatus( $status );
181 2
		$response = $response->withHeader( 'Location', $url );
182 2
		return $response;
183
	}
184
185
	/**
186
	 * Get a cloned response, with location header equal to the current url and status header
187
	 *
188
	 * @param  ResponseInterface $response
189
	 * @param  \WPEmerge\Request $request
190
	 * @param  integer           $status
191
	 * @return ResponseInterface
192
	 */
193 2
	public static function reload( ResponseInterface $response, $request, $status = 302 ) {
194 2
		return static::redirect( $response, $request->getUrl(), $status );
195
	}
196
197
	/**
198
	 * Get a cloned response, with status headers and rendering a suitable view as the body
199
	 *
200
	 * @param  ResponseInterface $response
201
	 * @param  integer           $status
202
	 * @return ResponseInterface
203
	 */
204 1
	public static function error( ResponseInterface $response, $status ) {
205 1
		global $wp_query;
206 1
		if ( $status === 404 ) {
207 1
			$wp_query->set_404();
208 1
		}
209
210 1
		$response = $response->withStatus( $status );
211 1
		return static::view( $response, [$status . '.php', 'index.php'] );
212
	}
213
}
214