1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
use Yii;
use yii\base\Action;
use yii\base\InlineAction;
use yii\base\InvalidRouteException;
use yii\helpers\Console;
/**
* Controller is the base class of console command classes.
*
* 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.
* The `yii` program is used when calling a console command, like the following:
*
* ~~~
* yii <route> [--param1=value1 --param2 ...]
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Controller extends \yii\base\Controller
{
/**
* @var boolean whether to run the command interactively.
*/
public $interactive = true;
/**
* @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;
/**
* 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;
}
/**
* 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.
* @see createAction
*/
public function runAction($id, $params = [])
{
if (!empty($params)) {
$options = $this->globalOptions();
foreach ($params as $name => $value) {
if (in_array($name, $options, true)) {
$this->$name = $value;
unset($params[$name]);
}
}
}
return parent::runAction($id, $params);
}
/**
* 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 [[globalOptions()|global 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)
{
$args = [];
if (!empty($params)) {
$options = $this->globalOptions();
foreach ($params as $name => $value) {
if (in_array($name, $options, true)) {
$this->$name = $value;
} elseif (is_int($name)) {
$args[] = $value;
} else {
throw new Exception(Yii::t('yii', 'Unknown option: --{name}', ['name' => $name]));
}
}
}
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
}
$missing = [];
foreach ($method->getParameters() as $i => $param) {
$name = $param->getName();
if (!isset($args[$i])) {
if ($param->isDefaultValueAvailable()) {
$args[$i] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
}
}
if (!empty($missing)) {
throw new Exception(Yii::t('yii', 'Missing required arguments: {params}', ['params' => implode(', ', $missing)]));
}
return $args;
}
/**
* 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);
}
return $string;
}
/**
* 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);
}
return Console::stdout($string);
}
/**
* 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);
}
return fwrite(STDERR, $string);
}
/**
* 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 the global options for this command.
* A global option requires the existence of a public member variable whose
* name is the option name.
* Child classes may override this method to specify possible global options.
*
* Note that the values setting via global options are not available
* until [[beforeAction()]] is being called.
*
* @return array the names of the global options for this command.
*/
public function globalOptions()
{
return ['color', 'interactive'];
}
}