Passed
Push — master ( 43db54...cc5a21 )
by Atanas
02:03
created

Response::resolveTemplateFromFilesystem()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 8
ccs 0
cts 5
cp 0
crap 12
rs 9.4285
1
<?php
2
3
namespace CarbonFramework;
4
5
use GuzzleHttp\Psr7;
6
use GuzzleHttp\Psr7\Response as Psr7Response;
7
use Psr\Http\Message\ResponseInterface;
8
9
/**
10
 * A collection of tools for the creation of responses
11
 */
12
class Response {
13
	/**
14
	 * Create a new response object
15
	 *
16
	 * @return ResponseInterface
17
	 */
18 1
	public static function response() {
19 1
		return new Psr7Response();
20
	}
21
22
	/**
23
	 * Send output based on a response object
24
	 * @credit modified version of slimphp/slim - Slim/App.php
25
	 *
26
	 * @codeCoverageIgnore
27
	 * @param  ResponseInterface $response
28
	 * @return null
29
	 */
30
	public static function respond( ResponseInterface $response ) {
31
		if ( ! headers_sent() ) {
32
			static::sendHeaders( $response );
33
		}
34
		static::sendBody( $response );
35
	}
36
37
	/**
38
	 * Send a request's headers to the client
39
	 *
40
	 * @param  ResponseInterface $response
41
	 * @return null
42
	 */
43
	protected static function sendHeaders( ResponseInterface $response ) {
44
		// Status
45
		header( sprintf(
46
			'HTTP/%s %s %s',
47
			$response->getProtocolVersion(),
48
			$response->getStatusCode(),
49
			$response->getReasonPhrase()
50
		) );
51
52
		// Headers
53
		foreach ( $response->getHeaders() as $name => $values ) {
54
			foreach ( $values as $value ) {
55
				header( sprintf( '%s: %s', $name, $value ), false );
56
			}
57
		}
58
	}
59
60
	/**
61
	 * Return a response's body stream so it is ready to be read
62
	 *
63
	 * @param  ResponseInterface $response
64
	 * @return ResponseInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be \Psr\Http\Message\StreamInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
65
	 */
66
	protected static function getBody( ResponseInterface $response ) {
67
		$body = $response->getBody();
68
		if ( $body->isSeekable() ) {
69
			$body->rewind();
70
		}
71
		return $body;
72
	}
73
74
	/**
75
	 * Return a response's body's content length
76
	 *
77
	 * @param  ResponseInterface $response
78
	 * @return integer
79
	 */
80
	protected static function getBodyContentLength( ResponseInterface $response ) {
81
		$content_length = $response->getHeaderLine( 'Content-Length' );
82
		if ( ! $content_length ) {
83
			$body = static::getBody( $response );
84
			$content_length = $body->getSize();
85
		}
86
		return $content_length;
87
	}
88
89
	/**
90
	 * Send a request's body to the client
91
	 *
92
	 * @param  ResponseInterface $response
93
	 * @return null
94
	 */
95
	protected static function sendBody( ResponseInterface $response, $chunk_size = 4096 ) {
96
		$body = static::getBody( $response );
97
		$content_length = static::getBodyContentLength( $response );
98
99
		$content_left = $content_length ? $content_length : -1;
100
		$amount_to_read = $content_left > -1 ? min( $chunk_size, $content_left ) : $chunk_size;
101
102
		while ( ! $body->eof() ) {
103
			echo $body->read( $amount_to_read );
104
105
			if ( $content_left > -1 ) {
106
				$content_left -= $amount_to_read;
107
			}
108
109
			if ( connection_status() != CONNECTION_NORMAL ) {
110
				break;
111
			}
112
		}
113
	}
114
115
	/**
116
	 * Return a cloned response with the passed string as the body
117
	 *
118
	 * @param  ResponseInterface $response
119
	 * @param  string            $output
120
	 * @return ResponseInterface
121
	 */
122
	public static function output( ResponseInterface $response, $output ) {
123
		$response = $response->withBody( Psr7\stream_for( $output ) );
124
		return $response;
125
	}
126
127
	/**
128
	 * Resolve a template or a template array to an absolute filepath
129
	 *
130
	 * @param  string|string[] $templates
131
	 * @return string
132
	 */
133
	protected static function resolveTemplate( $templates ) {
134
		$templates = is_array( $templates ) ? $templates : [$templates];
135
		$template = locate_template( $templates, false );
136
137
		// locate_template failed to find the template - test if a valid absolute path was passed
138
		if ( ! $template ) {
139
			$template = static::resolveTemplateFromFilesystem( $templates );
140
		}
141
142
		return $template;
143
	}
144
145
	/**
146
	 * Resolve the first existing absolute template filepath from an array of template filepaths
147
	 *
148
	 * @param  string[] $templates
149
	 * @return string
150
	 */
151
	protected static function resolveTemplateFromFilesystem( $templates ) {
152
		foreach ( $templates as $template ) {
153
			if ( file_exists( $template ) ) {
154
				return $template;
155
			}
156
		}
157
		return '';
158
	}
159
160
	/**
161
	 * Return a cloned response, resolving and rendering a template as the body
162
	 *
163
	 * @param  ResponseInterface $response
164
	 * @param  string|string[]   $templates
165
	 * @param  array             $context
166
	 * @return ResponseInterface
167
	 */
168
	public static function template( ResponseInterface $response, $templates, $context = array() ) {
169
		$template = static::resolveTemplate( $templates );
170
171
		$engine = Framework::resolve( 'framework.templating.engine' );
172
		$html = $engine->render( $template, $context );
173
174
		$response = $response->withHeader( 'Content-Type', 'text/html' );
175
		$response = $response->withBody( Psr7\stream_for( $html ) );
176
		return $response;
177
	}
178
179
	/**
180
	 * Return a cloned response, json encoding the passed data as the body
181
	 *
182
	 * @param  ResponseInterface $response
183
	 * @param  mixed             $data
184
	 * @return ResponseInterface
185
	 */
186
	public static function json( ResponseInterface $response, $data ) {
187
		$response = $response->withHeader( 'Content-Type', 'application/json' );
188
		$response = $response->withBody( Psr7\stream_for( wp_json_encode( $data ) ) );
189
		return $response;
190
	}
191
192
	/**
193
	 * Return a cloned response, with location and status headers
194
	 *
195
	 * @param  ResponseInterface $response
196
	 * @param  string            $url
197
	 * @param  integer           $status
198
	 * @return ResponseInterface
199
	 */
200
	public static function redirect( ResponseInterface $response, $url, $status = 302 ) {
201
		$response = $response->withStatus( $status );
202
		$response = $response->withHeader( 'Location', $url );
203
		return $response;
204
	}
205
206
	/**
207
	 * Return a cloned response, with status headers and rendering a suitable template as the body
208
	 *
209
	 * @param  ResponseInterface $response
210
	 * @param  integer           $status
211
	 * @return ResponseInterface
212
	 */
213
	public static function error( ResponseInterface $response, $status ) {
214
		global $wp_query;
215
		if ( $status === 404 ) {
216
			$wp_query->set_404();
217
		}
218
219
		$response = $response->withStatus( $status );
220
		return static::template( $response, array( $status . '.php', 'index.php' ) );
221
	}
222
}
223