33namespace React \Http \Message ;
44
55use Fig \Http \Message \StatusCodeInterface ;
6+ use Psr \Http \Message \ResponseInterface ;
67use Psr \Http \Message \StreamInterface ;
78use React \Http \Io \BufferedBody ;
89use React \Http \Io \HttpBodyStream ;
910use React \Stream \ReadableStreamInterface ;
10- use RingCentral \Psr7 \Response as Psr7Response ;
11+ use RingCentral \Psr7 \MessageTrait ;
1112
1213/**
1314 * Represents an outgoing server response message.
4041 *
4142 * @see \Psr\Http\Message\ResponseInterface
4243 */
43- final class Response extends Psr7Response implements StatusCodeInterface
44+ final class Response extends MessageTrait implements ResponseInterface, StatusCodeInterface
4445{
4546 /**
4647 * Create an HTML response
@@ -257,6 +258,41 @@ public static function xml($xml)
257258 return new self (self ::STATUS_OK , array ('Content-Type ' => 'application/xml ' ), $ xml );
258259 }
259260
261+ /**
262+ * @var bool
263+ * @see self::$phrasesMap
264+ */
265+ private static $ phrasesInitialized = false ;
266+
267+ /**
268+ * Map of standard HTTP status codes to standard reason phrases.
269+ *
270+ * This map will be fully populated with all standard reason phrases on
271+ * first access. By default, it only contains a subset of HTTP status codes
272+ * that have a custom mapping to reason phrases (such as those with dashes
273+ * and all caps words). See `self::STATUS_*` for all possible status code
274+ * constants.
275+ *
276+ * @var array<int,string>
277+ * @see self::STATUS_*
278+ * @see self::getReasonPhraseForStatusCode()
279+ */
280+ private static $ phrasesMap = array (
281+ 200 => 'OK ' ,
282+ 203 => 'Non-Authoritative Information ' ,
283+ 207 => 'Multi-Status ' ,
284+ 226 => 'IM Used ' ,
285+ 414 => 'URI Too Large ' ,
286+ 418 => 'I \'m a teapot ' ,
287+ 505 => 'HTTP Version Not Supported '
288+ );
289+
290+ /** @var int */
291+ private $ statusCode ;
292+
293+ /** @var string */
294+ private $ reasonPhrase ;
295+
260296 /**
261297 * @param int $status HTTP status code (e.g. 200/404), see `self::STATUS_*` constants
262298 * @param array<string,string|string[]> $headers additional response headers
@@ -280,12 +316,60 @@ public function __construct(
280316 throw new \InvalidArgumentException ('Invalid response body given ' );
281317 }
282318
283- parent ::__construct (
284- $ status ,
285- $ headers ,
286- $ body ,
287- $ version ,
288- $ reason
289- );
319+ $ this ->protocol = (string ) $ version ;
320+ $ this ->setHeaders ($ headers );
321+ $ this ->stream = $ body ;
322+
323+ $ this ->statusCode = (int ) $ status ;
324+ $ this ->reasonPhrase = ($ reason !== '' && $ reason !== null ) ? (string ) $ reason : self ::getReasonPhraseForStatusCode ($ status );
325+ }
326+
327+ public function getStatusCode ()
328+ {
329+ return $ this ->statusCode ;
330+ }
331+
332+ public function withStatus ($ code , $ reasonPhrase = '' )
333+ {
334+ if ((string ) $ reasonPhrase === '' ) {
335+ $ reasonPhrase = self ::getReasonPhraseForStatusCode ($ code );
336+ }
337+
338+ if ($ this ->statusCode === (int ) $ code && $ this ->reasonPhrase === (string ) $ reasonPhrase ) {
339+ return $ this ;
340+ }
341+
342+ $ response = clone $ this ;
343+ $ response ->statusCode = (int ) $ code ;
344+ $ response ->reasonPhrase = (string ) $ reasonPhrase ;
345+
346+ return $ response ;
347+ }
348+
349+ public function getReasonPhrase ()
350+ {
351+ return $ this ->reasonPhrase ;
352+ }
353+
354+ /**
355+ * @param int $code
356+ * @return string default reason phrase for given status code or empty string if unknown
357+ */
358+ private static function getReasonPhraseForStatusCode ($ code )
359+ {
360+ if (!self ::$ phrasesInitialized ) {
361+ self ::$ phrasesInitialized = true ;
362+
363+ // map all `self::STATUS_` constants from status code to reason phrase
364+ // e.g. `self::STATUS_NOT_FOUND = 404` will be mapped to `404 Not Found`
365+ $ ref = new \ReflectionClass (__CLASS__ );
366+ foreach ($ ref ->getConstants () as $ name => $ value ) {
367+ if (!isset (self ::$ phrasesMap [$ value ]) && \strpos ($ name , 'STATUS_ ' ) === 0 ) {
368+ self ::$ phrasesMap [$ value ] = \ucwords (\strtolower (\str_replace ('_ ' , ' ' , \substr ($ name , 7 ))));
369+ }
370+ }
371+ }
372+
373+ return isset (self ::$ phrasesMap [$ code ]) ? self ::$ phrasesMap [$ code ] : '' ;
290374 }
291375}
0 commit comments