Controller.php 9.18 KB
Newer Older
Alexander Makarov committed
1 2 3
<?php
/**
 * @link http://www.yiiframework.com/
Qiang Xue committed
4
 * @copyright Copyright (c) 2008 Yii Software LLC
Alexander Makarov committed
5 6 7 8 9
 * @license http://www.yiiframework.com/license/
 */

namespace yii\console;

Qiang Xue committed
10
use Yii;
Qiang Xue committed
11
use yii\base\Action;
Qiang Xue committed
12
use yii\base\InlineAction;
Qiang Xue committed
13
use yii\base\InvalidRouteException;
14
use yii\helpers\Console;
Qiang Xue committed
15

Alexander Makarov committed
16
/**
Qiang Xue committed
17
 * Controller is the base class of console command classes.
Alexander Makarov committed
18
 *
Qiang Xue committed
19 20
 * A controller consists of one or several actions known as sub-commands.
 * Users call a console command by specifying the corresponding route which identifies a controller action.
21
 * The `yii` program is used when calling a console command, like the following:
Alexander Makarov committed
22
 *
Qiang Xue committed
23
 * ~~~
24
 * yii <route> [--param1=value1 --param2 ...]
Qiang Xue committed
25
 * ~~~
Alexander Makarov committed
26 27 28 29
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
Qiang Xue committed
30
class Controller extends \yii\base\Controller
Alexander Makarov committed
31
{
32 33 34 35
    /**
     * @var boolean whether to run the command interactively.
     */
    public $interactive = true;
Qiang Xue committed
36

37 38 39 40 41
    /**
     * @var boolean whether to enable ANSI color in the output.
     * If not set, ANSI color will only be enabled for terminals that support it.
     */
    public $color;
42

43 44 45 46 47 48 49 50 51 52 53 54 55
    /**
     * Returns a value indicating whether ANSI color is enabled.
     *
     * ANSI color is enabled only if [[color]] is set true or is not set
     * and the terminal supports ANSI color.
     *
     * @param  resource $stream the stream to check.
     * @return boolean  Whether to enable ANSI style in output.
     */
    public function isColorEnabled($stream = STDOUT)
    {
        return $this->color ===  null ? Console::streamSupportsAnsiColors($stream) : $this->color;
    }
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    /**
     * 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.
     * @throws Exception             if there are unknown options or missing arguments
     * @see createAction
     */
    public function runAction($id, $params = [])
    {
        if (!empty($params)) {
            // populate options here so that they are available in beforeAction().
            $options = $this->options($id);
            foreach ($params as $name => $value) {
                if (in_array($name, $options, true)) {
                    $default = $this->$name;
                    $this->$name = is_array($default) ? preg_split('/\s*,\s*/', $value) : $value;
                    unset($params[$name]);
                } elseif (!is_int($name)) {
                    throw new Exception(Yii::t('yii', 'Unknown option: --{name}', ['name' => $name]));
                }
            }
        }
Qiang Xue committed
82

83 84
        return parent::runAction($id, $params);
    }
