An Interest In:
Web News this Week
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
- March 26, 2024
- March 25, 2024
How to Create Custom CLI Commands Using the Symfony Console Component
In this article, we're going to explore how you could create custom command-line interface (CLI) commands in your PHP applications using the Symfony Console component. After installing necessary libraries, we'll create a few handful of examples to demonstrate the concepts of the Console component.
In fact, this component is used by several PHP frameworks to develop CLI applications, and a few popular frameworks are already using this component as a starting point.
What Is the Console Component?
The Symfony Console component allows you to create custom CLI commands in your PHP applications. If you have ever worked with Laravel or Symfony, you might be aware of the CLI tools they provide in order to ease day-to-day operations like:
- generating scaffolding code
- clearing caches
- installing, enabling and disabling add-on services
- running database migrations
- and more
In the case of Laravel, for example, it comes with the artisan
tool which provides plenty of utility commands that make our life easier. You may be surprised to know that the artisan
tool is built on top of the Symfony Console component itself! In fact, there are many frameworks that leverage the Console component to build their command-line tools.
In this article, we're going to explore the basics of the Console component so that you can create custom CLI commands in your PHP applications. To start with, we'll go ahead and install the Console component using Composer. After installation, we'll build a few examples for demonstration purposes.
Installation and Configuration
In this section, we're going to install the Console component which is required in order to create CLI commands in your PHP applications. I assume that you've installed Composer in your system—we'll need it to install the Console component which is available from Packagist.
Once you've installed Composer, go ahead and install the Console component using the following command.
$composer require symfony/console
That should have created the composer.json file, which should look like this:
{
"require": {
"symfony/console": "^5.4"
}
}
Let's modify the composer.json file to look like the following one:
{
"require": {
"symfony/console": "^5.4"
},
"autoload": {
"psr-4": {
"Console\\": "src"
},
"classmap": ["src"]
}
}
As we've added a new classmap
entry, let's go ahead and update the Composer autoloader by running the following command.
$composer dump -o
Now, you can use the Console
namespace to autoload classes under the src directory.
Your First HelloWorld Command
Creating CLI commands using the Console component is a two-step process.
- First, you need to create a console application which loads the necessary dependencies and registers your custom commands.
- Next, you need to create separate files for all commands that you have registered with the console application.
Create the Console Application
In this section, we'll go ahead and create our custom console application.
The proposed directory structure of our console application looks like this.
|-- bin
| `-- console
|-- composer.json
|-- composer.lock
|-- src
| `-- App
| `-- Commands
| |-- ClearcacheCommand.php
| `-- HelloworldCommand.php
`-- vendor
Go ahead and create the main application file bin/console with the following contents. Please note that there's no file extension, and also make sure that it's executable as well since we'll need to run it from the command line.
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
$app = new Application();
$app->run();
The first line in the file #!/usr/bin/env php
makes sure that it's run under the PHP environment. Go ahead and try to run it and see how it goes.
$bin/console
Console Tool
Usage:
command [options] [arguments]
Options:
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
completion Dump the shell completion script
help Display help for a command
list List commands
Not bad! With just a few lines of code, you have a custom console application rolling at your disposal! But it's not doing anything useful at the moment. In the next section, we'll see how you can create custom commands and register it with our custom console application.
Create the Hello World Command File
Let's go ahead and create our first custom command: HelloworldCommand
. Create the src/App/Commands/HelloworldCommand.php file with the following contents.
<?php
namespace Console\App\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
class HelloworldCommand extends Command
{
protected function configure()
{
$this->setName('hello-world')
->setDescription('Prints Hello-World!')
->setHelp('Demonstration of custom commands created by Symfony Console component.')
->addArgument('username', InputArgument::REQUIRED, 'Pass the username.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln(sprintf('Hello World!, %s', $input->getArgument('username')));
return Command::SUCCESS;
}
}
There are two main methods that you should create while creating your custom command: configure
and execute
.
As the name suggests, the configure
method allows you to configure your command so that you can set up the command name, a short description of the command, help text, and more. You can also configure arguments for your command if you want to pass parameters while running a command.
In the above example, the command name is set to hello-world
. Also, we want to pass a username as the first argument, and hence we've configured it using the addArgument
method. Also, as we've passed InputArgument::REQUIRED
in the second argument, a user must pass this argument while executing this command, otherwise the command won't be executed and would result in an error.
On the other hand, the execute
method contains the application logic of the command. In our case, we've kept it pretty simple by displaying Hello World as the output of the command.
It's also important to note that the execute
method must return an integer which will be used as the command exit status. And thus, we've passed Command::SUCCESS
as the return value of this command, which indicates that the command was executed successfully. You can also use other available statuses like Command::FAILURE
and Command::INVALID
.
Before you can go ahead and actually run this command, you need to register it with the console application which we've created in the previous section. Let's quickly revise the bin/console file to look like the following one.
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
use Console\App\Commands\HelloworldCommand;
$app = new Application();
$app->add(new HelloworldCommand());
$app->run();
As you can see, we've used the add
method of the Application
object to add the HelloworldCommand
command. Let's quickly list all the available commands.
Console Tool
Usage:
command [options] [arguments]
Options:
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
completion Dump the shell completion script
hello-world Prints Hello-World!
help Display help for a command
list List commands
As expected, the hello-world
command appears in the list of available commands! Go ahead and run it!
$bin/console hello-world tutsplus
Hello World!, tutsplus
So that's how you can set up basic commands!
A Real-World Example—Clear Cache Command
In the previous section, we built the hello-world
command to demonstrate the concepts of the Console component. In this section, we'll go ahead and create a real-world example which demonstrates how you could build a command to clear caches in your application.
Create the Clear Cache Command File
Go ahead and create the src/App/Commands/ClearcacheCommand.php file with the following contents.
<?php
namespace Console\App\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ClearcacheCommand extends Command
{
protected function configure()
{
$this->setName('clear-cache')
->setDescription('Clears the application cache.')
->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.')
->addOption(
'groups',
'g',
InputOption::VALUE_OPTIONAL,
'Pass the comma separated group names if you don\'t want to clear all caches.',
''
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Cache is about to cleared...');
if ($input->getOption('groups'))
{
$groups = explode(",", $input->getOption('groups'));
if (is_array($groups) && count($groups))
{
foreach ($groups as $group)
{
$output->writeln(sprintf('%s cache is cleared', $group));
}
}
}
else
{
$output->writeln('All caches are cleared.');
}
$output->writeln('Complete.');
return Command::SUCCESS;
}
}
The configure
method is pretty much the same, except that we've used the addOption
method to add an option to our command. Thus, you could pass group values by using the --groups
parameter.
On the other hand, the execute
method contains the application logic of our command.
If you want to clear the cache of specific groups, you need to pass group names along with the --group
parameter. On the other hand, skip the --group
parameter if you want to clear all caches. You may have noticed that we've kept the --group
parameter optional by providing the InputOption::VALUE_OPTIONAL
value in the third argument of the addOption
method.
Registration and Testing With the Console Application
Before we go ahead and actually run it, let's register the command with our console application.
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
use Console\App\Commands\HelloworldCommand;
use Console\App\Commands\ClearcacheCommand;
$app = new Application();
$app->add(new HelloworldCommand());
$app->add(new ClearcacheCommand());
$app->run();
Now, go ahead and run the bin/console clear-cache
command to clear all caches!
$bin/console clear-cache
Cache is about to cleared...
All caches are cleared.
Complete.
Next, if you want to clear specific caches, you could try something like this.
$bin/console clear-cache --groups=group1,group2
Cache is about to cleared...
group1 cache is cleared
group2 cache is cleared
Complete.
Of course, you will need to implement the actual logic to clear caches, but that should serve as a good starting point.
How to Add a Progress Bar to Your Command
When you prepare commands that may take a long time to run, it's useful if you can show progress information about the process which is going on. In this section, we'll quickly see how you can add a progress bar to your commands.
We'll revisit the example which we've just discussed in the previous section. Let's go ahead and replace the src/App/Commands/ClearcacheCommand.php file with the following contents.
<?php
namespace Console\App\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Helper\ProgressBar;
class ClearcacheCommand extends Command
{
protected function configure()
{
$this->setName('clear-cache')
->setDescription('Clears the application cache.')
->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.')
->addOption(
'groups',
'g',
InputOption::VALUE_OPTIONAL,
'Pass the comma separated group names if you don\'t want to clear all caches.',
''
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
if ($input->getOption('groups'))
{
$groups = explode(",", $input->getOption('groups'));
$progressBar = new ProgressBar($output, count($groups));
$progressBar->start();
if (is_array($groups) && count($groups))
{
foreach ($groups as $group)
{
sleep(5);
$progressBar->advance();
}
}
$progressBar->finish();
}
else
{
$output->writeln('All caches are cleared.');
}
$output->writeln('');
return Command::SUCCESS;
}
}
First of all, it's important to note that we've used the Symfony\Component\Console\Helper\ProgressBar
class to implement the progress bar.
Next, we've initialized the progress bar with the following statement.
$progressBar = new ProgressBar($output, count($groups));
In the first argument, you need to pass the $output
object and the second argument is the total number of units the progress bar will be made of. In our case, we'll count the number of cache groups that a user wants to clear, and pass the same number in the second argument.
Next, you need to start the progress bar with the start
method. To advance a progress bar, you need to use the advance
method. Finally, it's the finish
method which completes the progress bar. So whenever a command is completed successfully, you can call this method so that the progress bar is refreshed with a 100% completion.
In our example, we've used the sleep
command so you can actually see the progress bar during command execution.
Go ahead and run the clear-cache
command as shown in the following snippet which should display the progress bar.
$bin/console clear-cache --groups=group1,group2,group3,group4,group5
5/5 [============================] 100%
As we've passed five groups in the --groups
option, the progress bar is initialized with five units. With our logic, the progress bar should be increased by 20% after every five seconds, and it'll reach to 100% after 25 seconds.
So that's how you can implement the progress bar with your commands.
Conclusion
Today, we went through one of the popular components provided by the Symfony framework: the Console Component. It's really a useful component should you wish to develop your own CLI application which helps you execute your day-to-day utility tasks with ease.
In the first half, we went through the installation and configuration of the component. Then, in the second half, we created a couple of examples of console commands.
Original Link: https://code.tutsplus.com/tutorials/how-to-create-custom-cli-commands-using-the-symfony-console-component--cms-31274
TutsPlus - Code
Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.More About this Source Visit TutsPlus - Code