From 5a72523a14ada6d575a1422a85f770fbbf036fec Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 12 May 2012 00:28:23 -0400 Subject: [PATCH] console commands. --- framework/base/Action.php | 46 ++++----------- framework/base/Application.php | 4 +- framework/base/Controller.php | 115 ++++++++++++++++-------------------- framework/base/InlineAction.php | 18 +++--- framework/console/Application.php | 6 -- framework/util/ReflectionHelper.php | 64 ++++++++++++++++++++ framework/util/StringHelper.php | 4 +- framework/yiic.php | 3 + 8 files changed, 141 insertions(+), 119 deletions(-) create mode 100644 framework/util/ReflectionHelper.php diff --git a/framework/base/Action.php b/framework/base/Action.php index ac423eb..59561ee 100644 --- a/framework/base/Action.php +++ b/framework/base/Action.php @@ -45,44 +45,20 @@ class Action extends Component } /** - * Normalizes the input parameters for the action. - * The parameters will later be passed to the `run()` method of the action. - * This method is mainly called by the controller when running an action. - * @param array $params the input parameters in terms of name-value pairs. - * @return array|boolean the normalized parameters, or false if the input parameters are invalid. + * Runs this action with the specified parameters. + * 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). */ - public function normalizeParams($params) + public function runWithParams($params) { $method = new \ReflectionMethod($this, 'run'); - return $this->normalizeParamsByMethod($method, $params); - } - - /** - * Extracts the input parameters according to the specified method signature. - * @param \ReflectionMethod $method the method reflection - * @param array $params the parameters in name-value pairs - * @return array|boolean the extracted parameters in the order as declared in the "run()" method. - * False is returned if the input parameters do not follow the method declaration. - */ - protected function normalizeParamsByMethod($method, $params) - { - $ps = array(); - foreach ($method->getParameters() as $param) { - $name = $param->getName(); - if (isset($params[$name])) { - if ($param->isArray()) { - $ps[] = is_array($params[$name]) ? $params[$name] : array($params[$name]); - } elseif (!is_array($params[$name])) { - $ps[] = $params[$name]; - } else { - return false; - } - } elseif ($param->isDefaultValueAvailable()) { - $ps[] = $param->getDefaultValue(); - } else { - return false; - } + $params = \yii\util\ReflectionHelper::bindParams($method, $params); + if ($params === false) { + $this->controller->invalidActionParams($this); + return 1; + } else { + return (int)$method->invokeArgs($this, $params); } - return false; } } diff --git a/framework/base/Application.php b/framework/base/Application.php index e3fa808..13e4086 100644 --- a/framework/base/Application.php +++ b/framework/base/Application.php @@ -187,10 +187,10 @@ abstract class Application extends Module throw new Exception(\Yii::t('yii', 'Unable to resolve the request.')); } list($controller, $action) = $result; - $oldController = $this->controller; + $priorController = $this->controller; $this->controller = $controller; $status = $controller->run($action, $params); - $this->controller = $oldController; + $this->controller = $priorController; return $status; } diff --git a/framework/base/Controller.php b/framework/base/Controller.php index c94c84f..61ae94c 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -42,6 +42,30 @@ class Controller extends Component implements Initable */ public $defaultAction = 'index'; /** + * @var array mapping from action ID to action configuration. + * Array keys are action IDs, and array values are the corresponding + * action class names or action configuration arrays. For example, + * + * ~~~ + * return array( + * 'action1' => '@application/components/Action1', + * 'action2' => array( + * 'class' => '@application/components/Action2', + * 'property1' => 'value1', + * 'property2' => 'value2', + * ), + * ); + * ~~~ + * + * [[\Yii::createObject()]] will be invoked to create the requested action + * using the configuration provided here. + * + * Note, in order to inherit actions defined in the parent class, a child class needs to + * merge the parent actions with child actions using functions like `array_merge()`. + * @see createAction + */ + public $actions = array(); + /** * @var Action the action that is currently being executed */ public $action; @@ -66,45 +90,11 @@ class Controller extends Component implements Initable } /** - * Returns a list of external action classes. - * Array keys are action IDs, and array values are the corresponding - * action class names or action configuration arrays. For example, - * - * ~~~ - * return array( - * 'action1'=>'@application/components/Action1', - * 'action2'=>array( - * 'class'=>'@application/components/Action2', - * 'property1'=>'value1', - * 'property2'=>'value2', - * ), - * ); - * ~~~ - * - * [[\Yii::createObject()]] will be invoked to create the requested action - * using the configuration provided here. - * - * Derived classes may override this method to declare external actions. - * - * Note, in order to inherit actions defined in the parent class, a child class needs to - * merge the parent actions with child actions using functions like `array_merge()`. - * - * @return array list of external action classes - * @see createAction - */ - public function actions() - { - return array(); - } - - /** * Runs the controller with the specified action and parameters. * @param Action|string $action the action to be executed. This can be either an action object * or the ID of the action. - * @param array $params the parameters to be passed to the action. + * @param array $params the parameters (name-value pairs) to be passed to the action. * If null, the result of [[getActionParams()]] will be used as action parameters. - * Note that the parameters must be name-value pairs with the names corresponding to - * the parameter names as declared by the action. * @return integer the exit status of the action. 0 means normal, other values mean abnormal. * @see missingAction * @see createAction @@ -122,32 +112,17 @@ class Controller extends Component implements Initable $priorAction = $this->action; $this->action = $action; - $exitStatus = 1; - if ($this->authorize($action)) { - $params = $action->normalizeParams($params === null ? $this->getActionParams() : $params); - if ($params !== false) { - if ($this->beforeAction($action)) { - $exitStatus = (int)call_user_func_array(array($action, 'run'), $params); - $this->afterAction($action); - } - } else { - $this->invalidActionParams($action); - } + + if ($this->authorize($action) && $this->beforeAction($action)) { + $status = $action->runWithParams($params !== null ?: $this->getActionParams()); + $this->afterAction($action); + } else { + $status = 1; } + $this->action = $priorAction; - return $exitStatus; - } - /** - * Returns the request parameters that will be used for action parameter binding. - * Default implementation simply returns an empty array. - * Child classes may override this method to customize the parameters to be provided - * for action parameter binding (e.g. `$_GET`). - * @return array the request parameters (name-value pairs) to be used for action parameter binding - */ - public function getActionParams() - { - return array(); + return $status; } /** @@ -163,15 +138,25 @@ class Controller extends Component implements Initable if ($actionID === '') { $actionID = $this->defaultAction; } - if (method_exists($this, 'action' . $actionID) && strcasecmp($actionID, 's')) { + if (isset($this->actions[$actionID])) { + return \Yii::createObject($this->actions[$actionID], $actionID, $this); + } elseif (method_exists($this, 'action' . $actionID)) { return new InlineAction($actionID, $this); } else { - $actions = $this->actions(); - if (isset($actions[$actionID])) { - return \Yii::createObject($actions[$actionID], $actionID, $this); - } + return null; } - return null; + } + + /** + * Returns the request parameters that will be used for action parameter binding. + * Default implementation simply returns an empty array. + * Child classes may override this method to customize the parameters to be provided + * for action parameter binding (e.g. `$_GET`). + * @return array the request parameters (name-value pairs) to be used for action parameter binding + */ + public function getActionParams() + { + return array(); } /** @@ -234,7 +219,7 @@ class Controller extends Component implements Initable if ($route[0] !== '/' && !$this->module instanceof Application) { $route = '/' . $this->module->getUniqueId() . '/' . $route; } - $status = \Yii::$application->dispatch($route, $params); + $status = \Yii::$application->processRequest($route, $params); } if ($exit) { \Yii::$application->end($status); diff --git a/framework/base/InlineAction.php b/framework/base/InlineAction.php index 2bc8e96..f162aca 100644 --- a/framework/base/InlineAction.php +++ b/framework/base/InlineAction.php @@ -21,20 +21,20 @@ namespace yii\base; class InlineAction extends Action { /** - * Runs the action with the supplied parameters. - * This method is invoked by the controller. - * @param array $params the input parameters in terms of name-value pairs. - * @return boolean whether the input parameters are valid + * Runs this action with the specified parameters. + * 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). */ public function runWithParams($params) { $method = new \ReflectionMethod($this->controller, 'action' . $this->id); - $params = $this->normalizeParamsByMethod($method, $params); - if ($params !== false) { - call_user_func_array(array($this->controller, 'action' . $this->id), $params); - return true; + $params = \yii\util\ReflectionHelper::bindParams($method, $params); + if ($params === false) { + $this->controller->invalidActionParams($this); + return 1; } else { - return false; + return (int)$method->invokeArgs($this, $params); } } } diff --git a/framework/console/Application.php b/framework/console/Application.php index 8dcc476..345a5be 100644 --- a/framework/console/Application.php +++ b/framework/console/Application.php @@ -11,9 +11,6 @@ namespace yii\console; use yii\base\Exception; -// fcgi doesn't have STDIN defined by default -defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); - /** * Application represents a console application. * @@ -41,9 +38,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); * yiic help * ~~~ * - * @property string $commandPath The directory that contains the command classes. Defaults to 'protected/commands'. - * @property CommandRunner $commandRunner The command runner. - * * @author Qiang Xue * @since 2.0 */ diff --git a/framework/util/ReflectionHelper.php b/framework/util/ReflectionHelper.php new file mode 100644 index 0000000..b0d0231 --- /dev/null +++ b/framework/util/ReflectionHelper.php @@ -0,0 +1,64 @@ + + * @since 2.0 + */ +class ReflectionHelper +{ + /** + * Prepares parameters so that they can be bound to the specified method. + * This method mainly helps method parameter binding. It converts `$params` + * into an array which can be passed to `call_user_func_array()` when calling + * the specified method. The conversion is based on the matching of method parameter names + * and the input array keys. For example, + * + * ~~~ + * class Foo { + * function bar($a, $b) { ... } + * } + * + * $method = new \ReflectionMethod('Foo', 'bar'); + * $params = array('b' => 2, 'c' => 3, 'a' => 1); + * var_export(ReflectionHelper::bindMethodParams($method, $params)); + * // would output: array('a' => 1, 'b' => 2) + * ~~~ + * + * @param \ReflectionMethod $method the method reflection + * @param array $params the parameters in terms of name-value pairs + * @return array|boolean the parameters that can be passed to the method via `call_user_func_array()`. + * False is returned if the input parameters do not follow the method declaration. + */ + public static function bindParams($method, $params) + { + $ps = array(); + foreach ($method->getParameters() as $param) { + $name = $param->getName(); + if (array_key_exists($name, $params)) { + if ($param->isArray()) { + $ps[$name] = is_array($params[$name]) ? $params[$name] : array($params[$name]); + } elseif (!is_array($params[$name])) { + $ps[$name] = $params[$name]; + } else { + return false; + } + } elseif ($param->isDefaultValueAvailable()) { + $ps[$name] = $param->getDefaultValue(); + } else { + return false; + } + } + return $ps; + } +} diff --git a/framework/util/StringHelper.php b/framework/util/StringHelper.php index caf0c61..81c12b2 100644 --- a/framework/util/StringHelper.php +++ b/framework/util/StringHelper.php @@ -1,6 +1,6 @@ * @author Alex Makarov diff --git a/framework/yiic.php b/framework/yiic.php index cd5c746..a1e2a24 100644 --- a/framework/yiic.php +++ b/framework/yiic.php @@ -7,6 +7,9 @@ * @license http://www.yiiframework.com/license/ */ +// fcgi doesn't have STDIN defined by default +defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); + require(__DIR__ . '/yii.php'); $config = array(