Command.php 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. <?php
  2. namespace Illuminate\Console;
  3. use Illuminate\Support\Str;
  4. use Illuminate\Support\Traits\Macroable;
  5. use Illuminate\Contracts\Support\Arrayable;
  6. use Symfony\Component\Console\Helper\Table;
  7. use Symfony\Component\Console\Input\ArrayInput;
  8. use Symfony\Component\Console\Output\NullOutput;
  9. use Symfony\Component\Console\Question\Question;
  10. use Symfony\Component\Console\Input\InputInterface;
  11. use Symfony\Component\Console\Output\OutputInterface;
  12. use Symfony\Component\Console\Question\ChoiceQuestion;
  13. use Symfony\Component\Console\Formatter\OutputFormatterStyle;
  14. use Symfony\Component\Console\Command\Command as SymfonyCommand;
  15. class Command extends SymfonyCommand
  16. {
  17. use Macroable;
  18. /**
  19. * The Laravel application instance.
  20. *
  21. * @var \Illuminate\Contracts\Foundation\Application
  22. */
  23. protected $laravel;
  24. /**
  25. * The input interface implementation.
  26. *
  27. * @var \Symfony\Component\Console\Input\InputInterface
  28. */
  29. protected $input;
  30. /**
  31. * The output interface implementation.
  32. *
  33. * @var \Illuminate\Console\OutputStyle
  34. */
  35. protected $output;
  36. /**
  37. * The name and signature of the console command.
  38. *
  39. * @var string
  40. */
  41. protected $signature;
  42. /**
  43. * The console command name.
  44. *
  45. * @var string
  46. */
  47. protected $name;
  48. /**
  49. * The console command description.
  50. *
  51. * @var string
  52. */
  53. protected $description;
  54. /**
  55. * Indicates whether the command should be shown in the Artisan command list.
  56. *
  57. * @var bool
  58. */
  59. protected $hidden = false;
  60. /**
  61. * The default verbosity of output commands.
  62. *
  63. * @var int
  64. */
  65. protected $verbosity = OutputInterface::VERBOSITY_NORMAL;
  66. /**
  67. * The mapping between human readable verbosity levels and Symfony's OutputInterface.
  68. *
  69. * @var array
  70. */
  71. protected $verbosityMap = [
  72. 'v' => OutputInterface::VERBOSITY_VERBOSE,
  73. 'vv' => OutputInterface::VERBOSITY_VERY_VERBOSE,
  74. 'vvv' => OutputInterface::VERBOSITY_DEBUG,
  75. 'quiet' => OutputInterface::VERBOSITY_QUIET,
  76. 'normal' => OutputInterface::VERBOSITY_NORMAL,
  77. ];
  78. /**
  79. * Create a new console command instance.
  80. *
  81. * @return void
  82. */
  83. public function __construct()
  84. {
  85. // We will go ahead and set the name, description, and parameters on console
  86. // commands just to make things a little easier on the developer. This is
  87. // so they don't have to all be manually specified in the constructors.
  88. if (isset($this->signature)) {
  89. $this->configureUsingFluentDefinition();
  90. } else {
  91. parent::__construct($this->name);
  92. }
  93. // Once we have constructed the command, we'll set the description and other
  94. // related properties of the command. If a signature wasn't used to build
  95. // the command we'll set the arguments and the options on this command.
  96. $this->setDescription($this->description);
  97. $this->setHidden($this->hidden);
  98. if (! isset($this->signature)) {
  99. $this->specifyParameters();
  100. }
  101. }
  102. /**
  103. * Configure the console command using a fluent definition.
  104. *
  105. * @return void
  106. */
  107. protected function configureUsingFluentDefinition()
  108. {
  109. list($name, $arguments, $options) = Parser::parse($this->signature);
  110. parent::__construct($this->name = $name);
  111. // After parsing the signature we will spin through the arguments and options
  112. // and set them on this command. These will already be changed into proper
  113. // instances of these "InputArgument" and "InputOption" Symfony classes.
  114. foreach ($arguments as $argument) {
  115. $this->getDefinition()->addArgument($argument);
  116. }
  117. foreach ($options as $option) {
  118. $this->getDefinition()->addOption($option);
  119. }
  120. }
  121. /**
  122. * Specify the arguments and options on the command.
  123. *
  124. * @return void
  125. */
  126. protected function specifyParameters()
  127. {
  128. // We will loop through all of the arguments and options for the command and
  129. // set them all on the base command instance. This specifies what can get
  130. // passed into these commands as "parameters" to control the execution.
  131. foreach ($this->getArguments() as $arguments) {
  132. call_user_func_array([$this, 'addArgument'], $arguments);
  133. }
  134. foreach ($this->getOptions() as $options) {
  135. call_user_func_array([$this, 'addOption'], $options);
  136. }
  137. }
  138. /**
  139. * Run the console command.
  140. *
  141. * @param \Symfony\Component\Console\Input\InputInterface $input
  142. * @param \Symfony\Component\Console\Output\OutputInterface $output
  143. * @return int
  144. */
  145. public function run(InputInterface $input, OutputInterface $output)
  146. {
  147. return parent::run(
  148. $this->input = $input, $this->output = new OutputStyle($input, $output)
  149. );
  150. }
  151. /**
  152. * Execute the console command.
  153. *
  154. * @param \Symfony\Component\Console\Input\InputInterface $input
  155. * @param \Symfony\Component\Console\Output\OutputInterface $output
  156. * @return mixed
  157. */
  158. protected function execute(InputInterface $input, OutputInterface $output)
  159. {
  160. return $this->laravel->call([$this, 'handle']);
  161. }
  162. /**
  163. * Call another console command.
  164. *
  165. * @param string $command
  166. * @param array $arguments
  167. * @return int
  168. */
  169. public function call($command, array $arguments = [])
  170. {
  171. $arguments['command'] = $command;
  172. return $this->getApplication()->find($command)->run(
  173. $this->createInputFromArguments($arguments), $this->output
  174. );
  175. }
  176. /**
  177. * Call another console command silently.
  178. *
  179. * @param string $command
  180. * @param array $arguments
  181. * @return int
  182. */
  183. public function callSilent($command, array $arguments = [])
  184. {
  185. $arguments['command'] = $command;
  186. return $this->getApplication()->find($command)->run(
  187. $this->createInputFromArguments($arguments), new NullOutput
  188. );
  189. }
  190. /**
  191. * Create an input instance from the given arguments.
  192. *
  193. * @param array $arguments
  194. * @return \Symfony\Component\Console\Input\ArrayInput
  195. */
  196. protected function createInputFromArguments(array $arguments)
  197. {
  198. return tap(new ArrayInput($arguments), function ($input) {
  199. if ($input->hasParameterOption(['--no-interaction'], true)) {
  200. $input->setInteractive(false);
  201. }
  202. });
  203. }
  204. /**
  205. * Determine if the given argument is present.
  206. *
  207. * @param string|int $name
  208. * @return bool
  209. */
  210. public function hasArgument($name)
  211. {
  212. return $this->input->hasArgument($name);
  213. }
  214. /**
  215. * Get the value of a command argument.
  216. *
  217. * @param string|null $key
  218. * @return string|array
  219. */
  220. public function argument($key = null)
  221. {
  222. if (is_null($key)) {
  223. return $this->input->getArguments();
  224. }
  225. return $this->input->getArgument($key);
  226. }
  227. /**
  228. * Get all of the arguments passed to the command.
  229. *
  230. * @return array
  231. */
  232. public function arguments()
  233. {
  234. return $this->argument();
  235. }
  236. /**
  237. * Determine if the given option is present.
  238. *
  239. * @param string $name
  240. * @return bool
  241. */
  242. public function hasOption($name)
  243. {
  244. return $this->input->hasOption($name);
  245. }
  246. /**
  247. * Get the value of a command option.
  248. *
  249. * @param string|null $key
  250. * @return string|array
  251. */
  252. public function option($key = null)
  253. {
  254. if (is_null($key)) {
  255. return $this->input->getOptions();
  256. }
  257. return $this->input->getOption($key);
  258. }
  259. /**
  260. * Get all of the options passed to the command.
  261. *
  262. * @return array
  263. */
  264. public function options()
  265. {
  266. return $this->option();
  267. }
  268. /**
  269. * Confirm a question with the user.
  270. *
  271. * @param string $question
  272. * @param bool $default
  273. * @return bool
  274. */
  275. public function confirm($question, $default = false)
  276. {
  277. return $this->output->confirm($question, $default);
  278. }
  279. /**
  280. * Prompt the user for input.
  281. *
  282. * @param string $question
  283. * @param string|null $default
  284. * @return string
  285. */
  286. public function ask($question, $default = null)
  287. {
  288. return $this->output->ask($question, $default);
  289. }
  290. /**
  291. * Prompt the user for input with auto completion.
  292. *
  293. * @param string $question
  294. * @param array $choices
  295. * @param string|null $default
  296. * @return string
  297. */
  298. public function anticipate($question, array $choices, $default = null)
  299. {
  300. return $this->askWithCompletion($question, $choices, $default);
  301. }
  302. /**
  303. * Prompt the user for input with auto completion.
  304. *
  305. * @param string $question
  306. * @param array $choices
  307. * @param string|null $default
  308. * @return string
  309. */
  310. public function askWithCompletion($question, array $choices, $default = null)
  311. {
  312. $question = new Question($question, $default);
  313. $question->setAutocompleterValues($choices);
  314. return $this->output->askQuestion($question);
  315. }
  316. /**
  317. * Prompt the user for input but hide the answer from the console.
  318. *
  319. * @param string $question
  320. * @param bool $fallback
  321. * @return string
  322. */
  323. public function secret($question, $fallback = true)
  324. {
  325. $question = new Question($question);
  326. $question->setHidden(true)->setHiddenFallback($fallback);
  327. return $this->output->askQuestion($question);
  328. }
  329. /**
  330. * Give the user a single choice from an array of answers.
  331. *
  332. * @param string $question
  333. * @param array $choices
  334. * @param string|null $default
  335. * @param mixed|null $attempts
  336. * @param bool|null $multiple
  337. * @return string
  338. */
  339. public function choice($question, array $choices, $default = null, $attempts = null, $multiple = null)
  340. {
  341. $question = new ChoiceQuestion($question, $choices, $default);
  342. $question->setMaxAttempts($attempts)->setMultiselect($multiple);
  343. return $this->output->askQuestion($question);
  344. }
  345. /**
  346. * Format input to textual table.
  347. *
  348. * @param array $headers
  349. * @param \Illuminate\Contracts\Support\Arrayable|array $rows
  350. * @param string $tableStyle
  351. * @param array $columnStyles
  352. * @return void
  353. */
  354. public function table($headers, $rows, $tableStyle = 'default', array $columnStyles = [])
  355. {
  356. $table = new Table($this->output);
  357. if ($rows instanceof Arrayable) {
  358. $rows = $rows->toArray();
  359. }
  360. $table->setHeaders((array) $headers)->setRows($rows)->setStyle($tableStyle);
  361. foreach ($columnStyles as $columnIndex => $columnStyle) {
  362. $table->setColumnStyle($columnIndex, $columnStyle);
  363. }
  364. $table->render();
  365. }
  366. /**
  367. * Write a string as information output.
  368. *
  369. * @param string $string
  370. * @param null|int|string $verbosity
  371. * @return void
  372. */
  373. public function info($string, $verbosity = null)
  374. {
  375. $this->line($string, 'info', $verbosity);
  376. }
  377. /**
  378. * Write a string as standard output.
  379. *
  380. * @param string $string
  381. * @param string $style
  382. * @param null|int|string $verbosity
  383. * @return void
  384. */
  385. public function line($string, $style = null, $verbosity = null)
  386. {
  387. $styled = $style ? "<$style>$string</$style>" : $string;
  388. $this->output->writeln($styled, $this->parseVerbosity($verbosity));
  389. }
  390. /**
  391. * Write a string as comment output.
  392. *
  393. * @param string $string
  394. * @param null|int|string $verbosity
  395. * @return void
  396. */
  397. public function comment($string, $verbosity = null)
  398. {
  399. $this->line($string, 'comment', $verbosity);
  400. }
  401. /**
  402. * Write a string as question output.
  403. *
  404. * @param string $string
  405. * @param null|int|string $verbosity
  406. * @return void
  407. */
  408. public function question($string, $verbosity = null)
  409. {
  410. $this->line($string, 'question', $verbosity);
  411. }
  412. /**
  413. * Write a string as error output.
  414. *
  415. * @param string $string
  416. * @param null|int|string $verbosity
  417. * @return void
  418. */
  419. public function error($string, $verbosity = null)
  420. {
  421. $this->line($string, 'error', $verbosity);
  422. }
  423. /**
  424. * Write a string as warning output.
  425. *
  426. * @param string $string
  427. * @param null|int|string $verbosity
  428. * @return void
  429. */
  430. public function warn($string, $verbosity = null)
  431. {
  432. if (! $this->output->getFormatter()->hasStyle('warning')) {
  433. $style = new OutputFormatterStyle('yellow');
  434. $this->output->getFormatter()->setStyle('warning', $style);
  435. }
  436. $this->line($string, 'warning', $verbosity);
  437. }
  438. /**
  439. * Write a string in an alert box.
  440. *
  441. * @param string $string
  442. * @return void
  443. */
  444. public function alert($string)
  445. {
  446. $length = Str::length(strip_tags($string)) + 12;
  447. $this->comment(str_repeat('*', $length));
  448. $this->comment('* '.$string.' *');
  449. $this->comment(str_repeat('*', $length));
  450. $this->output->newLine();
  451. }
  452. /**
  453. * Set the verbosity level.
  454. *
  455. * @param string|int $level
  456. * @return void
  457. */
  458. protected function setVerbosity($level)
  459. {
  460. $this->verbosity = $this->parseVerbosity($level);
  461. }
  462. /**
  463. * Get the verbosity level in terms of Symfony's OutputInterface level.
  464. *
  465. * @param string|int|null $level
  466. * @return int
  467. */
  468. protected function parseVerbosity($level = null)
  469. {
  470. if (isset($this->verbosityMap[$level])) {
  471. $level = $this->verbosityMap[$level];
  472. } elseif (! is_int($level)) {
  473. $level = $this->verbosity;
  474. }
  475. return $level;
  476. }
  477. /**
  478. * Get the console command arguments.
  479. *
  480. * @return array
  481. */
  482. protected function getArguments()
  483. {
  484. return [];
  485. }
  486. /**
  487. * Get the console command options.
  488. *
  489. * @return array
  490. */
  491. protected function getOptions()
  492. {
  493. return [];
  494. }
  495. /**
  496. * Get the output implementation.
  497. *
  498. * @return \Symfony\Component\Console\Output\OutputInterface
  499. */
  500. public function getOutput()
  501. {
  502. return $this->output;
  503. }
  504. /**
  505. * Get the Laravel application instance.
  506. *
  507. * @return \Illuminate\Contracts\Foundation\Application
  508. */
  509. public function getLaravel()
  510. {
  511. return $this->laravel;
  512. }
  513. /**
  514. * Set the Laravel application instance.
  515. *
  516. * @param \Illuminate\Contracts\Container\Container $laravel
  517. * @return void
  518. */
  519. public function setLaravel($laravel)
  520. {
  521. $this->laravel = $laravel;
  522. }
  523. }