Commit 0d21ee67 by Qiang Xue

MVC WIP

parent 5855b7c1
...@@ -53,18 +53,43 @@ class Action extends Component ...@@ -53,18 +53,43 @@ class Action extends Component
* This method is mainly invoked by the controller. * This method is mainly invoked by the controller.
* @param array $params action parameters * @param array $params action parameters
* @return integer the exit status (0 means normal, non-zero means abnormal). * @return integer the exit status (0 means normal, non-zero means abnormal).
* @throws InvalidConfigException if the action class does not have a run() method
*/ */
public function runWithParams($params) public function runWithParams($params)
{ {
try { if (!method_exists($this, 'run')) {
$ps = ReflectionHelper::extractMethodParams($this, 'run', $params); throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.');
} catch (Exception $e) {
$this->controller->invalidActionParams($this, $e);
return 1;
} }
if ($params !== $ps) { $method = new \ReflectionMethod($this, 'run');
$this->controller->extraActionParams($this, $ps, $params); $args = $this->bindActionParams($method, $params);
return (int)$method->invokeArgs($this, $args);
}
/**
* Binds the given parameters to the action method.
* The returned array contains the parameters that need to be passed to the action method.
* This method calls [[Controller::validateActionParams()]] to check if any exception
* should be raised if there are missing or unknown parameters.
* @param \ReflectionMethod $method the action method reflection object
* @param array $params the supplied parameters
* @return array the parameters that can be passed to the action method
*/
protected function bindActionParams($method, $params)
{
$args = array();
$missing = array();
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
$args[] = $params[$name];
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
} }
return (int)call_user_func_array(array($this, 'run'), $ps); $this->controller->validateActionParams($this, $missing, $params);
return $args;
} }
} }
...@@ -190,7 +190,7 @@ class Controller extends Component ...@@ -190,7 +190,7 @@ class Controller extends Component
if (method_exists($this, $methodName)) { if (method_exists($this, $methodName)) {
$method = new \ReflectionMethod($this, $methodName); $method = new \ReflectionMethod($this, $methodName);
if ($method->getName() === $methodName) { if ($method->getName() === $methodName) {
return new InlineAction($id, $this); return new InlineAction($id, $this, $methodName);
} }
} }
} }
...@@ -245,39 +245,15 @@ class Controller extends Component ...@@ -245,39 +245,15 @@ class Controller extends Component
} }
/** /**
* This method is invoked when the request parameters do not satisfy the requirement of the specified action. * Validates the parameter being bound to actions.
* The default implementation will throw an exception. * This method is invoked when parameters are being bound to the currently requested action.
* @param Action $action the action being executed * Child classes may override this method to throw exceptions when there are missing and/or unknown parameters.
* @param Exception $exception the exception about the invalid parameters * @param Action $action the currently requested action
* @throws Exception whenever this method is invoked * @param array $missingParams the names of the missing parameters
* @param array $unknownParams the unknown parameters (name=>value)
*/ */
public function invalidActionParams($action, $exception) public function validateActionParams($action, $missingParams, $unknownParams)
{ {
throw $exception;
}
/**
* This method is invoked when extra parameters are provided to an action when it is executed.
* The default implementation does nothing.
* @param Action $action the action being executed
* @param array $expected the expected action parameters (name => value)
* @param array $actual the actual action parameters (name => value)
*/
public function extraActionParams($action, $expected, $actual)
{
}
/**
* Handles the request whose action is not recognized.
* This method is invoked when the controller cannot find the requested action.
* The default implementation simply throws an exception.
* @param string $actionID the missing action name
* @throws InvalidRequestException whenever this method is invoked
*/
public function missingAction($actionID)
{
throw new InvalidRequestException(\Yii::t('yii', 'The system is unable to find the requested action "{action}".',
array('{action}' => $actionID == '' ? $this->defaultAction : $actionID)));
} }
/** /**
......
...@@ -23,6 +23,23 @@ use yii\util\ReflectionHelper; ...@@ -23,6 +23,23 @@ use yii\util\ReflectionHelper;
class InlineAction extends Action class InlineAction extends Action
{ {
/** /**
* @var string the controller method that this inline action is associated with
*/
public $actionMethod;
/**
* @param string $id the ID of this action
* @param Controller $controller the controller that owns this action
* @param string $actionMethod the controller method that this inline action is associated with
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($id, $controller, $actionMethod, $config = array())
{
$this->actionMethod = $actionMethod;
parent::__construct($id, $controller, $config);
}
/**
* Runs this action with the specified parameters. * Runs this action with the specified parameters.
* This method is mainly invoked by the controller. * This method is mainly invoked by the controller.
* @param array $params action parameters * @param array $params action parameters
...@@ -30,16 +47,8 @@ class InlineAction extends Action ...@@ -30,16 +47,8 @@ class InlineAction extends Action
*/ */
public function runWithParams($params) public function runWithParams($params)
{ {
try { $method = new \ReflectionMethod($this->controller, $this->actionMethod);
$method = 'action' . $this->id; $args = $this->bindActionParams($method, $params);
$ps = ReflectionHelper::extractMethodParams($this->controller, $method, $params); return (int)$method->invokeArgs($this, $args);
} catch (Exception $e) {
$this->controller->invalidActionParams($this, $e);
return 1;
}
if ($params !== $ps) {
$this->controller->extraActionParams($this, $ps, $params);
}
return (int)call_user_func_array(array($this->controller, $method), $ps);
} }
} }
...@@ -92,36 +92,13 @@ class Application extends \yii\base\Application ...@@ -92,36 +92,13 @@ class Application extends \yii\base\Application
/** @var $request Request */ /** @var $request Request */
$request = $this->getRequest(); $request = $this->getRequest();
if ($request->getIsConsoleRequest()) { if ($request->getIsConsoleRequest()) {
return $this->runController($request->route, $request->params); return $this->runAction($request->route, $request->params);
} else { } else {
die('This script must be run from the command line.'); die('This script must be run from the command line.');
} }
} }
/** /**
* Runs a controller with the given route and parameters.
* @param string $route the route (e.g. `post/create`)
* @param array $params the parameters to be passed to the controller action
* @return integer the exit status (0 means normal, non-zero values mean abnormal)
* @throws Exception if the route cannot be resolved into a controller
*/
public function runController($route, $params = array())
{
$result = $this->createController($route);
if ($result === false) {
throw new Exception(\Yii::t('yii', 'Unable to resolve the request.'));
}
/** @var $controller \yii\console\Controller */
list($controller, $action) = $result;
$priorController = $this->controller;
$this->controller = $controller;
$params = ReflectionHelper::initObjectWithParams($controller, $params);
$status = $controller->run($action, $params);
$this->controller = $priorController;
return $status;
}
/**
* Returns the configuration of the built-in commands. * Returns the configuration of the built-in commands.
* @return array the configuration of the built-in commands. * @return array the configuration of the built-in commands.
*/ */
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
namespace yii\console; namespace yii\console;
use yii\base\Action; use yii\base\Action;
use yii\base\InvalidRouteException;
use yii\base\Exception; use yii\base\Exception;
/** /**
...@@ -30,6 +31,32 @@ use yii\base\Exception; ...@@ -30,6 +31,32 @@ use yii\base\Exception;
class Controller extends \yii\base\Controller class Controller extends \yii\base\Controller
{ {
/** /**
* Runs an action with the specified action ID and parameters.
* If the action ID is empty, the method will use [[defaultAction]].
* @param string $id the ID of the action to be executed.
* @param array $params the parameters (name-value pairs) to be passed to the action.
* @return integer the status of the action execution. 0 means normal, other values mean abnormal.
* @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully.
* @see createAction
*/
public function runAction($id, $params = array())
{
if ($params !== array()) {
$class = new \ReflectionClass($this);
foreach ($params as $name => $value) {
if ($class->hasProperty($name)) {
$property = $class->getProperty($name);
if ($property->isPublic() && !$property->isStatic() && $property->getDeclaringClass()->getName() === get_class($this)) {
$this->$name = $value;
unset($params[$name]);
}
}
}
}
return parent::runAction($id, $params);
}
/**
* This method is invoked when the request parameters do not satisfy the requirement of the specified action. * This method is invoked when the request parameters do not satisfy the requirement of the specified action.
* The default implementation will throw an exception. * The default implementation will throw an exception.
* @param Action $action the action being executed * @param Action $action the action being executed
......
...@@ -312,7 +312,7 @@ class HelpController extends Controller ...@@ -312,7 +312,7 @@ class HelpController extends Controller
{ {
$options = array(); $options = array();
foreach ($class->getProperties() as $property) { foreach ($class->getProperties() as $property) {
if (!$property->isPublic() || $property->isStatic() || $property->getDeclaringClass()->getName() === 'yii\base\Controller') { if (!$property->isPublic() || $property->isStatic() || $property->getDeclaringClass()->getName() !== get_class($controller)) {
continue; continue;
} }
$name = $property->getName(); $name = $property->getName();
......
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