Passed
Push — master ( 74a67e...bf1276 )
by Atanas
01:58
created

Response::sendBodyWithLength()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
212
	}
213
214
	/**
215
	 * Get a view convertible to a response.
216
	 *
217
	 * @param  string|string[]   $views
218
	 * @param  array             $context
219
	 * @return ViewInterface
220
	 */
221 1
	public static function view( $views, $context = [] ) {
222 1
		$views = Mixed::toArray( $views );
223 1
		$engine = Framework::resolve( WPEMERGE_VIEW_ENGINE_KEY );
224 1
		return $engine->make( $views, $context );
225
	}
226
227
	/**
228
	 * Get an error response, with status headers and rendering a suitable view as the body.
229
	 *
230
	 * @param  integer           $status
231
	 * @return ResponseInterface
232
	 */
233 1
	public static function error( $status ) {
234 1
		global $wp_query;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
235 1
		if ( $status === 404 ) {
236 1
			$wp_query->set_404();
237
		}
238
239 1
		return static::view( [$status, 'error', 'index'] )
240 1
			->toResponse()
241 1
			->withStatus( $status );
242
	}
243
}
244