From b2662c0cd9f1f97c822b6a05d03ae117c2dcdeaf Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 2 Feb 2013 23:36:20 -0500 Subject: [PATCH] clean up help command. --- framework/base/Action.php | 9 + framework/base/Controller.php | 2 +- framework/console/Application.php | 8 +- framework/console/BadUsageException.php | 33 --- framework/console/Controller.php | 29 ++- framework/console/Exception.php | 33 +++ framework/console/Request.php | 6 +- framework/console/controllers/HelpController.php | 256 ++++++++++++--------- .../console/controllers/MigrateController.php | 116 +++++++--- 9 files changed, 289 insertions(+), 203 deletions(-) delete mode 100644 framework/console/BadUsageException.php create mode 100644 framework/console/Exception.php diff --git a/framework/base/Action.php b/framework/base/Action.php index 8d4ec5a..a852e0b 100644 --- a/framework/base/Action.php +++ b/framework/base/Action.php @@ -56,6 +56,15 @@ class Action extends Component } /** + * Returns the unique ID of this action among the whole application. + * @return string the unique ID of this action among the whole application. + */ + public function getUniqueId() + { + return $this->controller->getUniqueId() . '/' . $this->id; + } + + /** * Runs this action with the specified parameters. * This method is mainly invoked by the controller. * @param array $params the parameters to be bound to the action's run() method. diff --git a/framework/base/Controller.php b/framework/base/Controller.php index 804b339..3cbee77 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -250,7 +250,7 @@ class Controller extends Component */ public function getRoute() { - return $this->action !== null ? $this->getUniqueId() . '/' . $this->action->id : $this->getUniqueId(); + return $this->action !== null ? $this->action->getUniqueId() : $this->getUniqueId(); } /** diff --git a/framework/console/Application.php b/framework/console/Application.php index 47c3142..5f86cac 100644 --- a/framework/console/Application.php +++ b/framework/console/Application.php @@ -9,7 +9,6 @@ namespace yii\console; -use yii\base\Exception; use yii\base\InvalidRouteException; /** @@ -85,6 +84,7 @@ class Application extends \yii\base\Application * Processes the request. * The request is represented in terms of a controller route and action parameters. * @return integer the exit status of the controller action (0 means normal, non-zero values mean abnormal) + * @throws Exception if the script is not running from the command line */ public function processRequest() { @@ -93,7 +93,7 @@ class Application extends \yii\base\Application if ($request->getIsConsoleRequest()) { return $this->runAction($request->route, $request->params); } else { - throw new BadUsageException(\Yii::t('yii', 'this script must be run from the command line.')); + throw new Exception(\Yii::t('yii', 'this script must be run from the command line.')); } } @@ -105,14 +105,14 @@ class Application extends \yii\base\Application * @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 BadUsageException if the route is invalid + * @throws Exception if the route is invalid */ public function runAction($route, $params = array()) { try { return parent::runAction($route, $params); } catch (InvalidRouteException $e) { - throw new BadUsageException(\Yii::t('yii', 'Unknown command "{command}".', array('{command}' => $route))); + throw new Exception(\Yii::t('yii', 'Unknown command "{command}".', array('{command}' => $route))); } } diff --git a/framework/console/BadUsageException.php b/framework/console/BadUsageException.php deleted file mode 100644 index abf02b0..0000000 --- a/framework/console/BadUsageException.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @since 2.0 - */ -class BadUsageException extends \yii\base\Exception -{ - /** - * @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL) - */ - public $causedByUser = true; - - /** - * @return string the user-friendly name of this exception - */ - public function getName() - { - return \Yii::t('yii', 'Bad Usage'); - } -} - diff --git a/framework/console/Controller.php b/framework/console/Controller.php index 0880c44..faab435 100644 --- a/framework/console/Controller.php +++ b/framework/console/Controller.php @@ -48,14 +48,11 @@ class Controller extends \yii\base\Controller public function runAction($id, $params = array()) { if ($params !== array()) { - $class = new \ReflectionClass($this); + $options = $this->globalOptions(); 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]); - } + if (in_array($name, $options, true)) { + $this->$name = $value; + unset($params[$name]); } } } @@ -69,16 +66,19 @@ class Controller extends \yii\base\Controller * @param Action $action the currently requested action * @param array $missingParams the names of the missing parameters * @param array $unknownParams the unknown parameters (name=>value) - * @throws BadUsageException if there are missing or unknown parameters + * @throws Exception if there are missing or unknown parameters */ public function validateActionParams($action, $missingParams, $unknownParams) { + unset($missingParams[Request::ANONYMOUS_PARAMS], $unknownParams[Request::ANONYMOUS_PARAMS]); + if (!empty($missingParams)) { - throw new BadUsageException(Yii::t('yii', 'Missing required options: {params}', array( + throw new Exception(Yii::t('yii', 'Missing required options: {params}', array( '{params}' => implode(', ', $missingParams), ))); - } elseif (!empty($unknownParams)) { - throw new BadUsageException(Yii::t('yii', 'Unknown options: {params}', array( + } + if (!empty($unknownParams)) { + throw new Exception(Yii::t('yii', 'Unknown options: {params}', array( '{params}' => implode(', ', $unknownParams), ))); } @@ -102,6 +102,13 @@ class Controller extends \yii\base\Controller } } + /** + * Returns the names of the global options for this command. + * A global option requires the existence of a global member variable whose + * name is the option name. + * Child classes may override this method to specify possible global options. + * @return array the names of the global options for this command. + */ public function globalOptions() { return array(); diff --git a/framework/console/Exception.php b/framework/console/Exception.php new file mode 100644 index 0000000..0ed5a42 --- /dev/null +++ b/framework/console/Exception.php @@ -0,0 +1,33 @@ + + * @since 2.0 + */ +class Exception extends \yii\base\Exception +{ + /** + * @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL) + */ + public $causedByUser = true; + + /** + * @return string the user-friendly name of this exception + */ + public function getName() + { + return \Yii::t('yii', 'Error'); + } +} + diff --git a/framework/console/Request.php b/framework/console/Request.php index dbf80ba..4976fd2 100644 --- a/framework/console/Request.php +++ b/framework/console/Request.php @@ -15,6 +15,8 @@ namespace yii\console; */ class Request extends \yii\base\Request { + const ANONYMOUS_PARAMS = 'args'; + /** * @var string the controller route specified by this request. If this is an empty string, * it means the [[Application::defaultRoute|default route]] will be used. @@ -50,13 +52,13 @@ class Request extends \yii\base\Request $this->route = ''; } - $this->params = array(); + $this->params = array(self::ANONYMOUS_PARAMS => array()); foreach ($rawParams as $param) { if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) { $name = $matches[1]; $this->params[$name] = isset($matches[3]) ? $matches[3] : true; } else { - $this->params['args'][] = $param; + $this->params[self::ANONYMOUS_PARAMS][] = $param; } } } diff --git a/framework/console/controllers/HelpController.php b/framework/console/controllers/HelpController.php index d1dc697..2d86285 100644 --- a/framework/console/controllers/HelpController.php +++ b/framework/console/controllers/HelpController.php @@ -11,9 +11,10 @@ namespace yii\console\controllers; use Yii; use yii\base\Application; -use yii\console\BadUsageException; +use yii\console\Exception; use yii\base\InlineAction; use yii\console\Controller; +use yii\console\Request; use yii\util\StringHelper; /** @@ -46,19 +47,17 @@ class HelpController extends Controller * yiic help message # display help info about "message" * ~~~ * - * @param array $args additional anonymous command line arguments. - * You may provide a command name to display its detailed information. + * @param array $args The name of the command to show help about. + * If not provided, all available commands will be displayed. * @return integer the exit status - * @throws BadUsageException if the command for help is unknown + * @throws Exception if the command for help is unknown */ public function actionIndex($args = array()) { - if (empty($args)) { - $this->getHelp(); - } else { + if (isset($args[0])) { $result = Yii::$application->createController($args[0]); if ($result === false) { - throw new BadUsageException(Yii::t('yii', 'No help for unknown command "{command}".', array( + throw new Exception(Yii::t('yii', 'No help for unknown command "{command}".', array( '{command}' => $args[0], ))); } @@ -70,6 +69,8 @@ class HelpController extends Controller } else { $this->getActionHelp($controller, $actionID); } + } else { + $this->getHelp(); } } @@ -143,7 +144,7 @@ class HelpController extends Controller { $commands = $this->getCommands(); if ($commands !== array()) { - echo "\nUsage: yiic [...options...]\n\n"; + echo "Usage: yiic [...options...] [...arguments...]\n\n"; echo "The following commands are available:\n\n"; foreach ($commands as $command) { echo " * $command\n"; @@ -168,35 +169,23 @@ class HelpController extends Controller } if ($comment !== '') { - echo "\n" . $comment . "\n"; - } - - $options = $this->getGlobalOptions($class, $controller); - if ($options !== array()) { - echo "\nGLOBAL OPTIONS"; - echo "\n--------------\n\n"; - foreach ($options as $name => $description) { - echo " --$name"; - if ($description != '') { - echo ": $description\n"; - } - echo "\n"; - } + echo "\nDESCRIPTION\n"; + echo "\n" . $comment . "\n\n"; } $actions = $this->getActions($controller); if ($actions !== array()) { - echo "\nSUB-COMMANDS"; - echo "\n------------\n\n"; + echo "\nSUB-COMMANDS\n\n"; $prefix = $controller->getUniqueId(); foreach ($actions as $action) { if ($controller->defaultAction === $action) { - echo " * $prefix (default)\n"; + echo " * $prefix/$action (or $prefix)\n"; } else { echo " * $prefix/$action\n"; } } - echo "\n"; + echo "\nTo see the help of each sub-command, enter:\n"; + echo "\n yiic help \n\n"; } } @@ -204,45 +193,78 @@ class HelpController extends Controller * Displays the detailed information of a command action. * @param Controller $controller the controller instance * @param string $actionID action ID - * @throws BadUsageException if the action does not exist + * @throws Exception if the action does not exist */ protected function getActionHelp($controller, $actionID) { $action = $controller->createAction($actionID); if ($action === null) { - throw new BadUsageException(Yii::t('yii', 'No help for unknown sub-command "{command}".', array( - '{command}' => $controller->getUniqueId() . "/$actionID", + throw new Exception(Yii::t('yii', 'No help for unknown sub-command "{command}".', array( + '{command}' => $action->getUniqueId(), ))); } if ($action instanceof InlineAction) { - $method = new \ReflectionMethod($controller, 'action' . $action->id); + $method = new \ReflectionMethod($controller, $action->actionMethod); } else { $method = new \ReflectionMethod($action, 'run'); } - $comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($method->getDocComment(), '/'))), "\r", ''); - if (preg_match('/^\s*@\w+/m', $comment, $matches, PREG_OFFSET_CAPTURE)) { - $meta = substr($comment, $matches[0][1]); - $comment = trim(substr($comment, 0, $matches[0][1])); + + $tags = $this->parseComment($method->getDocComment()); + $options = $this->getOptions($method, isset($tags['param']) ? $tags['param'] : array()); + $globalOptions = $this->getGlobalOptions($controller); + $options = array_merge($options, $globalOptions); + + echo "\nUSAGE\n\n"; + if ($action->id === $controller->defaultAction) { + echo 'yiic ' . $controller->getUniqueId(); } else { - $meta = ''; + echo "yiic " . $action->getUniqueId(); + } + if (isset($options[Request::ANONYMOUS_PARAMS])) { + if (count($options) > 1) { + echo ' [...options...]'; + } + echo " [...arguments...]"; + } elseif (count($options)) { + echo " [...options...]"; } + echo "\n\n"; - if ($comment !== '') { - echo "\n" . $comment . "\n"; + if ($tags['description'] !== '') { + echo "\nDESCRIPTION"; + echo "\n\n" . $tags['description'] . "\n\n"; + } + + if (isset($options[Request::ANONYMOUS_PARAMS])) { + echo "\nARGUMENTS\n\n"; + echo $options[Request::ANONYMOUS_PARAMS] . "\n\n"; + unset($options[Request::ANONYMOUS_PARAMS]); } - $options = $this->getOptions($method, $meta); if ($options !== array()) { - echo "\nOPTIONS"; - echo "\n-------\n\n"; - foreach ($options as $name => $description) { - echo " --$name"; - if ($description != '') { - echo ": $description\n"; + echo "\nOPTIONS\n\n"; + echo implode("\n\n", $options) . "\n\n"; + } + } + + function parseComment($comment) + { + $tags = array(); + $comment = "@description \n" . strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($comment, '/'))), "\r", ''); + $parts = preg_split('/^\s*@/m', $comment, -1, PREG_SPLIT_NO_EMPTY); + foreach ($parts as $part) { + if (preg_match('/^(\w+)(.*)/ms', trim($part), $matches)) { + $name = $matches[1]; + if (!isset($tags[$name])) { + $tags[$name] = trim($matches[2]); + } elseif (is_array($tags[$name])) { + $tags[$name][] = trim($matches[2]); + } else { + $tags[$name] = array($tags[$name], trim($matches[2])); } } - echo "\n"; } + return $tags; } /** @@ -250,93 +272,99 @@ class HelpController extends Controller * @param string $meta * @return array */ - protected function getOptions($method, $meta) + protected function getOptions($method, $tags) { + if (is_string($tags)) { + $tags = array($tags); + } $params = $method->getParameters(); - $tags = preg_split('/^\s*@/m', $meta, -1, PREG_SPLIT_NO_EMPTY); - $options = array(); - $count = 0; - foreach ($tags as $tag) { - $parts = preg_split('/\s+/', trim($tag), 2); - if ($parts[0] === 'param' && isset($params[$count])) { - $param = $params[$count]; - $comment = isset($parts[1]) ? $parts[1] : ''; - if (preg_match('/^([^\s]+)\s+(\$\w+\s+)?(.*)/s', $comment, $matches)) { - $type = $matches[1]; - $doc = $matches[3]; - } else { - $type = $comment; - $doc = ''; - } - $comment = $type === '' ? '' : ($type . ', '); - if ($param->isDefaultValueAvailable()) { - $value = $param->getDefaultValue(); - if (!is_array($value)) { - $comment .= 'optional (defaults to ' . var_export($value, true) . ').'; - } else { - $comment .= 'optional.'; - } - } else { - $comment .= 'required.'; - } - if (trim($doc) !== '') { - $comment .= "\n" . preg_replace("/^/m", " ", $doc); - } - $options[$param->getName()] = $comment; - $count++; + $optional = $required = array(); + foreach ($params as $i => $param) { + $name = $param->getName(); + $tag = isset($tags[$i]) ? $tags[$i] : ''; + if (preg_match('/^([^\s]+)\s+(\$\w+\s+)?(.*)/s', $tag, $matches)) { + $type = $matches[1]; + $comment = $matches[3]; + } else { + $type = null; + $comment = $tag; + } + if ($param->isDefaultValueAvailable()) { + $optional[$name] = $this->formatOptionHelp($name, false, $type, $param->getDefaultValue(), $comment); + } else { + $required[$name] = $this->formatOptionHelp($name, true, $type, null, $comment); } } - if ($count < count($params)) { - for ($i = $count; $i < count($params); ++$i) { - $options[$params[$i]->getName()] = ''; + + ksort($required); + ksort($optional); + + return array_merge($required, $optional); + } + + protected function formatOptionHelp($name, $required, $type, $defaultValue, $comment) + { + $doc = ''; + $comment = trim($comment); + + if ($name === Request::ANONYMOUS_PARAMS) { + return $comment; + } + + if ($defaultValue !== null && !is_array($defaultValue)) { + if ($type === null) { + $type = gettype($defaultValue); } + $doc = "$type (defaults to " . var_export($defaultValue, true) . ")"; + } elseif (trim($type) !== '') { + $doc = $type; } - ksort($options); - return $options; + if ($doc === '') { + $doc = $comment; + } elseif ($comment !== '') { + $doc .= "\n" . preg_replace("/^/m", " ", $comment); + } + + $name = $required ? "--$name (required)" : "--$name"; + return $doc === '' ? $name : "$name: $doc"; } /** - * @param \ReflectionClass $class * @param Controller $controller * @return array */ - protected function getGlobalOptions($class, $controller) + protected function getGlobalOptions($controller) { + $optionNames = $controller->globalOptions(); + if (empty($optionNames)) { + return array(); + } + + $class = new \ReflectionClass($controller); $options = array(); foreach ($class->getProperties() as $property) { - if (!$property->isPublic() || $property->isStatic() || $property->getDeclaringClass()->getName() !== get_class($controller)) { - continue; - } $name = $property->getName(); - $comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($property->getDocComment(), '/'))), "\r", ''); - if (preg_match('/^\s*@\w+/m', $comment, $matches, PREG_OFFSET_CAPTURE)) { - $meta = substr($comment, $matches[0][1]); - } else { - $meta = ''; + if (!in_array($name, $optionNames, true)) { + continue; } - $tags = preg_split('/^\s*@/m', $meta, -1, PREG_SPLIT_NO_EMPTY); - foreach ($tags as $tag) { - $parts = preg_split('/\s+/', trim($tag), 2); - $comment = isset($parts[1]) ? $parts[1] : ''; - if ($parts[0] === 'var' || $parts[0] === 'property') { - if (preg_match('/^([^\s]+)(\s+.*)?/s', $comment, $matches)) { - $type = $matches[1]; - $doc = trim($matches[2]); - } else { - $type = $comment; - $doc = ''; - } - $comment = $type === '' ? '' : ($type); - if (trim($doc) !== '') { - $comment .= ', ' . preg_replace("/^/m", "", $doc); - } - $options[$name] = $comment; - break; + $defaultValue = $property->getValue($controller); + $tags = $this->parseComment($property->getDocComment()); + if (isset($tags['var']) || isset($tags['property'])) { + $doc = isset($tags['var']) ? $tags['var'] : $tags['property']; + if (is_array($doc)) { + $doc = reset($doc); } - } - if (!isset($options[$name])) { - $options[$name] = ''; + if (preg_match('/^([^\s]+)(.*)/s', $doc, $matches)) { + $type = $matches[1]; + $comment = $matches[2]; + } else { + $type = null; + $comment = $doc; + } + $options[$name] = $this->formatOptionHelp($name, false, $type, $defaultValue, $comment); + } else { + $options[$name] = $this->formatOptionHelp($name, false, null, $defaultValue, ''); } } ksort($options); diff --git a/framework/console/controllers/MigrateController.php b/framework/console/controllers/MigrateController.php index e104856..b8076fc 100644 --- a/framework/console/controllers/MigrateController.php +++ b/framework/console/controllers/MigrateController.php @@ -11,22 +11,20 @@ namespace yii\console\controllers; use Yii; +use yii\console\Exception; use yii\console\Controller; +use yii\db\Connection; /** * This command provides support for database migrations. * - * The implementation of this command and other supporting classes referenced - * the yii-dbmigrations extension ((https://github.com/pieterclaerhout/yii-dbmigrations), - * authored by Pieter Claerhout. - * * EXAMPLES * * - yiic migrate * Applies ALL new migrations. This is equivalent to 'yiic migrate up'. * * - yiic migrate create create_user_table - * Creates a new migration named 'create_user_table'. + * Creates a new migration named 'create_user_table'. * * - yiic migrate up 3 * Applies the next 3 new migrations. @@ -45,69 +43,86 @@ use yii\console\Controller; * No actual migration will be performed. * * - yiic migrate history - * Shows all previously applied migration information. + * Shows all previously applied migration information. * * - yiic migrate history 10 - * Shows the last 10 applied migrations. + * Shows the last 10 applied migrations. * * - yiic migrate new - * Shows all new migrations. + * Shows all new migrations. * * - yiic migrate new 10 - * Shows the next 10 migrations that have not been applied. + * Shows the next 10 migrations that have not been applied. * * @author Qiang Xue * @since 2.0 */ class MigrateController extends Controller { + /** + * The name of the dummy migration that marks the beginning of the whole migration history. + */ const BASE_MIGRATION = 'm000000_000000_base'; /** - * @var string the directory that stores the migrations. This must be specified - * in terms of a path alias, and the corresponding directory must exist. - * Defaults to 'application.migrations' (meaning 'protected/migrations'). + * @var string the directory that stores the migrations. This can be either a path alias + * or a directory. Defaults to '@application/migrations'. */ public $migrationPath = '@application/migrations'; /** * @var string the name of the table for keeping applied migration information. - * This table will be automatically created if not exists. Defaults to 'tbl_migration'. - * The table structure is: (version varchar(255) primary key, apply_time integer) + * This table will be automatically created if not exists. + * The table structure is as follows: + * + * ~~~ + * CREATE TABLE tbl_migration ( + * version varchar(255) PRIMARY KEY, + * apply_time integer + * ) + * ~~~ */ public $migrationTable = 'tbl_migration'; /** - * @var string the application component ID that specifies the database connection for - * storing migration information. Defaults to 'db'. + * @var string the component ID that specifies the database connection for + * storing migration information. */ public $connectionID = 'db'; /** - * @var string the path of the template file for generating new migrations. This - * must be specified in terms of a path alias (e.g. application.migrations.template). - * If not set, an internal template will be used. + * @var string the path of the template file for generating new migrations. + * This can be either a path alias (e.g. "@application/migrations/template.php") + * or a file path. If not set, an internal template will be used. */ public $templateFile; /** - * @var string the default command action. It defaults to 'up'. + * @var string the default command action. */ public $defaultAction = 'up'; /** - * @var boolean whether to execute the migration in an interactive mode. Defaults to true. - * Set this to false when performing migration in a cron job or background process. + * @var boolean whether to execute the migration in an interactive mode. */ public $interactive = true; - + public function globalOptions() + { + return array('migrationPath', 'migrationTable', 'connectionID', 'templateFile', 'interactive'); + } + /** + * This method is invoked right before an action is to be executed (after all possible filters.) + * It checks the existence of the [[migrationPath]]. + * @param \yii\base\Action $action the action to be executed. + * @return boolean whether the action should continue to be executed. + * @throws Exception if the migration directory does not exist. + */ public function beforeAction($action) { if (parent::beforeAction($action)) { $path = Yii::getAlias($this->migrationPath); if ($path === false || !is_dir($path)) { - echo 'Error: the migration directory does not exist "' . $this->migrationPath . "\"\n"; - return false; + throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist."); } $this->migrationPath = $path; $version = Yii::getVersion(); - echo "\nYii Migration Tool v2.0 (based on Yii v{$version})\n\n"; + echo "\nYii Migration Tool (based on Yii v{$version})\n\n"; return true; } else { return false; @@ -115,7 +130,15 @@ class MigrateController extends Controller } /** - * @param array $args + * Upgrades the application by applying new migrations. For example, + * + * ~~~ + * yiic migrate # apply all new migrations + * yiic migrate 3 # apply the first 3 new migrations + * ~~~ + * + * @param array $args the number of new migrations to be applied. If not provided, + * all new migrations will be applied. */ public function actionUp($args) { @@ -145,7 +168,7 @@ class MigrateController extends Controller if ($this->confirm('Apply the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { foreach ($migrations as $migration) { if ($this->migrateUp($migration) === false) { - echo "\nMigration failed. All later migrations are canceled.\n"; + echo "\nMigration failed. The rest of the new migrations are canceled.\n"; return; } } @@ -153,11 +176,23 @@ class MigrateController extends Controller } } + /** + * Downgrades the application by reverting old migrations. For example, + * + * ~~~ + * yiic migrate/down # revert the last migration + * yiic migrate/down 3 # revert the last 3 migrations + * ~~~ + * + * @param array $args the number of migrations to be reverted. If not provided, + * the last applied migration will be reverted. + * @throws Exception if the number of the steps is less than 1. + */ public function actionDown($args) { $step = isset($args[0]) ? (int)$args[0] : 1; if ($step < 1) { - die("Error: The step parameter must be greater than 0.\n"); + throw new Exception("The step parameter must be greater than 0."); } if (($migrations = $this->getMigrationHistory($step)) === array()) { @@ -226,14 +261,14 @@ class MigrateController extends Controller if (isset($args[0])) { $version = $args[0]; } else { - $this->usageError('Please specify which version to migrate to.'); + throw new Exception("Please specify which version to migrate to."); } $originalVersion = $version; if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { $version = 'm' . $matches[1]; } else { - die("Error: The version option must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table).\n"); + throw new Exception("The version option must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); } // try migrate up @@ -258,7 +293,7 @@ class MigrateController extends Controller } } - die("Error: Unable to find the version '$originalVersion'.\n"); + throw new Exception("Unable to find the version '$originalVersion'."); } public function actionMark($args) @@ -266,13 +301,13 @@ class MigrateController extends Controller if (isset($args[0])) { $version = $args[0]; } else { - $this->usageError('Please specify which version to mark to.'); + throw new Exception('Please specify which version to mark to.'); } $originalVersion = $version; if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { $version = 'm' . $matches[1]; } else { - die("Error: The version option must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table).\n"); + throw new Exception("Error: The version option must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); } $db = $this->getDb(); @@ -357,12 +392,17 @@ class MigrateController extends Controller } } + /** + * Creates a new migration. + * @param array $args the name of the new migration. + * @throws Exception if the name of the new migration is not provided + */ public function actionCreate($args) { if (isset($args[0])) { $name = $args[0]; } else { - $this->usageError('Please provide the name of the new migration.'); + throw new Exception('Please provide the name of the new migration.'); } if (!preg_match('/^\w+$/', $name)) { @@ -428,7 +468,7 @@ class MigrateController extends Controller $file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php'; require_once($file); $migration = new $class; - $migration->setDb($this->getDb()); + $migration->db = $this->getDb(); return $migration; } @@ -445,7 +485,7 @@ class MigrateController extends Controller if (($this->_db = Yii::$application->getComponent($this->connectionID)) instanceof CDbConnection) { return $this->_db; } else { - die("Error: CMigrationCommand.connectionID '{$this->connectionID}' is invalid. Please make sure it refers to the ID of a CDbConnection application component.\n"); + throw new Exception("Invalid DB connection: {$this->connectionID}."); } } } @@ -505,7 +545,7 @@ class MigrateController extends Controller protected function getTemplate() { if ($this->templateFile !== null) { - return file_get_contents(Yii::getPathOfAlias($this->templateFile) . '.php'); + return file_get_contents(Yii::getAlias($this->templateFile)); } else { return <<