Введення консолі (аргументи та опції)
Дата оновлення перекладу 2024-05-09
Введення консолі (аргументи та опції)
Найцікавішою частиною команд є аргументи та опції, які ви можете зробити доступними. Ці аргументи та опції дозволяють вам передавати динамічну інформацію з терміналу в команду.
Використання аргументів команд
Аргументи - це рядки, розділені пробілами, які йдуть після самого імені команди.
Вони впорядковані та можуть бути обовʼязковими або необовʼязковими. Наприклад, щоб
додати необовʼязковий аргумент last_name
в команду і зробити аргумент name
обовʼязковим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
class GreetCommand extends Command
{
// ...
protected function configure(): void
{
$this
// ...
->addArgument('name', InputArgument::REQUIRED, 'Who do you want to greet?')
->addArgument('last_name', InputArgument::OPTIONAL, 'Your last name?')
;
}
}
Тепер у вас є доступ до аргументу last_name
у вашій команді:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class GreetCommand extends Command
{
// ...
protected function execute(InputInterface $input, OutputInterface $output): int
{
$text = 'Hi '.$input->getArgument('name');
$lastName = $input->getArgument('last_name');
if ($lastName) {
$text .= ' '.$lastName;
}
$output->writeln($text.'!');
return Command::SUCCESS;
}
}
Тепер команда може бути використана будь-яким з наступних способів:
1 2 3 4 5
$ php bin/console app:greet Fabien
Привіт, Фабієн!
$ php bin/console app:greet Fabien Potencier
Привіт, Фабієн Потенсьє!
Також можливо дозволити аргументи використовувати список значень (уявіть, що ви хочете привітатися з усіма вашими друзями). Лише останній аргумент може бути списком:
1 2 3 4 5 6 7 8
$this
// ...
->addArgument(
'names',
InputArgument::IS_ARRAY,
'З ким ви хочете привітатися (розділіть декілька імен пробілами)?'
)
;
Щоб використати це, просто вкажіть стільки імен, скільки хочете:
1
$ php bin/console app:greet Fabien Ryan Bernhard
Ви можете отримати доступ до аргументу names
, як до масиву:
1 2 3 4
$names = $input->getArgument('names');
if (count($names) > 0) {
$text .= ' '.implode(', ', $names);
}
Існує три варіанти аргументів, які ви можете використати:
InputArgument::REQUIRED
- Аргумент обовʼязковий. Команда не буде виконана, якщо цього аргументу немає;
InputArgument::OPTIONAL
- Аргумент необовʼязковий і тому може бути опущений. Це поведінка аргументу за замовчуванням;
InputArgument::IS_ARRAY
- Аргумент може містити будь-яку кількість значень. З цієї причини, він може бути використаний наприкінці списку аргументів.
Ви можете комбінувати IS_ARRAY
з REQUIRED
і OPTIONAL
таким чином:
1 2 3 4 5 6 7
$this
// ...
->addArgument(
'names',
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
'С кем вы хотите поздороваться (разделите несколько имён пробелом)?'
);
Використання опцій команд
На відміну від аргументів, опції не впорядковані (тобто ви можете вказувати їх
у будь-якому порядку) і вказуються з двома дефісами (наприклад, --yell
).
Опції завжди обовʼязкові і можуть бути налаштовані так, щоб приймати значення
(наприклад, --dir=src
) або просто як булевий прапорець без значення (наприклад,
--yell
).
Наприклад, додайте нову опцію до команди, яка може бути використана для вказання того, скільки разів поспіль повинно бути надруковане повідомлення:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// ...
use Symfony\Component\Console\Input\InputOption;
$this
// ...
->addOption(
// це імʼя, яке користувачі повинні надрукувати, щоб передати цю опцію (наприклад, --iterations=5)
'iterations',
// це необовʼязкове скорочення імені опції, яке зазвичай є просто літерою
// (наприклад, `i`, щоб користувачі передавали його як `-i`); використовуйте це для часто використовуваних опцій
// або опцій з довгими іменами
null,
// це тип опції (наприклад, вимагає значення, може бути передана більше одного разу, та ін.)
InputOption::VALUE_REQUIRED,
// опис опції, відображений при відображенні допомоги команди
'Скільки разів має бути надруковане повідомлення?',
// значення опції за замовчуванням (для тих, які дозволяють передачу значень)
1
)
;
Далі, використайте це в команді, щоб надрукувати повідомленння декілька разів:
1 2 3
for ($i = 0; $i < $input->getOption('iterations'); $i++) {
$output->writeln($text);
}
Тепер, коли ви виконаєте команду, ви можете за бажанням вказати прапорець
--iterations
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# не надано --iterations, використовується (1) за замовчуванням
$ php bin/console app:greet Fabien
Привіт, Фабієн!
$ php bin/console app:greet Fabien --iterations=5
Привіт, Фабієн!
Привіт, Фабієн!
Привіт, Фабієн!
Привіт, Фабієн!
Привіт, Фабієн!
# порядок опцій неважливий
$ php bin/console app:greet Fabien --iterations=5 --yell
$ php bin/console app:greet Fabien --yell --iterations=5
$ php bin/console app:greet --yell --iterations=5 Fabien
Tip
Ви також можете оголосити скорочення з однієї літери, яке ви можете викликати
за допомогою одного дефісу, наприклад, -i
:
1 2 3 4 5 6 7 8 9 10
$this
// ...
->addOption(
'iterations',
'i',
InputOption::VALUE_REQUIRED,
'Скільки разів має бути надруковане повідомлення?',
1
)
;
Відмітьте, що щоб відповідати стандарту docopt, довгі опції можуть вказувати свої
значення після пробілу або знаку =
(наприклад, --iterations 5
або
--iterations=5
), але короткі опції можуть використовувати лише пробіли або взагалі
не використовувати ніякого розділювача (наприклад, -i 5
або -i5
).
Caution
Хоча можливо відділити опцію від її значення за допомогою пробілу, використання
цієї форми призводить до двозначності, якщо опція зʼявляється перед іменем команди.
Наприклад, php bin/console --iterations 5 app:greet Fabien
двозначна; Symfony
інтерпретує 5
як імʼя команди. Щоб уникнути такої ситуації, завжди розміщуйте
опції після імені команди, або уникайте використання пробілу для відділення імʼя
опції від її значення.
Існує пʼять варіантів опцій, які ви можете використовувати:
InputOption::VALUE_IS_ARRAY
-
Ця опція примає декілька значень (наприклад,
--dir=/foo --dir=/bar
); InputOption::VALUE_NONE
-
Не приймає введення для цієї опції (наприклад,
--yell
). Це поведінка опцій за замовчуванням; InputOption::VALUE_REQUIRED
-
Це значення обовʼязкове (наприклад,
--iterations=5
), але сама опція все ще не є обовʼязковою; InputOption::VALUE_OPTIONAL
-
Ця опція може мати або не мати значення (наприклад,
--yell
або--yell=loud
). InputOption::VALUE_NEGATABLE
-
Приймає або прапорець (наприклад,
--yell
) або його інверсію (наприклад,--no-yell
).
Ви маєте комбінувати VALUE_IS_ARRAY
з VALUE_REQUIRED
або
VALUE_OPTIONAL
таким чином:
1 2 3 4 5 6 7 8 9 10
$this
// ...
->addOption(
'colors',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Які кольори вам подобаються?',
['blue', 'red']
)
;
Опції з необовʼязковими аргументами
Вам нічого не забороняє створити команду з опцією, яка опціонально приймає значення, але це трохи складно. Розгляньте цей приклад:
1 2 3 4 5 6 7 8 9 10 11 12
// ...
use Symfony\Component\Console\Input\InputOption;
$this
// ...
->addOption(
'yell',
null,
InputOption::VALUE_OPTIONAL,
'Мені кричати при привітанні?'
)
;
Ця опція може бути використана трьома способами: greet --yell
, greet --yell=louder
,
та greet
. Однак, важко розрізнити передачу опції без значення (greet --yell
)
і відсутність передачі опції (greet
).
Щоб вирішити цю проблему, вам потрібно встановити значення опції за замовчуванням як
false
:
1 2 3 4 5 6 7 8 9 10 11 12 13
// ...
use Symfony\Component\Console\Input\InputOption;
$this
// ...
->addOption(
'yell',
null,
InputOption::VALUE_OPTIONAL,
'Мені кричати при привітанні?',
false // це нове значення за замовчуванням замість null
)
;
Тепер можливо розрізнювати відсутність передачі опції та відсутність передачі значення для неї:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$optionValue = $input->getOption('yell');
if (false === $optionValue) {
// в цьому випадку, опція не була передана при виконанні команди
$yell = false;
$yellLouder = false;
} elseif (null === $optionValue) {
// в цьому випадку, опція була передана при виконанні команди, але
// їй не було надано значення
$yell = true;
$yellLouder = false;
} else {
// в цьому випадку, опція була передана при виконанні команди і їй
// було надане якесь конкретне значення
$yell = true;
if ('louder' === $optionValue) {
$yellLouder = true;
} else {
$yellLouder = false;
}
}
Код вище можна спростити таким чином, так як false !== null
:
1 2 3
$optionValue = $input->getOption('yell');
$yell = ($optionValue !== false);
$yellLouder = ($optionValue === 'louder');
Додавання заповнення значень аргументів/опцій
Якщо встановлено заповнення Консолі , імена
команд та опцій будуть автоматично заповнені оболонкою. Однак, ви також можете реалізувати
заповнення значеня для введення у ваших командах. Наприклад, ви можете захотіти
заповнити всі імена користувачів з бази даних в аргументі name
вашої команди
привітання.
Щоб досягти цього, використайте 5ий аргумент addArgument()
/addOption
:
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
// ...
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
class GreetCommand extends Command
{
// ...
protected function configure(): void
{
$this
->addArgument(
'names',
InputArgument::IS_ARRAY,
'Кого ви хочете привітати (розділіть багато імен пробілами)?',
null,
function (CompletionInput $input): array {
// значення користувача вже надруковано, наприклад, при введенні "app:greet Fa" до
// натискання Tab, це міститиме "Fa"
$currentValue = $input->getCompletionValue();
// отримати список імен користувачів звідкись (наприклад, база даних)
// ви можете використати $currentValue, щоб відфільтрувати імена
$availableUsernames = ...;
// потім запропоновані імена користувачів як значення
return $availableUsernames;
}
)
;
}
}
Це все, що вам потрібно! Припускаючи, що "Fabien" та "Fabrice" існують, натискання
табу після введення app:greet Fa
надасть вам ці імена в якості пропозиції.
Tip
Скрипт оболонки доступний для обробки величезної кількості пропозицій та автоматично відфільтрує запропоновані значення, засновуючись на існуючому введенні від користувача. Вам не потрібно реалізовувати ніякої логіки фільтрації у команді.
Ви можете використати CompletionInput::getCompletionValue()
, щоб отримати
поточне введення, якщо це допоможе покращити продуктивність (наприклад, зменшивши
кількість рядків, вилучених з бази даних).
Тестування скрипту заповнення
Компонент Консоль постачається зі спеціальним класом CommandCompletionTester щоб допомогти вам модульно тестувати логіку заповнення:
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
// ...
use Symfony\Component\Console\Application;
class GreetCommandTest extends TestCase
{
public function testComplete(): void
{
$application = new Application();
$application->add(new GreetCommand());
// створіть нового тестувальника з командою привітання
$tester = new CommandCompletionTester($application->get('app:greet'));
// закінчіть введення без існуючого введення (пустий рядок представляє
// позицію курсору)
$suggestions = $tester->complete(['']);
$this->assertSame(['Fabien', 'Fabrice', 'Wouter'], $suggestions);
// Якщо ви відфільтруєте значення всередині вашого коду (не рекомендовано, якщо вам не
// треба покращити продуктивність, наприклад, запиту бази даних), ви можете протестувати
// це, передавши введення користувача
$suggestions = $tester->complete(['Fa']);
$this->assertSame(['Fabien', 'Fabrice'], $suggestions);
}
}
Глобальні опції команди
Компонент Console додає деякі попередньо визначені опції до всіх команд:
--verbose
: встановлює рівень багатослівності (наприклад,1
за замовчуванням,2
і3
, або ви можете використовувати відповідні комбінації клавіш-v
,-vv
та-vvv
)--quiet
: вимикає виведення та взаємодію--no-interaction
: вимикає взаємодію--version
: виводить номер версії консольного додатку--help
: виводить довідку до команди--ansi|--no-ansi
: чи примусово вимикати розфарбовування виведення
При використанні FrameworkBundle
попередньо визначено ще дві опції:
--env
: встановлює середовище конфігурації ядра (за замовчуваннямAPP_ENV
)--no-debug
: вимикає налагодження ядра (за замовчуваннямAPP_DEBUG
)
Таким чином, ваші користувацькі команди також можуть використовувати їх одразу після установки.