From 0d21ee67cb19d2d71ad44f5e55ea46e4681239c0 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 28 Jan 2013 18:51:36 -0500 Subject: [PATCH] MVC WIP --- framework/base/Action.php | 41 +++++++++++++++++++----- framework/base/Controller.php | 40 +++++------------------ framework/base/InlineAction.php | 31 +++++++++++------- framework/console/Application.php | 25 +-------------- framework/console/Controller.php | 27 ++++++++++++++++ framework/console/controllers/HelpController.php | 2 +- 6 files changed, 90 insertions(+), 76 deletions(-) diff --git a/framework/base/Action.php b/framework/base/Action.php index 1948c9d..6925500 100644 --- a/framework/base/Action.php +++ b/framework/base/Action.php @@ -53,18 +53,43 @@ class Action extends Component * This method is mainly invoked by the controller. * @param array $params action parameters * @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) { - try { - $ps = ReflectionHelper::extractMethodParams($this, 'run', $params); - } catch (Exception $e) { - $this->controller->invalidActionParams($this, $e); - return 1; + if (!method_exists($this, 'run')) { + throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.'); } - if ($params !== $ps) { - $this->controller->extraActionParams($this, $ps, $params); + $method = new \ReflectionMethod($this, 'run'); + $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; } } diff --git a/framework/base/Controller.php b/framework/base/Controller.php index 79ad574..39c829d 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -190,7 +190,7 @@ class Controller extends Component if (method_exists($this, $methodName)) { $method = new \ReflectionMethod($this, $methodName); if ($method->getName() === $methodName) { - return new InlineAction($id, $this); + return new InlineAction($id, $this, $methodName); } } } @@ -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. - * The default implementation will throw an exception. - * @param Action $action the action being executed - * @param Exception $exception the exception about the invalid parameters - * @throws Exception whenever this method is invoked + * Validates the parameter being bound to actions. + * This method is invoked when parameters are being bound to the currently requested action. + * Child classes may override this method to throw exceptions when there are missing and/or unknown parameters. + * @param Action $action the currently requested action + * @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))); } /** diff --git a/framework/base/InlineAction.php b/framework/base/InlineAction.php index 8764ac2..4c509a3 100644 --- a/framework/base/InlineAction.php +++ b/framework/base/InlineAction.php @@ -23,6 +23,23 @@ use yii\util\ReflectionHelper; 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. * This method is mainly invoked by the controller. * @param array $params action parameters @@ -30,16 +47,8 @@ class InlineAction extends Action */ public function runWithParams($params) { - try { - $method = 'action' . $this->id; - $ps = ReflectionHelper::extractMethodParams($this->controller, $method, $params); - } 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); + $method = new \ReflectionMethod($this->controller, $this->actionMethod); + $args = $this->bindActionParams($method, $params); + return (int)$method->invokeArgs($this, $args); } } diff --git a/framework/console/Application.php b/framework/console/Application.php index 23d80e0..1b3192e 100644 --- a/framework/console/Application.php +++ b/framework/console/Application.php @@ -92,36 +92,13 @@ class Application extends \yii\base\Application /** @var $request Request */ $request = $this->getRequest(); if ($request->getIsConsoleRequest()) { - return $this->runController($request->route, $request->params); + return $this->runAction($request->route, $request->params); } else { 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. * @return array the configuration of the built-in commands. */ diff --git a/framework/console/Controller.php b/framework/console/Controller.php index 250cefe..164f631 100644 --- a/framework/console/Controller.php +++ b/framework/console/Controller.php @@ -10,6 +10,7 @@ namespace yii\console; use yii\base\Action; +use yii\base\InvalidRouteException; use yii\base\Exception; /** @@ -30,6 +31,32 @@ use yii\base\Exception; 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. * The default implementation will throw an exception. * @param Action $action the action being executed diff --git a/framework/console/controllers/HelpController.php b/framework/console/controllers/HelpController.php index f4d1eb8..5617c7b 100644 --- a/framework/console/controllers/HelpController.php +++ b/framework/console/controllers/HelpController.php @@ -312,7 +312,7 @@ class HelpController extends Controller { $options = array(); 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; } $name = $property->getName();