diff --git a/flight/Engine.php b/flight/Engine.php
index 2559810..a1378a6 100644
--- a/flight/Engine.php
+++ b/flight/Engine.php
@@ -57,6 +57,8 @@ use flight\net\Route;
* @method void redirect(string $url, int $code = 303) Redirects the current request to another URL.
* @method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSON response.
+ * @method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
+ * Sends a JSON response and immediately halts the request.
* @method void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
* Sends a JSONP response.
*
@@ -73,7 +75,7 @@ class Engine
*/
private const MAPPABLE_METHODS = [
'start', 'stop', 'route', 'halt', 'error', 'notFound',
- 'render', 'redirect', 'etag', 'lastModified', 'json', 'jsonp',
+ 'render', 'redirect', 'etag', 'lastModified', 'json', 'jsonHalt', 'jsonp',
'post', 'put', 'patch', 'delete', 'group', 'getUrl'
];
@@ -608,7 +610,7 @@ class Engine
try {
$this->response()
- ->clear()
+ ->clearBody()
->status(500)
->write($msg)
->send();
@@ -735,7 +737,7 @@ class Engine
public function _halt(int $code = 200, string $message = '', bool $actuallyExit = true): void
{
$this->response()
- ->clear()
+ ->clearBody()
->status($code)
->write($message)
->send();
@@ -750,7 +752,7 @@ class Engine
$output = '
404 Not Found
The page you have requested could not be found.
';
$this->response()
- ->clear()
+ ->clearBody()
->status(404)
->write($output)
->send();
@@ -775,7 +777,7 @@ class Engine
}
$this->response()
- ->clear()
+ ->clearBody()
->status($code)
->header('Location', $url)
->send();
@@ -829,6 +831,33 @@ class Engine
}
}
+ /**
+ * Sends a JSON response and halts execution immediately.
+ *
+ * @param mixed $data JSON data
+ * @param int $code HTTP status code
+ * @param bool $encode Whether to perform JSON encoding
+ * @param string $charset Charset
+ * @param int $option Bitmask Json constant such as JSON_HEX_QUOT
+ *
+ * @throws Exception
+ */
+ public function _jsonHalt(
+ $data,
+ int $code = 200,
+ bool $encode = true,
+ string $charset = 'utf-8',
+ int $option = 0
+ ): void {
+ $this->json($data, $code, $encode, $charset, $option);
+ $jsonBody = $this->response()->getBody();
+ if ($this->response()->v2_output_buffering === false) {
+ $this->response()->clearBody();
+ $this->response()->send();
+ }
+ $this->halt($code, $jsonBody, empty(getenv('PHPUNIT_TEST')));
+ }
+
/**
* Sends a JSONP response.
*
@@ -877,6 +906,7 @@ class Engine
isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
$_SERVER['HTTP_IF_NONE_MATCH'] === $id
) {
+ $this->response()->clear();
$this->halt(304, '', empty(getenv('PHPUNIT_TEST')));
}
}
@@ -894,6 +924,7 @@ class Engine
isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $time
) {
+ $this->response()->clear();
$this->halt(304, '', empty(getenv('PHPUNIT_TEST')));
}
}
diff --git a/flight/Flight.php b/flight/Flight.php
index a04ad80..207d44b 100644
--- a/flight/Flight.php
+++ b/flight/Flight.php
@@ -68,6 +68,8 @@ require_once __DIR__ . '/autoload.php';
* @method static void redirect(string $url, int $code = 303) Redirects to another URL.
* @method static void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* Sends a JSON response.
+ * @method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0)
+ * Sends a JSON response and immediately halts the request.
* @method static void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512)
* Sends a JSONP response.
* @method static void error(Throwable $exception) Sends an HTTP 500 response.
diff --git a/tests/EngineTest.php b/tests/EngineTest.php
index 3c24c88..93f3ff7 100644
--- a/tests/EngineTest.php
+++ b/tests/EngineTest.php
@@ -370,6 +370,16 @@ class EngineTest extends TestCase
$this->assertEquals(200, $engine->response()->status());
}
+ public function testJsonHalt()
+ {
+ $engine = new Engine();
+ $this->expectOutputString('{"key1":"value1","key2":"value2"}');
+ $engine->jsonHalt(['key1' => 'value1', 'key2' => 'value2']);
+ $this->assertEquals('application/json; charset=utf-8', $engine->response()->headers()['Content-Type']);
+ $this->assertEquals(200, $engine->response()->status());
+ $this->assertEquals('{"key1":"value1","key2":"value2"}', $engine->response()->getBody());
+ }
+
public function testJsonP()
{
$engine = new Engine();
diff --git a/tests/RouterTest.php b/tests/RouterTest.php
index 8906168..f0ac765 100644
--- a/tests/RouterTest.php
+++ b/tests/RouterTest.php
@@ -631,6 +631,10 @@ class RouterTest extends TestCase
$this->router->rewind();
$result = $this->router->valid();
$this->assertTrue($result);
+
+ $this->router->previous();
+ $result = $this->router->valid();
+ $this->assertFalse($result);
}
public function testGetRootUrlByAlias()