Qiang Xue committed
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    /**
     * Binds the parameters to the action.
     * This method is invoked by [[Action]] when it begins to run with the given parameters.
     * This method will first bind the parameters with the [[options()|options]]
     * available to the action. It then validates the given arguments.
     * @param  Action    $action the action to be bound with parameters
     * @param  array     $params the parameters to be bound to the action
     * @return array     the valid parameters that the action can run with.
     * @throws Exception if there are unknown options or missing arguments
     */
    public function bindActionParams($action, $params)
    {
        if ($action instanceof InlineAction) {
            $method = new \ReflectionMethod($this, $action->actionMethod);
        } else {
            $method = new \ReflectionMethod($action, 'run');
        }
103

104
        $args = array_values($params);
Qiang Xue committed
105

106 107 108 109 110 111 112 113 114 115 116 117 118
        $missing = [];
        foreach ($method->getParameters() as $i => $param) {
            if ($param->isArray() && isset($args[$i])) {
                $args[$i] = preg_split('/\s*,\s*/', $args[$i]);
            }
            if (!isset($args[$i])) {
                if ($param->isDefaultValueAvailable()) {
                    $args[$i] = $param->getDefaultValue();
                } else {
                    $missing[] = $param->getName();
                }
            }
        }
Qiang Xue committed
119

120 121 122
        if (!empty($missing)) {
            throw new Exception(Yii::t('yii', 'Missing required arguments: {params}', ['params' => implode(', ', $missing)]));
        }
Alexander Makarov committed
123

124 125
        return $args;
    }
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    /**
     * Formats a string with ANSI codes
     *
     * You may pass additional parameters using the constants defined in [[\yii\helpers\Console]].
     *
     * Example:
     *
     * ~~~
     * echo $this->ansiFormat('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
     * ~~~
     *
     * @param  string $string the string to be formatted
     * @return string
     */
    public function ansiFormat($string)
    {
        if ($this->isColorEnabled()) {
            $args = func_get_args();
            array_shift($args);
            $string = Console::ansiFormat($string, $args);
        }
148

149 150
        return $string;
    }
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    /**
     * Prints a string to STDOUT
     *
     * You may optionally format the string with ANSI codes by
     * passing additional parameters using the constants defined in [[\yii\helpers\Console]].
     *
     * Example:
     *
     * ~~~
     * $this->stdout('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
     * ~~~
     *
     * @param  string      $string the string to print
     * @return int|boolean Number of bytes printed or false on error
     */
    public function stdout($string)
    {
        if ($this->isColorEnabled()) {
            $args = func_get_args();
            array_shift($args);
            $string = Console::ansiFormat($string, $args);
        }
174

175 176
        return Console::stdout($string);
    }
Qiang Xue committed
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    /**
     * Prints a string to STDERR
     *
     * You may optionally format the string with ANSI codes by
     * passing additional parameters using the constants defined in [[\yii\helpers\Console]].
     *
     * Example:
     *
     * ~~~
     * $this->stderr('This will be red and underlined.', Console::FG_RED, Console::UNDERLINE);
     * ~~~
     *
     * @param  string      $string the string to print
     * @return int|boolean Number of bytes printed or false on error
     */
    public function stderr($string)
    {
        if ($this->isColorEnabled(STDERR)) {
            $args = func_get_args();
            array_shift($args);
            $string = Console::ansiFormat($string, $args);
        }
200

201 202
        return fwrite(STDERR, $string);
    }
203

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    /**
     * Prompts the user for input and validates it
     *
     * @param string $text    prompt string
     * @param array  $options the options to validate the input:
     *
     *  - required: whether it is required or not
     *  - default: default value if no input is inserted by the user
     *  - pattern: regular expression pattern to validate user input
     *  - validator: a callable function to validate input. The function must accept two parameters:
     *      - $input: the user input to validate
     *      - $error: the error value passed by reference if validation failed.
     * @return string the user input
     */
    public function prompt($text, $options = [])
    {
        if ($this->interactive) {
            return Console::prompt($text, $options);
        } else {
            return isset($options['default']) ? $options['default'] : '';
        }
    }

    /**
     * Asks user to confirm by typing y or n.
     *
     * @param  string  $message to echo out before waiting for user input
     * @param  boolean $default this value is returned if no selection is made.
     * @return boolean whether user confirmed.
     *                         Will return true if [[interactive]] is false.
     */
    public function confirm($message, $default = false)
    {
        if ($this->interactive) {
            return Console::confirm($message, $default);
        } else {
            return true;
        }
    }

    /**
     * Gives the user an option to choose from. Giving '?' as an input will show
     * a list of options to choose from and their explanations.
     *
     * @param string $prompt  the prompt message
     * @param array  $options Key-value array of options to choose from
     *
     * @return string An option character the user chose
     */
    public function select($prompt, $options = [])
    {
        return Console::select($prompt, $options);
    }

    /**
     * Returns the names of valid options for the action (id)
     * An option requires the existence of a public member variable whose
     * name is the option name.
     * Child classes may override this method to specify possible options.
     *
     * Note that the values setting via options are not available
     * until [[beforeAction()]] is being called.
     *
     * @param  string $id action name
     * @return array  the names of the options valid for the action
     */
    public function options($id)
    {
        // $id might be used in subclass to provide options specific to action id
        return ['color', 'interactive'];
    }
Zander Baldwin committed
275
}