You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

345 lines
9.4 KiB

<?php
/**
* HelpController class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console\controllers;
use Yii;
use yii\base\Application;
use yii\console\BadUsageException;
use yii\base\InlineAction;
use yii\console\Controller;
use yii\util\StringHelper;
/**
* This command provides help information about console commands.
*
* This command displays the available command list in
* the application or the detailed instructions about using
* a specific command.
*
* This command can be used as follows on command line:
*
* ~~~
* yiic help [command name]
* ~~~
*
* In the above, if the command name is not provided, all
* available commands will be displayed.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HelpController extends Controller
{
/**
* Displays available commands or the detailed information
* about a particular command. For example,
*
* ~~~
* yiic help # list available commands
* 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.
* @return integer the exit status
* @throws BadUsageException if the command for help is unknown
*/
public function actionIndex($args = array())
{
if (empty($args)) {
$this->getHelp();
} else {
$result = Yii::$application->createController($args[0]);
if ($result === false) {
throw new BadUsageException(Yii::t('yii', 'No help for unknown command "{command}".', array(
'{command}' => $args[0],
)));
}
list($controller, $actionID) = $result;
if ($actionID === '') {
$this->getControllerHelp($controller);
} else {
$this->getActionHelp($controller, $actionID);
}
}
}
/**
* Returns all available command names.
* @return array all available command names
*/
public function getCommands()
{
$commands = $this->getModuleCommands(Yii::$application);
sort($commands);
return array_unique($commands);
}
/**
* Returns all available actions of the specified controller.
* @param Controller $controller the controller instance
* @return array all available action IDs.
*/
public function getActions($controller)
{
$actions = array_keys($controller->actions());
$class = new \ReflectionClass($controller);
foreach ($class->getMethods() as $method) {
$name = $method->getName();
if ($method->isPublic() && !$method->isStatic() && strpos($name, 'action') === 0 && $name !== 'actions') {
$actions[] = StringHelper::camel2id(substr($name, 6));
}
}
sort($actions);
return array_unique($actions);
}
/**
* Returns available commands of a specified module.
* @param \yii\base\Module $module the module instance
* @return array the available command names
*/
protected function getModuleCommands($module)
{
$prefix = $module instanceof Application ? '' : $module->getUniqueID() . '/';
$commands = array();
foreach (array_keys($module->controllerMap) as $id) {
$commands[] = $prefix . $id;
}
foreach ($module->getModules() as $id => $child) {
if (($child = $module->getModule($id)) === null) {
continue;
}
foreach ($this->getModuleCommands($child) as $command) {
$commands[] = $prefix . $id . '/' . $command;
}
}
$files = scandir($module->getControllerPath());
foreach ($files as $file) {
if(strcmp(substr($file,-14),'Controller.php') === 0 && is_file($file)) {
$commands[] = $prefix . lcfirst(substr(basename($file), 0, -14));
}
}
return $commands;
}
/**
* Displays all available commands.
*/
protected function getHelp()
{
$commands = $this->getCommands();
if ($commands !== array()) {
echo "\nUsage: yiic <command-name> [...options...]\n\n";
echo "The following commands are available:\n\n";
foreach ($commands as $command) {
echo " * $command\n";
}
echo "\nTo see the help of each command, enter:\n";
echo "\n yiic help <command-name>\n";
} else {
echo "\nNo commands are found.\n";
}
}
/**
* Displays the overall information of the command.
* @param Controller $controller the controller instance
*/
protected function getControllerHelp($controller)
{
$class = new \ReflectionClass($controller);
$comment = strtr(trim(preg_replace('/^\s*\**( |\t)?/m', '', trim($class->getDocComment(), '/'))), "\r", '');
if (preg_match('/^\s*@\w+/m', $comment, $matches, PREG_OFFSET_CAPTURE)) {
$comment = trim(substr($comment, 0, $matches[0][1]));
}
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";
}
}
$actions = $this->getActions($controller);
if ($actions !== array()) {
echo "\nSUB-COMMANDS";
echo "\n------------\n\n";
$prefix = $controller->getUniqueId();
foreach ($actions as $action) {
if ($controller->defaultAction === $action) {
echo " * $prefix (default)\n";
} else {
echo " * $prefix/$action\n";
}
}
echo "\n";
}
}
/**
* 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
*/
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",
)));
}
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($controller, 'action' . $action->id);
} 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]));
} else {
$meta = '';
}
if ($comment !== '') {
echo "\n" . $comment . "\n";
}
$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 "\n";
}
}
/**
* @param \ReflectionMethod $method
* @param string $meta
* @return array
*/
protected function getOptions($method, $meta)
{
$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++;
}
}
if ($count < count($params)) {
for ($i = $count; $i < count($params); ++$i) {
$options[$params[$i]->getName()] = '';
}
}
ksort($options);
return $options;
}
/**
* @param \ReflectionClass $class
* @param Controller $controller
* @return array
*/
protected function getGlobalOptions($class, $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 = '';
}
$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;
}
}
if (!isset($options[$name])) {
$options[$name] = '';
}
}
ksort($options);
return $options;
}
}