Commit ac74fede by Qiang Xue

Fixes #2910: Added `Application::end()`

parent 33c8f703
......@@ -157,6 +157,7 @@ Yii Framework 2 Change Log
- Enh #2756: Added support for injecting custom `isEmpty` check for all validators (qiangxue)
- Enh #2775: Added `yii\base\Application::bootstrap` and `yii\base\BootstrapInterface` to support running bootstrap classes when starting an application (qiangxue)
- Enh #2892: ActiveRecord dirty attributes are now reset after call to `afterSave()` so information about changed attributes is available in `afterSave`-event (cebe)
- Enh #2910: Added `Application::end()` (qiangxue)
- Enh: Added support for using arrays as option values for console commands (qiangxue)
- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
......
......@@ -60,11 +60,39 @@ abstract class Application extends Module
const EVENT_AFTER_ACTION = 'afterAction';
/**
* Application state used by [[state]]: application just started.
*/
const STATE_BEGIN = 0;
/**
* Application state used by [[state]]: application is initializing.
*/
const STATE_INIT = 1;
/**
* Application state used by [[state]]: application is triggering [[EVENT_BEFORE_REQUEST]].
*/
const STATE_BEFORE_REQUEST = 2;
/**
* Application state used by [[state]]: application is handling the request.
*/
const STATE_HANDLING_REQUEST = 3;
/**
* Application state used by [[state]]: application is triggering [[EVENT_AFTER_REQUEST]]..
*/
const STATE_AFTER_REQUEST = 4;
/**
* Application state used by [[state]]: application is about to send response.
*/
const STATE_SENDING_RESPONSE = 5;
/**
* Application state used by [[state]]: application has ended.
*/
const STATE_END = 6;
/**
* @var string the namespace that controller classes are in. If not set,
* it will use the "app\controllers" namespace.
*/
public $controllerNamespace = 'app\\controllers';
/**
* @var string the application name.
*/
......@@ -144,6 +172,11 @@ abstract class Application extends Module
* it means the application is handling some exception and extra care should be taken.
*/
public $exception;
/**
* @var integer the current application state during a request handling life cycle.
* This property is managed by the application. Do not modify this property.
*/
public $_state;
/**
* @var string Used to reserve memory for fatal error handler.
......@@ -160,10 +193,14 @@ abstract class Application extends Module
{
Yii::$app = $this;
$this->state = self::STATE_BEGIN;
$this->preInit($config);
$this->registerErrorHandlers();
Component::__construct($config);
$this->state = self::STATE_INIT;
}
/**
......@@ -309,11 +346,20 @@ abstract class Application extends Module
*/
public function run()
{
$this->state = self::STATE_BEFORE_REQUEST;
$this->trigger(self::EVENT_BEFORE_REQUEST);
$this->state = self::STATE_HANDLING_REQUEST;
$response = $this->handleRequest($this->getRequest());
$this->state = self::STATE_AFTER_REQUEST;
$this->trigger(self::EVENT_AFTER_REQUEST);
$this->state = self::STATE_SENDING_RESPONSE;
$response->send();
$this->state = self::STATE_END;
return $response->exitStatus;
}
......@@ -460,6 +506,15 @@ abstract class Application extends Module
}
/**
* Returns the response component.
* @return \yii\web\Response|\yii\console\Response the response component
*/
public function getResponse()
{
return $this->get('response');
}
/**
* Returns the view object.
* @return View|\yii\web\View the view object that is used to render various view files.
*/
......@@ -533,6 +588,34 @@ abstract class Application extends Module
}
/**
* Terminates the application.
* This method replaces the `exit()` function by ensuring the application life cycle is completed
* before terminating the application.
* @param integer $status the exit status (value 0 means normal exit while other values mean abnormal exit).
* @param Response $response the response to be sent. If not set, the default application [[response]] component will be used.
* @throws ExitException if the application is in testing mode
*/
public function end($status = 0, $response = null)
{
if ($this->state === self::STATE_BEFORE_REQUEST || $this->state === self::STATE_HANDLING_REQUEST) {
$this->state = self::STATE_AFTER_REQUEST;
$this->trigger(self::EVENT_AFTER_REQUEST);
}
if ($this->state !== self::STATE_SENDING_RESPONSE && $this->state !== self::STATE_END) {
$this->state = self::STATE_END;
$response = $response ? : $this->getResponse();
$response->send();
}
if (YII_ENV_TEST) {
throw new ExitException($status);
} else {
exit($status);
}
}
/**
* Handles uncaught PHP exceptions.
*
* This method is implemented as a PHP exception handler.
......@@ -541,6 +624,10 @@ abstract class Application extends Module
*/
public function handleException($exception)
{
if ($exception instanceof ExitException) {
return;
}
$this->exception = $exception;
// disable error capturing to avoid recursive errors while handling exceptions
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ExitException represents a normal termination of an application.
*
* Do not catch ExitException. Yii will handle this exception to terminate the application gracefully.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ExitException extends Exception
{
/**
* @var integer the exit status code
*/
public $statusCode;
/**
* Constructor.
* @param integer $status the exit status code
* @param string $message error message
* @param integer $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($status = 0, $message = null, $code = 0, \Exception $previous = null)
{
$this->statusCode = $status;
parent::__construct($message, $code, $previous);
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return 'Application Ended';
}
}
......@@ -149,15 +149,6 @@ class Application extends \yii\base\Application
}
/**
* Returns the response component.
* @return Response the response component
*/
public function getResponse()
{
return $this->get('response');
}
/**
* Runs a controller action specified by a route.
* This method parses the specified route and creates the corresponding child module(s), controller and action
* instances. It then calls [[Controller::runAction()]] to run the action with the given parameters.
......
......@@ -124,24 +124,6 @@ class Application extends \yii\base\Application
}
/**
* Returns the request component.
* @return Request the request component
*/
public function getRequest()
{
return $this->get('request');
}
/**
* Returns the response component.
* @return Response the response component
*/
public function getResponse()
{
return $this->get('response');
}
/**
* Returns the session component.
* @return Session the session component
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment