Commit 5a72523a by Qiang Xue

console commands.

parent a9b02d4e
...@@ -45,44 +45,20 @@ class Action extends Component ...@@ -45,44 +45,20 @@ class Action extends Component
} }
/** /**
* Normalizes the input parameters for the action. * Runs this action with the specified parameters.
* The parameters will later be passed to the `run()` method of the action. * This method is mainly invoked by the controller.
* This method is mainly called by the controller when running an action. * @param array $params action parameters
* @param array $params the input parameters in terms of name-value pairs. * @return integer the exit status (0 means normal, non-zero means abnormal).
* @return array|boolean the normalized parameters, or false if the input parameters are invalid.
*/ */
public function normalizeParams($params) public function runWithParams($params)
{ {
$method = new \ReflectionMethod($this, 'run'); $method = new \ReflectionMethod($this, 'run');
return $this->normalizeParamsByMethod($method, $params); $params = \yii\util\ReflectionHelper::bindParams($method, $params);
} if ($params === false) {
$this->controller->invalidActionParams($this);
/** return 1;
* Extracts the input parameters according to the specified method signature. } else {
* @param \ReflectionMethod $method the method reflection return (int)$method->invokeArgs($this, $params);
* @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;
}
} }
return false;
} }
} }
...@@ -187,10 +187,10 @@ abstract class Application extends Module ...@@ -187,10 +187,10 @@ abstract class Application extends Module
throw new Exception(\Yii::t('yii', 'Unable to resolve the request.')); throw new Exception(\Yii::t('yii', 'Unable to resolve the request.'));
} }
list($controller, $action) = $result; list($controller, $action) = $result;
$oldController = $this->controller; $priorController = $this->controller;
$this->controller = $controller; $this->controller = $controller;
$status = $controller->run($action, $params); $status = $controller->run($action, $params);
$this->controller = $oldController; $this->controller = $priorController;
return $status; return $status;
} }
......
...@@ -42,6 +42,30 @@ class Controller extends Component implements Initable ...@@ -42,6 +42,30 @@ class Controller extends Component implements Initable
*/ */
public $defaultAction = 'index'; 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 * @var Action the action that is currently being executed
*/ */
public $action; public $action;
...@@ -66,45 +90,11 @@ class Controller extends Component implements Initable ...@@ -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. * 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 * @param Action|string $action the action to be executed. This can be either an action object
* or the ID of the action. * 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. * 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. * @return integer the exit status of the action. 0 means normal, other values mean abnormal.
* @see missingAction * @see missingAction
* @see createAction * @see createAction
...@@ -122,32 +112,17 @@ class Controller extends Component implements Initable ...@@ -122,32 +112,17 @@ class Controller extends Component implements Initable
$priorAction = $this->action; $priorAction = $this->action;
$this->action = $action; $this->action = $action;
$exitStatus = 1;
if ($this->authorize($action)) { if ($this->authorize($action) && $this->beforeAction($action)) {
$params = $action->normalizeParams($params === null ? $this->getActionParams() : $params); $status = $action->runWithParams($params !== null ?: $this->getActionParams());
if ($params !== false) { $this->afterAction($action);
if ($this->beforeAction($action)) { } else {
$exitStatus = (int)call_user_func_array(array($action, 'run'), $params); $status = 1;
$this->afterAction($action);
}
} else {
$this->invalidActionParams($action);
}
} }
$this->action = $priorAction; $this->action = $priorAction;
return $exitStatus;
}
/** return $status;
* 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();
} }
/** /**
...@@ -163,15 +138,25 @@ class Controller extends Component implements Initable ...@@ -163,15 +138,25 @@ class Controller extends Component implements Initable
if ($actionID === '') { if ($actionID === '') {
$actionID = $this->defaultAction; $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); return new InlineAction($actionID, $this);
} else { } else {
$actions = $this->actions(); return null;
if (isset($actions[$actionID])) {
return \Yii::createObject($actions[$actionID], $actionID, $this);
}
} }
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 ...@@ -234,7 +219,7 @@ class Controller extends Component implements Initable
if ($route[0] !== '/' && !$this->module instanceof Application) { if ($route[0] !== '/' && !$this->module instanceof Application) {
$route = '/' . $this->module->getUniqueId() . '/' . $route; $route = '/' . $this->module->getUniqueId() . '/' . $route;
} }
$status = \Yii::$application->dispatch($route, $params); $status = \Yii::$application->processRequest($route, $params);
} }
if ($exit) { if ($exit) {
\Yii::$application->end($status); \Yii::$application->end($status);
......
...@@ -21,20 +21,20 @@ namespace yii\base; ...@@ -21,20 +21,20 @@ namespace yii\base;
class InlineAction extends Action class InlineAction extends Action
{ {
/** /**
* Runs the action with the supplied parameters. * Runs this action with the specified parameters.
* This method is invoked by the controller. * This method is mainly invoked by the controller.
* @param array $params the input parameters in terms of name-value pairs. * @param array $params action parameters
* @return boolean whether the input parameters are valid * @return integer the exit status (0 means normal, non-zero means abnormal).
*/ */
public function runWithParams($params) public function runWithParams($params)
{ {
$method = new \ReflectionMethod($this->controller, 'action' . $this->id); $method = new \ReflectionMethod($this->controller, 'action' . $this->id);
$params = $this->normalizeParamsByMethod($method, $params); $params = \yii\util\ReflectionHelper::bindParams($method, $params);
if ($params !== false) { if ($params === false) {
call_user_func_array(array($this->controller, 'action' . $this->id), $params); $this->controller->invalidActionParams($this);
return true; return 1;
} else { } else {
return false; return (int)$method->invokeArgs($this, $params);
} }
} }
} }
...@@ -11,9 +11,6 @@ namespace yii\console; ...@@ -11,9 +11,6 @@ namespace yii\console;
use yii\base\Exception; 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. * Application represents a console application.
* *
...@@ -41,9 +38,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); ...@@ -41,9 +38,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
* yiic help <command-name> * yiic help <command-name>
* ~~~ * ~~~
* *
* @property string $commandPath The directory that contains the command classes. Defaults to 'protected/commands'.
* @property CommandRunner $commandRunner The command runner.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
......
<?php
/**
* ReflectionHelper class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
/**
* ReflectionHelper
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @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;
}
}
<?php <?php
/** /**
* Text helper class file. * StringHelper class file.
* *
* @link http://www.yiiframework.com/ * @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC * @copyright Copyright &copy; 2008-2012 Yii Software LLC
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
namespace yii\util; namespace yii\util;
/** /**
* Text helper * StringHelper
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Alex Makarov <sam@rmcreative.ru> * @author Alex Makarov <sam@rmcreative.ru>
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* @license http://www.yiiframework.com/license/ * @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'); require(__DIR__ . '/yii.php');
$config = array( $config = array(
......
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