Commit b138199c by Carsten Brandt

implementation of Response tied to actions

Result of a discussion with @qiangxue - there is not global Yii::$app->response anymore, every action has dedicated response class - implementation allows using HMVC pattern now, nested actions do not interfer
parent 82c978f8
...@@ -41,17 +41,27 @@ class Action extends Component ...@@ -41,17 +41,27 @@ class Action extends Component
* @var Controller the controller that owns this action * @var Controller the controller that owns this action
*/ */
public $controller; public $controller;
/**
* @var Response
*/
private $_response; private $_response;
/**
* @return Response|\yii\console\Response|\yii\web\Response
*/
public function getResponse() public function getResponse()
{ {
if ($this->_response === null) { if ($this->_response === null) {
$this->_response = Yii::$app->createResponse(); // TODO use applications response factory here
//$this->_response = new Response();
} }
return $this->_response; return $this->_response;
} }
/**
* @param Response $response
*/
public function setResponse($response) public function setResponse($response)
{ {
$this->_response = $response; $this->_response = $response;
...@@ -92,8 +102,6 @@ class Action extends Component ...@@ -92,8 +102,6 @@ class Action extends Component
throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.'); throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.');
} }
$args = $this->controller->bindActionParams($this, $params); $args = $this->controller->bindActionParams($this, $params);
$response = $this->getResponse(); return call_user_func_array(array($this, 'run'), $args);
$response->result = call_user_func_array(array($this, 'run'), $args);
return $response;
} }
} }
...@@ -155,8 +155,6 @@ abstract class Application extends Module ...@@ -155,8 +155,6 @@ abstract class Application extends Module
*/ */
abstract public function handleRequest($request); abstract public function handleRequest($request);
public abstract function createResponse();
private $_runtimePath; private $_runtimePath;
/** /**
......
...@@ -110,23 +110,39 @@ class Controller extends Component ...@@ -110,23 +110,39 @@ class Controller extends Component
if ($action !== null) { if ($action !== null) {
$oldAction = $this->action; $oldAction = $this->action;
$this->action = $action; $this->action = $action;
$result = null;
// TODO beforeAction may also create a response somehow.
if ($this->module->beforeAction($action)) { if ($this->module->beforeAction($action)) {
if ($this->beforeAction($action)) { if ($this->beforeAction($action)) {
$result = $action->runWithParams($params); $result = $action->runWithParams($params);
if ($result !== null) {
$this->handleActionResult($result, $action);
}
$this->afterAction($action); $this->afterAction($action);
} }
$this->module->afterAction($action); $this->module->afterAction($action);
} }
$this->action = $oldAction; $this->action = $oldAction;
return $result; return $action->getResponse();
} else { } else {
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id); throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id);
} }
} }
/** /**
* Handles the return value of an action
* @param mixed $result
* @param Action $action
*/
protected abstract function handleActionResult(&$result, $action);
/**
* @return Response the response object of the current action. null if no action is running
*/
public function getResponse()
{
return $this->action !== null ? $this->action->getResponse() : null;
}
/**
* Runs a request specified in terms of a route. * Runs a request specified in terms of a route.
* The route can be either an ID of an action within this controller or a complete route consisting * The route can be either an ID of an action within this controller or a complete route consisting
* of module IDs, controller ID and action ID. If the route starts with a slash '/', the parsing of * of module IDs, controller ID and action ID. If the route starts with a slash '/', the parsing of
......
...@@ -44,8 +44,6 @@ class InlineAction extends Action ...@@ -44,8 +44,6 @@ class InlineAction extends Action
public function runWithParams($params) public function runWithParams($params)
{ {
$args = $this->controller->bindActionParams($this, $params); $args = $this->controller->bindActionParams($this, $params);
$response = $this->getResponse(); return call_user_func_array(array($this->controller, $this->actionMethod), $args);
$response->result = call_user_func_array(array($this->controller, $this->actionMethod), $args);
return $response;
} }
} }
...@@ -571,7 +571,7 @@ abstract class Module extends Component ...@@ -571,7 +571,7 @@ abstract class Module extends Component
* If the route is empty, the method will use [[defaultRoute]]. * If the route is empty, the method will use [[defaultRoute]].
* @param string $route the route that specifies the action. * @param string $route the route that specifies the action.
* @param array $params the parameters to be passed to the action * @param array $params the parameters to be passed to the action
* @return mixed the result of the action. * @return Response the resulting response of the action.
* @throws InvalidRouteException if the requested route cannot be resolved into an action successfully * @throws InvalidRouteException if the requested route cannot be resolved into an action successfully
*/ */
public function runAction($route, $params = array()) public function runAction($route, $params = array())
...@@ -582,9 +582,9 @@ abstract class Module extends Component ...@@ -582,9 +582,9 @@ abstract class Module extends Component
list($controller, $actionID) = $parts; list($controller, $actionID) = $parts;
$oldController = Yii::$app->controller; $oldController = Yii::$app->controller;
Yii::$app->controller = $controller; Yii::$app->controller = $controller;
$result = $controller->runAction($actionID, $params); $response = $controller->runAction($actionID, $params);
Yii::$app->controller = $oldController; Yii::$app->controller = $oldController;
return $result; return $response;
} else { } else {
throw new InvalidRouteException('Unable to resolve the request "' . trim($this->getUniqueId() . '/' . $route, '/') . '".'); throw new InvalidRouteException('Unable to resolve the request "' . trim($this->getUniqueId() . '/' . $route, '/') . '".');
} }
......
...@@ -88,39 +88,13 @@ class Application extends \yii\base\Application ...@@ -88,39 +88,13 @@ class Application extends \yii\base\Application
* Handles the specified request. * Handles the specified request.
* @param Request $request the request to be handled * @param Request $request the request to be handled
* @return Response the resulting response * @return Response the resulting response
* @throws Exception if the route is invalid
*/ */
public function handleRequest($request) public function handleRequest($request)
{ {
list ($route, $params) = $request->resolve(); list ($route, $params) = $request->resolve();
$result = $this->runAction($route, $params);
$response = $this->getResponse();
$response->exitStatus = (int)$result;
return $response;
}
/**
* Returns the response component.
* @return Response the response component
*/
public function createResponse()
{
return new 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.
* If the route is empty, the method will use [[defaultRoute]].
* @param string $route the route that specifies the action.
* @param array $params the parameters to be passed to the action
* @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal.
* @throws Exception if the route is invalid
*/
public function runAction($route, $params = array())
{
try { try {
return parent::runAction($route, $params); return $this->runAction($route, $params);
} catch (InvalidRouteException $e) { } catch (InvalidRouteException $e) {
throw new Exception(\Yii::t('yii', 'Unknown command "{command}".', array('{command}' => $route)), 0, $e); throw new Exception(\Yii::t('yii', 'Unknown command "{command}".', array('{command}' => $route)), 0, $e);
} }
...@@ -152,9 +126,6 @@ class Application extends \yii\base\Application ...@@ -152,9 +126,6 @@ class Application extends \yii\base\Application
'request' => array( 'request' => array(
'class' => 'yii\console\Request', 'class' => 'yii\console\Request',
), ),
'response' => array(
'class' => 'yii\console\Response',
),
)); ));
} }
} }
...@@ -135,6 +135,16 @@ class Controller extends \yii\base\Controller ...@@ -135,6 +135,16 @@ class Controller extends \yii\base\Controller
} }
/** /**
* Handles the return value of an action
* @param mixed $result
* @param Action $action
*/
protected function handleActionResult(&$result, $action)
{
$action->getResponse()->exitStatus = (int)$result;
}
/**
* Formats a string with ANSI codes * Formats a string with ANSI codes
* *
* You may pass additional parameters using the constants defined in [[yii\helpers\base\Console]]. * You may pass additional parameters using the constants defined in [[yii\helpers\base\Console]].
......
...@@ -65,8 +65,7 @@ class Application extends \yii\base\Application ...@@ -65,8 +65,7 @@ class Application extends \yii\base\Application
$params = array_splice($this->catchAll, 1); $params = array_splice($this->catchAll, 1);
} }
try { try {
$response = $this->runAction($route, $params); return $this->runAction($route, $params);
return $response;
} catch (InvalidRouteException $e) { } catch (InvalidRouteException $e) {
throw new HttpException(404, $e->getMessage(), $e->getCode(), $e); throw new HttpException(404, $e->getMessage(), $e->getCode(), $e);
} }
...@@ -108,15 +107,6 @@ class Application extends \yii\base\Application ...@@ -108,15 +107,6 @@ class Application extends \yii\base\Application
} }
/** /**
* Returns the response component.
* @return Response the response component
*/
public function createResponse()
{
return new Response();
}
/**
* Returns the session component. * Returns the session component.
* @return Session the session component * @return Session the session component
*/ */
...@@ -154,9 +144,6 @@ class Application extends \yii\base\Application ...@@ -154,9 +144,6 @@ class Application extends \yii\base\Application
'request' => array( 'request' => array(
'class' => 'yii\web\Request', 'class' => 'yii\web\Request',
), ),
'response' => array(
'class' => 'yii\web\Response',
),
'session' => array( 'session' => array(
'class' => 'yii\web\Session', 'class' => 'yii\web\Session',
), ),
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace yii\web; namespace yii\web;
use Yii; use Yii;
use yii\base\Action;
use yii\base\InlineAction; use yii\base\InlineAction;
/** /**
...@@ -62,6 +63,16 @@ class Controller extends \yii\base\Controller ...@@ -62,6 +63,16 @@ class Controller extends \yii\base\Controller
} }
/** /**
* Handles the return value of an action
* @param mixed $result
* @param Action $action
*/
protected function handleActionResult(&$result, $action)
{
$action->getResponse()->setContent($result);
}
/**
* Creates a URL using the given route and parameters. * Creates a URL using the given route and parameters.
* *
* This method enhances [[UrlManager::createUrl()]] by supporting relative routes. * This method enhances [[UrlManager::createUrl()]] by supporting relative routes.
......
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