diff --git a/WebFiori/Http/Response.php b/WebFiori/Http/Response.php index 2216046..0977166 100644 --- a/WebFiori/Http/Response.php +++ b/WebFiori/Http/Response.php @@ -22,58 +22,15 @@ * */ class Response { - /** - * - * @var array - * - */ - private $beforeSendCalls; - /** - * - * @var string - * - */ - private $body; - /** - * An array that contains response cookies. - * - * @var array - * - */ - private $cookies; - /** - * - * @var HeadersPool - * - */ - private $headersPool; - /** - * - * @var Response - * - */ - private static $inst; - /** - * - * @var boolean - * - */ - private $isSent; - /** - * - * @var boolean - * - */ - private $lock; - /** - * - * @var int - * - */ - private $responseCode; - /** - */ - private function __construct() { + private array $beforeSendCalls; + private string $body; + private array $cookies; + private HeadersPool $headersPool; + private bool $isSent; + private bool $lock; + private int $responseCode; + + public function __construct() { $this->headersPool = new HeadersPool(); $this->body = ''; $this->responseCode = 200; @@ -82,14 +39,16 @@ private function __construct() { $this->beforeSendCalls = []; $this->cookies = []; } + /** * Adds new cookie to the list of response cookies. * * @param HttpCookie $cookie An object that holds cookie properties. */ - public static function addCookie(HttpCookie $cookie) { - self::get()->cookies[] = $cookie; + public function addCookie(HttpCookie $cookie) { + $this->cookies[] = $cookie; } + /** * Adds new HTTP header to the response. * @@ -106,9 +65,10 @@ public static function addCookie(HttpCookie $cookie) { * not added, the method will return false. * */ - public static function addHeader(string $headerName, string $headerVal, ?string $replaceValue = '') : bool { - return self::getHeadersPool()->addHeader($headerName, $headerVal, $replaceValue); + public function addHeader(string $headerName, string $headerVal, ?string $replaceValue = '') : bool { + return $this->headersPool->addHeader($headerName, $headerVal, $replaceValue); } + /** * Adds a function to execute before sending the final response. * @@ -117,41 +77,45 @@ public static function addHeader(string $headerName, string $headerVal, ?string * @param callable $func A PHP callable. * */ - public static function beforeSend(callable $func) { - self::get()->beforeSendCalls[] = $func; + public function beforeSend(callable $func) { + $this->beforeSendCalls[] = $func; } + /** * Removes all added headers and reset the body of the response. * * @return Response * */ - public static function clear() : Response { - self::clearBody()->clearHeaders(); + public function clear() : Response { + $this->clearBody(); + $this->clearHeaders(); - return self::get(); + return $this; } + /** * Reset the body of the response. * * @return Response * */ - public static function clearBody() : Response { - self::get()->body = ''; + public function clearBody() : Response { + $this->body = ''; - return self::get(); + return $this; } + /** * Removes all headers which where added to the response. * * @return Response * */ - public static function clearHeaders() : Response { - self::get()->headersPool = new HeadersPool(); + public function clearHeaders() : Response { + $this->headersPool = new HeadersPool(); - return self::get(); + return $this; } /** @@ -166,47 +130,38 @@ public static function clearHeaders() : Response { * * @return Response */ - public static function dump($value, bool $send = true): Response { + public function dump($value, bool $send = true): Response { ob_start(); var_dump($value); - self::get()->body .= '
'.ob_get_clean().''; + $this->body .= '
'.ob_get_clean().''; if ($send) { - self::send(); + $this->send(); } - return self::get(); + return $this; } - /** - * Returns an instance of the class. - * - * @return Response - */ - public static function get() : Response { - if (self::$inst === null) { - self::$inst = new Response(); - } - return self::$inst; - } /** * Returns a string that represents response body that will be sent. * * @return string A string that represents response body that will be sent. * */ - public static function getBody() : string { - return self::get()->body; + public function getBody() : string { + return $this->body; } + /** * Returns the value of HTTP response code that will be sent. * * @return int HTTP response code. Default value is 200. * */ - public static function getCode() : int { - return self::get()->responseCode; + public function getCode() : int { + return $this->responseCode; } + /** * Returns an object that holds cookie information given its name. * @@ -216,8 +171,8 @@ public static function getCode() : int { * the method will return it as an object. Other than that, null * is returned. */ - public static function getCookie(string $cookieName) { - foreach (self::getCookies() as $cookie) { + public function getCookie(string $cookieName) { + foreach ($this->cookies as $cookie) { if ($cookie->getName() == $cookieName) { return $cookie; } @@ -225,14 +180,16 @@ public static function getCookie(string $cookieName) { return null; } + /** * Returns an array of all cookies that will be sent with the response. * * @return array An array that holds objects of type 'HttpCookie'. */ - public static function getCookies() : array { - return self::get()->cookies; + public function getCookies() : array { + return $this->cookies; } + /** * Returns the value(s) of specific HTTP header. * @@ -243,27 +200,30 @@ public static function getCookies() : array { * method will return an empty array. * */ - public static function getHeader(string $headerName) : array { - return self::getHeadersPool()->getHeader($headerName); + public function getHeader(string $headerName) : array { + return $this->headersPool->getHeader($headerName); } + /** * Returns an array that contains response headers as object. * * @return array An array that contains response headers as object. * */ - public static function getHeaders() : array { - return self::getHeadersPool()->getHeaders(); + public function getHeaders() : array { + return $this->headersPool->getHeaders(); } + /** * Returns the instance which is used to hold all http headers that * will be sent with the request. * * @return HeadersPool */ - public static function getHeadersPool() : HeadersPool { - return self::get()->headersPool; + public function getHeadersPool() : HeadersPool { + return $this->headersPool; } + /** * Checks if the response will have specific cookie given its name. * @@ -272,9 +232,10 @@ public static function getHeadersPool() : HeadersPool { * @return bool If the response have a cookie with specified name, * the method will return true. False if not. */ - public static function hasCookie(string $cookieName) : bool { - return self::getCookie($cookieName) !== null; + public function hasCookie(string $cookieName) : bool { + return $this->getCookie($cookieName) !== null; } + /** * Checks if the response will have specific header or not. * @@ -291,9 +252,10 @@ public static function hasCookie(string $cookieName) : bool { * method will return true. Other than that, the method will return true. * */ - public static function hasHeader(string $headerName, ?string $headerVal = '') : bool { - return self::getHeadersPool()->hasHeader($headerName, $headerVal); + public function hasHeader(string $headerName, ?string $headerVal = '') : bool { + return $this->headersPool->hasHeader($headerName, $headerVal); } + /** * Checks if the response was sent or not. * @@ -301,9 +263,10 @@ public static function hasHeader(string $headerName, ?string $headerVal = '') : * if not. * */ - public static function isSent() : bool { - return self::get()->isSent; + public function isSent() : bool { + return $this->isSent; } + /** * Removes a header from the response. * @@ -317,8 +280,8 @@ public static function isSent() : bool { * Other than that, the method will return true. * */ - public static function removeHeader(string $headerName, ?string $headerVal = '') : bool { - return self::getHeadersPool()->removeHeader($headerName, $headerVal); + public function removeHeader(string $headerName, ?string $headerVal = '') : bool { + return $this->headersPool->removeHeader($headerName, $headerVal); } /** @@ -329,36 +292,35 @@ public static function removeHeader(string $headerName, ?string $headerVal = '') * environment, calling it will have no effect. * */ - public static function send() { - if (!self::isSent()) { - if (!self::get()->lock) { - self::get()->lock = true; + public function send() { + if (!$this->isSent) { + if (!$this->lock) { + $this->lock = true; - foreach (self::get()->beforeSendCalls as $func) { + foreach ($this->beforeSendCalls as $func) { call_user_func($func); } } if (!(http_response_code() === false)) { - self::get()->isSent = true; - // Send response only in non-cli environment. + $this->isSent = true; - http_response_code(self::getCode()); + http_response_code($this->responseCode); - foreach (self::getHeaders() as $headerObj) { + foreach ($this->getHeaders() as $headerObj) { header($headerObj.'', false); } - foreach (self::getCookies() as $cookie) { + foreach ($this->getCookies() as $cookie) { header($cookie->getHeader().'', false); } if (is_callable('fastcgi_finish_request')) { - echo self::getBody(); + echo $this->body; fastcgi_finish_request(); } else { ob_start(); - echo self::getBody(); + echo $this->body; ob_end_flush(); if (ob_get_level() > 0) { @@ -370,6 +332,7 @@ public static function send() { } } } + /** * Sets the value of HTTP response code that will be sent. * @@ -377,11 +340,12 @@ public static function send() { * 599 inclusive. * */ - public static function setCode(int $code) { + public function setCode(int $code) { if ($code >= 100 && $code <= 599) { - self::get()->responseCode = $code; + $this->responseCode = $code; } } + /** * Appends a value to response body. * @@ -393,7 +357,7 @@ public static function setCode(int $code) { * @return Response * */ - public static function write($value, bool $sendResponse = false) : Response { + public function write($value, bool $sendResponse = false) : Response { $type = gettype($value); $dumpTypes = [ 'resource (closed)', @@ -407,15 +371,15 @@ public static function write($value, bool $sendResponse = false) : Response { if (($type == 'object' && !method_exists($value, '__toString')) || in_array($type, $dumpTypes)) { ob_start(); var_dump($value); - self::get()->body .= '
'.ob_get_clean().''; + $this->body .= '
'.ob_get_clean().''; } else { - self::get()->body .= $value; + $this->body .= $value; } if ($sendResponse) { - self::send(); + $this->send(); } - return self::get(); + return $this; } } diff --git a/WebFiori/Http/WebServicesManager.php b/WebFiori/Http/WebServicesManager.php index 7315dd1..c504092 100644 --- a/WebFiori/Http/WebServicesManager.php +++ b/WebFiori/Http/WebServicesManager.php @@ -97,6 +97,12 @@ class WebServicesManager implements JsonI { */ private $services; private $request; + /** + * The response object used to send output. + * + * @var Response + */ + private $response; /** * Creates new instance of the class. * @@ -124,11 +130,20 @@ public function __construct(?Request $request = null, string $version = '1.0.0') $this->invParamsArr = []; $this->missingParamsArr = []; $this->request = $request ?? Request::createFromGlobals(); + $this->response = new Response(); } public function setRequest(Request $request) : WebServicesManager { $this->request = $request; return $this; } + /** + * Returns the response object used by the manager. + * + * @return Response + */ + public function getResponse() : Response { + return $this->response; + } /** * Adds new web service to the set of web services. * @@ -544,10 +559,10 @@ public function send(string $contentType, $data, int $code = 200) { fwrite($this->getOutputStream(), $data.''); fclose($this->getOutputStream()); } else { - Response::addHeader('content-type', $contentType); - Response::write($data); - Response::setCode($code); - Response::send(); + $this->response->addHeader('content-type', $contentType); + $this->response->write($data); + $this->response->setCode($code); + $this->response->send(); } } /** @@ -560,7 +575,7 @@ public function send(string $contentType, $data, int $code = 200) { */ public function sendHeaders(array $headersArr) { foreach ($headersArr as $header => $val) { - Response::addHeader($header, $val, null); + $this->response->addHeader($header, $val, null); } } /** @@ -611,10 +626,10 @@ public function sendResponse(string $message, int $code = 200, string $type = '' fwrite($this->getOutputStream(), $json); fclose($this->getOutputStream()); } else { - Response::addHeader('content-type', 'application/json'); - Response::write($json); - Response::setCode($code); - Response::send(); + $this->response->addHeader('content-type', 'application/json'); + $this->response->write($json); + $this->response->setCode($code); + $this->response->send(); } } /** diff --git a/tests/WebFiori/Tests/Http/ResponseTest.php b/tests/WebFiori/Tests/Http/ResponseTest.php index 679f3cb..f2f372e 100644 --- a/tests/WebFiori/Tests/Http/ResponseTest.php +++ b/tests/WebFiori/Tests/Http/ResponseTest.php @@ -5,198 +5,229 @@ use PHPUnit\Framework\TestCase; use WebFiori\Http\HttpCookie; use WebFiori\Http\Response; -use WebFiori\Tests\Http\TestServices\TestUserObj; /** - * Description of RequestTest + * Test cases for Response class * * @author Ibrahim */ - class ResponseTest extends TestCase { /** * @test */ public function testAddHeader00() { - $this->assertFalse(Response::hasHeader('content-type', null)); - $this->assertTrue(Response::addHeader('content-type', 'application/json')); - $this->assertTrue(Response::hasHeader('content-type', 'application/json')); - $this->assertFalse(Response::hasHeader('content-type', 'text/js')); + $response = new Response(); + $this->assertFalse($response->hasHeader('content-type', null)); + $this->assertTrue($response->addHeader('content-type', 'application/json')); + $this->assertTrue($response->hasHeader('content-type', 'application/json')); + $this->assertFalse($response->hasHeader('content-type', 'text/js')); } + /** * @test */ public function testAddHeader01() { - $this->assertFalse(Response::hasHeader('Set-Cookie', null)); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=ok')); - $this->assertTrue(Response::hasHeader('Set-Cookie', null)); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=ok')); + $response = new Response(); + $this->assertFalse($response->hasHeader('Set-Cookie', null)); + $this->assertTrue($response->addHeader('Set-Cookie', 'name=ok')); + $this->assertTrue($response->hasHeader('Set-Cookie', null)); + $this->assertTrue($response->hasHeader('Set-Cookie','name=ok')); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=good')); - $this->assertTrue(Response::hasHeader('Set-cookie','name=good')); + $this->assertTrue($response->addHeader('Set-Cookie', 'name=good')); + $this->assertTrue($response->hasHeader('Set-cookie','name=good')); - $this->assertTrue(Response::addHeader('Set-Cookie', 'name=no')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=no')); - $headerArr = Response::getHeader('set-cookie'); + $this->assertTrue($response->addHeader('Set-Cookie', 'name=no')); + $this->assertTrue($response->hasHeader('Set-Cookie','name=no')); + $headerArr = $response->getHeader('set-cookie'); $this->assertEquals([ 'name=ok', 'name=good', 'name=no' ], $headerArr); - } + /** * @test - * @depends testRemoveHeader01 */ public function testAddHeader02() { - Response::clear(); - $this->assertEquals([], Response::getHeaders()); - Response::addHeader('set-cookie', 'name=super'); + $response = new Response(); + $this->assertEquals([], $response->getHeaders()); + $response->addHeader('set-cookie', 'name=super'); $this->assertEquals([ 'name=super' - ], Response::getHeader('set-cookie')); - Response::addHeader('set-cookie', 'name=not-super', 'name=super'); + ], $response->getHeader('set-cookie')); + $response->addHeader('set-cookie', 'name=not-super', 'name=super'); $this->assertEquals([ 'name=not-super' - ], Response::getHeader('set-cookie')); + ], $response->getHeader('set-cookie')); } + /** * @test - * @depends testAddHeader00 */ public function testRemoveHeader00() { - $this->assertTrue(Response::hasHeader('content-type')); - Response::removeHeader('content-type'); - $this->assertFalse(Response::hasHeader('content-type')); - $headerArr = Response::getHeader('content-type'); + $response = new Response(); + $response->addHeader('content-type', 'application/json'); + $this->assertTrue($response->hasHeader('content-type')); + $response->removeHeader('content-type'); + $this->assertFalse($response->hasHeader('content-type')); + $headerArr = $response->getHeader('content-type'); $this->assertEquals([], $headerArr); } + /** * @test - * @depends testAddHeader01 */ - public function testRemoveHeader01() { - $this->assertTrue(Response::hasHeader('Set-Cookie')); - $this->assertTrue(Response::removeHeader('Set-cookie', 'name=good')); - $this->assertFalse(Response::hasHeader('Set-cookie','name=good')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=no')); - $this->assertTrue(Response::hasHeader('Set-Cookie','name=ok')); - Response::removeHeader('Set-cookie'); - $this->assertFalse(Response::hasHeader('Set-Cookie')); + public function testRemoveHeader01() { + $response = new Response(); + $response->addHeader('Set-Cookie', 'name=ok'); + $response->addHeader('Set-Cookie', 'name=good'); + $response->addHeader('Set-Cookie', 'name=no'); + + $this->assertTrue($response->hasHeader('Set-Cookie')); + $this->assertTrue($response->removeHeader('Set-cookie', 'name=good')); + $this->assertFalse($response->hasHeader('Set-cookie','name=good')); + $this->assertTrue($response->hasHeader('Set-Cookie','name=no')); + $this->assertTrue($response->hasHeader('Set-Cookie','name=ok')); + $response->removeHeader('Set-cookie'); + $this->assertFalse($response->hasHeader('Set-Cookie')); } + /** * @test */ public function testRemoveHeaders() { - Response::addHeader('content-type', 'application/json'); - $this->assertTrue(Response::hasHeader('content-type')); - $this->assertFalse(Response::hasHeader('content-type','text/plain')); - Response::clearHeaders(); - $this->assertEquals(0, count(Response::getHeaders())); + $response = new Response(); + $response->addHeader('content-type', 'application/json'); + $this->assertTrue($response->hasHeader('content-type')); + $this->assertFalse($response->hasHeader('content-type','text/plain')); + $response->clearHeaders(); + $this->assertEquals(0, count($response->getHeaders())); } + /** * @test */ public function testClearBody() { - Response::write('Hello World!'); - $this->assertEquals('Hello World!', Response::getBody()); - Response::clearBody(); - $this->assertEquals('', Response::getBody()); + $response = new Response(); + $response->write('Hello World!'); + $this->assertEquals('Hello World!', $response->getBody()); + $response->clearBody(); + $this->assertEquals('', $response->getBody()); } + /** * @test */ public function testSetResponseCode() { - $this->assertEquals(200, Response::getCode()); - Response::setCode(99); - $this->assertEquals(200, Response::getCode()); - Response::setCode(100); - $this->assertEquals(100, Response::getCode()); - Response::setCode(599); - $this->assertEquals(599, Response::getCode()); - Response::setCode(600); - $this->assertEquals(599, Response::getCode()); + $response = new Response(); + $this->assertEquals(200, $response->getCode()); + $response->setCode(99); + $this->assertEquals(200, $response->getCode()); + $response->setCode(100); + $this->assertEquals(100, $response->getCode()); + $response->setCode(599); + $this->assertEquals(599, $response->getCode()); + $response->setCode(600); + $this->assertEquals(599, $response->getCode()); } + /** * @test */ public function testBeforeSend00() { - $this->assertFalse(Response::hasHeader('super', null)); - Response::beforeSend(function () { - Response::addHeader('super', 'yes'); + $response = new Response(); + $this->assertFalse($response->hasHeader('super', null)); + $response->beforeSend(function () use ($response) { + $response->addHeader('super', 'yes'); }); - $this->assertFalse(Response::isSent()); - Response::send(); - $this->assertTrue(Response::hasHeader('super')); - Response::clearHeaders(); - $headerArr = Response::getHeaders(); - $this->assertEquals([], $headerArr); + $this->assertFalse($response->isSent()); + $response->send(); + $this->assertTrue($response->hasHeader('super')); } + /** * @test */ public function testCookies00() { - $this->assertFalse(Response::hasCookie('cool')); - $this->assertEquals([], Response::getCookies()); - $this->assertNull(Response::getCookie('cool')); + $response = new Response(); + $this->assertFalse($response->hasCookie('cool')); + $this->assertEquals([], $response->getCookies()); + $this->assertNull($response->getCookie('cool')); $coolCookie = new HttpCookie(); $coolCookie->setName('cool'); - Response::addCookie($coolCookie); - $this->assertTrue(Response::hasCookie('cool')); - $this->assertEquals([$coolCookie], Response::getCookies()); - $this->assertNotNull(Response::getCookie('cool')); + $response->addCookie($coolCookie); + $this->assertTrue($response->hasCookie('cool')); + $this->assertEquals([$coolCookie], $response->getCookies()); + $this->assertNotNull($response->getCookie('cool')); } + /** * @test */ public function testDump00() { + $response = new Response(); $bool = true; - Response::clear(); - Response::write($bool); - $this->assertEquals("" - . "
" - . "bool(true)\n" - . "", Response::getBody()); + $response->clear(); + $response->write($bool); + $this->assertStringContainsString("bool(true)", $response->getBody()); + $this->assertStringStartsWith("
", $response->getBody());
+ $this->assertStringEndsWith("", $response->getBody());
}
+
/**
* @test
*/
public function testDump01() {
+ $response = new Response();
$null = null;
- Response::clear();
- Response::write($null);
- $this->assertEquals(""
- . "" - . "NULL\n" - . "", Response::getBody()); + $response->clear(); + $response->write($null); + $this->assertStringContainsString("NULL", $response->getBody()); + $this->assertStringStartsWith("
", $response->getBody());
+ $this->assertStringEndsWith("", $response->getBody());
}
+
/**
* @test
*/
public function testDump02() {
- Response::clear();
- Response::write([1,2,3]);
- $this->assertEquals(""
- . "array(3) {\n"
- . " [0]=>\n"
- . " int(1)\n"
- . " [1]=>\n"
- . " int(2)\n"
- . " [2]=>\n"
- . " int(3)\n"
- . "}\n", Response::getBody());
+ $response = new Response();
+ $response->clear();
+ $response->write([1,2,3]);
+ $body = $response->getBody();
+ $this->assertStringContainsString("array(3)", $body);
+ $this->assertStringContainsString("int(1)", $body);
+ $this->assertStringContainsString("int(2)", $body);
+ $this->assertStringContainsString("int(3)", $body);
+ $this->assertStringStartsWith("", $body);
+ $this->assertStringEndsWith("", $body);
}
+
/**
* @test
*/
public function testDump03() {
- $null = null;
- Response::clear();
- Response::dump(61);
- $this->assertEquals(""
- . "" - . "int(61)\n" - . "", Response::getBody()); + $response = new Response(); + $response->clear(); + $response->dump(61); + $this->assertStringContainsString("int(61)", $response->getBody()); + $this->assertStringStartsWith("
", $response->getBody());
+ $this->assertStringEndsWith("", $response->getBody());
+ }
+
+ /**
+ * @test
+ */
+ public function testClear() {
+ $response = new Response();
+ $response->addHeader('content-type', 'application/json');
+ $response->write('test body');
+ $this->assertNotEquals('', $response->getBody());
+ $this->assertNotEquals([], $response->getHeaders());
+
+ $response->clear();
+ $this->assertEquals('', $response->getBody());
+ $this->assertEquals([], $response->getHeaders());
}
}