If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWe have a new console command! But... it doesn't do much yet, aside from printing out a message. Let's make it fancier.
Scroll to the top. This is where we have the name of our command, and there's also a description... which shows up next to the command. Let me change ours to
A self-aware command that can do... only one thing.
... lines 1 - 12 | |
( | |
... line 14 | |
description: 'A self-aware command that can do... only one thing.', | |
) | |
class TalkToMeCommand extends Command | |
{ | |
... lines 19 - 43 | |
} |
Our command is called app:talk-to-me
because, when we run this, I want to make it possible to pass a name to the command - like Ryan - and then it'll reply with "Hey Ryan!". So, literally, we'll type bin/console app:talk-to-me ryan
and it'll reply back.
When you want to pass a value to a command, that's known as an argument... and those are configured down in... the configure()
method. There's already an argument called arg1
... so let's change that to name
.
This key is completely internal: you'll never see the word name
when you're using this command. But we will use this key to read the argument value in a minute. We can also give the argument a description and, if you want, you can make it required. I'll keep it as optional.
The next thing we have are options. These are like arguments... except that they start with a --
when you use them. I want to have an optional flag where we can say --yell
to make the command yell our name back.
In this case, the name of the option, yell
, is important: we will use this name when passing the option at the command line to use it. The InputOption::VALUE_NONE
means that our flag will just be --yell
and not --yell=
some value. If your option accepts a value, you would change this to VALUE_REQUIRED
. Finally, give this a description.
... lines 1 - 16 | |
class TalkToMeCommand extends Command | |
{ | |
protected function configure(): void | |
{ | |
$this | |
->addArgument('name', InputArgument::OPTIONAL, 'Your name') | |
->addOption('yell', null, InputOption::VALUE_NONE, 'Shall I yell?') | |
; | |
} | |
... lines 26 - 43 | |
} |
Beautiful! We're not using this argument and option yet... but we can already re-run our command with a --help
option:
php bin/console app:talk-to-me --help
And... awesome! We see the description up here... along with some details about how to use the argument and the --yell
option.
When we call our command, very simply, Symfony will call execute()
... which is where the fun starts. Inside, we can do whatever we want. It passes us two arguments: $input
and $output
. If you want to read some input - like the name
argument or the yell
option, use $input
. And if you want to output something, use $output
.
But in Symfony, we normally pop these two things into another object called SymfonyStyle
. This is helper class makes reading and outputing easier... and fancier.
Ok: let's start by saying $name = $input->getArgument('name')
. If we don't have a name, I'll default this to whoever you are
. Below, read the option: $shouldYell = $input->getOption('yell')
:
... lines 1 - 16 | |
class TalkToMeCommand extends Command | |
{ | |
... lines 19 - 26 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
$io = new SymfonyStyle($input, $output); | |
$name = $input->getArgument('name') ?: 'whoever you are'; | |
$shouldYell = $input->getOption('yell'); | |
... lines 32 - 40 | |
} | |
} |
Cool. Let's clear out this stuff down here and start our message: $message = sprintf('Hey %s!', $name)
. Then if we want to yell, you know what to do: $message = strtoupper($message)
. Below, use $io->success()
and put the message there.
... lines 1 - 16 | |
class TalkToMeCommand extends Command | |
{ | |
... lines 19 - 26 | |
protected function execute(InputInterface $input, OutputInterface $output): int | |
{ | |
$io = new SymfonyStyle($input, $output); | |
$name = $input->getArgument('name') ?: 'whoever you are'; | |
$shouldYell = $input->getOption('yell'); | |
$message = sprintf('Hey %s!', $name); | |
if ($shouldYell) { | |
$message = strtoupper($message); | |
} | |
$io->success($message); | |
return Command::SUCCESS; | |
} | |
} |
This is one of the many helper methods on the SymfonyStyle
class that help format your output. There's also $io->warning()
, $io->note()
, and several others.
Let's try it. Spin over and run:
php bin/console app:talk-to-me ryan
And... oh hello there! If we yell:
php bin/console app:talk-to-me ryan --yell
THAT WORKS TOO! We can even yell at 'whoever I am':
php bin/console app:talk-to-me --yell
Awesome! But let's get crazier... by autowiring a service and asking a question interactively on the command line. That's next... and it's the last chapter!
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"knplabs/knp-time-bundle": "^1.18", // v1.19.0
"symfony/asset": "6.1.*", // v6.1.0-RC1
"symfony/console": "6.1.*", // v6.1.0-RC1
"symfony/dotenv": "6.1.*", // v6.1.0-RC1
"symfony/flex": "^2", // v2.1.8
"symfony/framework-bundle": "6.1.*", // v6.1.0-RC1
"symfony/http-client": "6.1.*", // v6.1.0-RC1
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/runtime": "6.1.*", // v6.1.0-RC1
"symfony/twig-bundle": "6.1.*", // v6.1.0-RC1
"symfony/ux-turbo": "^2.0", // v2.1.1
"symfony/webpack-encore-bundle": "^1.13", // v1.14.1
"symfony/yaml": "6.1.*", // v6.1.0-RC1
"twig/extra-bundle": "^2.12|^3.0", // v3.4.0
"twig/twig": "^2.12|^3.0" // v3.4.0
},
"require-dev": {
"symfony/debug-bundle": "6.1.*", // v6.1.0-RC1
"symfony/maker-bundle": "^1.41", // v1.42.0
"symfony/stopwatch": "6.1.*", // v6.1.0-RC1
"symfony/web-profiler-bundle": "6.1.*" // v6.1.0-RC1
}
}