Advertisement
  1. Code
  2. Coding Fundamentals
  3. Terminal and CLI

How to Create Custom CLI Commands Using the Symfony Console Component

Scroll to top
Read Time: 12 min

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 the necessary libraries, we'll create a few 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 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.

1
$composer require symfony/console

That should have created the composer.json file, which should look like this:

1
{
2
    "require": {
3
        "symfony/console": "^5.4"
4
    }
5
}

Let's modify the composer.json file to look like the following one:

1
{
2
    "require": {
3
        "symfony/console": "^5.4"
4
    },
5
    "autoload": {
6
         "psr-4": {
7
             "Console\\": "src"
8
         },
9
         "classmap": ["src"]
10
     }
11
}

As we've added a new classmap entry, let's go ahead and update the Composer autoloader by running the following command.

1
$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 the commands that you have registered with the console application.

Create the Console Application

In this section, we'll create our custom console application. The proposed directory structure of our console application looks like this.

1
|-- bin
2
|   `-- console
3
|-- composer.json
4
|-- composer.lock
5
|-- src
6
|   `-- App
7
|       `-- Commands
8
|           |-- ClearcacheCommand.php
9
|           `-- HelloworldCommand.php
10
`-- 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.

1
#!/usr/bin/env php
2
<?php
3
require_once __DIR__ . '/../vendor/autoload.php';
4
 
5
use Symfony\Component\Console\Application;
6
 
7
$app = new Application();
8
$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.

1
$bin/console
2
Console Tool
3
4
Usage:
5
  command [options] [arguments]
6
7
Options:
8
  -h, --help            Display help for the given command. When no command is given display help for the list command
9
  -q, --quiet           Do not output any message
10
  -V, --version         Display this application version
11
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
12
  -n, --no-interaction  Do not ask any interactive question
13
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
14
15
Available commands:
16
  completion  Dump the shell completion script
17
  help        Display help for a command

18
  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 them 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.

1
<?php
2
namespace Console\App\Commands;
3
 
4
use Symfony\Component\Console\Command\Command;
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Console\Input\InputArgument;
8
 
9
class HelloworldCommand extends Command
10
{
11
    protected function configure()
12
    {
13
        $this->setName('hello-world')
14
            ->setDescription('Prints Hello-World!')
15
            ->setHelp('Demonstration of custom commands created by Symfony Console component.')
16
            ->addArgument('username', InputArgument::REQUIRED, 'Pass the username.');
17
    }
18
 
19
    protected function execute(InputInterface $input, OutputInterface $output)
20
    {
21
        $output->writeln(sprintf('Hello World!, %s', $input->getArgument('username')));
22
        return Command::SUCCESS;
23
    }
24
}

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 run this command, you need to register it with the console application that we created in the previous section. Let's quickly revise the bin/console file to look like the following one.

1
#!/usr/bin/env php
2
<?php
3
require_once __DIR__ . '/../vendor/autoload.php';
4
 
5
use Symfony\Component\Console\Application;
6
use Console\App\Commands\HelloworldCommand;
7
 
8
$app = new Application();
9
$app->add(new HelloworldCommand());
10
$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.

1
Console Tool
2
3
Usage:
4
  command [options] [arguments]
5
6
Options:
7
  -h, --help            Display help for the given command. When no command is given display help for the list command
8
  -q, --quiet           Do not output any message
9
  -V, --version         Display this application version
10
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
11
  -n, --no-interaction  Do not ask any interactive question
12
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
13
14
Available commands:
15
  completion   Dump the shell completion script
16
  hello-world  Prints Hello-World!
17
  help         Display help for a command
18
  list         List commands

As expected, the hello-world command appears in the list of available commands! Go ahead and run it!

1
$bin/console hello-world tutsplus
2
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 create a real-world example to demonstrate 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.

1
<?php
2
namespace Console\App\Commands;
3
 
4
use Symfony\Component\Console\Command\Command;
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputOption;
9
 
10
class ClearcacheCommand extends Command
11
{
12
    protected function configure()
13
    {
14
        $this->setName('clear-cache')
15
            ->setDescription('Clears the application cache.')
16
            ->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.')
17
            ->addOption(
18
                    'groups',
19
                    'g',
20
                    InputOption::VALUE_OPTIONAL,
21
                    'Pass the comma separated group names if you don\'t want to clear all caches.',
22
                    ''
23
                );
24
    }
25
 
26
    protected function execute(InputInterface $input, OutputInterface $output)
27
    {
28
        $output->writeln('Cache is about to cleared...');
29
 
30
        if ($input->getOption('groups'))
31
        {
32
            $groups = explode(",", $input->getOption('groups'));
33
 
34
            if (is_array($groups) && count($groups))
35
            {
36
                foreach ($groups as $group)
37
                {
38
                    $output->writeln(sprintf('%s cache is cleared', $group));
39
                }
40
            }
41
        }
42
        else
43
        {
44
            $output->writeln('All caches are cleared.');
45
        }
46
 
47
        $output->writeln('Complete.');
48
49
        return Command::SUCCESS;
50
    }
51
}

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 run it, let's register the command with our console application.

1
#!/usr/bin/env php
2
<?php
3
require_once __DIR__ . '/../vendor/autoload.php';
4
 
5
use Symfony\Component\Console\Application;
6
use Console\App\Commands\HelloworldCommand;
7
use Console\App\Commands\ClearcacheCommand;
8
 
9
$app = new Application();
10
$app->add(new HelloworldCommand());
11
$app->add(new ClearcacheCommand());
12
$app->run();

Now, go ahead and run the bin/console clear-cache command to clear all caches!

1
$bin/console clear-cache
2
Cache is about to cleared...
3
All caches are cleared.
4
Complete.

Next, if you want to clear specific caches, you could try something like this.

1
$bin/console clear-cache --groups=group1,group2
2
Cache is about to cleared...
3
group1 cache is cleared
4
group2 cache is cleared
5
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 to show progress information. In this section, we'll quickly see how you can add a progress bar to your commands.

We'll revisit the example we discussed in the previous section. Let's replace the src/App/Commands/ClearcacheCommand.php file with the following contents.

1
<?php
2
namespace Console\App\Commands;
3
 
4
use Symfony\Component\Console\Command\Command;
5
use Symfony\Component\Console\Input\InputInterface;
6
use Symfony\Component\Console\Output\OutputInterface;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Helper\ProgressBar;
10
 
11
class ClearcacheCommand extends Command
12
{
13
    protected function configure()
14
    {
15
        $this->setName('clear-cache')
16
            ->setDescription('Clears the application cache.')
17
            ->setHelp('Allows you to delete the application cache. Pass the --groups parameter to clear caches of specific groups.')
18
            ->addOption(
19
                    'groups',
20
                    'g',
21
                    InputOption::VALUE_OPTIONAL,
22
                    'Pass the comma separated group names if you don\'t want to clear all caches.',
23
                    ''
24
                );
25
    }
26
 
27
    protected function execute(InputInterface $input, OutputInterface $output)
28
    {
29
        if ($input->getOption('groups'))
30
        {
31
            $groups = explode(",", $input->getOption('groups'));
32
            $progressBar = new ProgressBar($output, count($groups));
33
 
34
            $progressBar->start();
35
            
36
            if (is_array($groups) && count($groups))
37
            {
38
                foreach ($groups as $group)
39
                {
40
                    sleep(5);
41
                    $progressBar->advance();
42
                }
43
            }
44
45
            $progressBar->finish();
46
        }
47
        else
48
        {
49
            $output->writeln('All caches are cleared.');
50
        }
51
52
        $output->writeln('');
53
54
        return Command::SUCCESS;
55
    }
56
}

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.

1
$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 in the progress bar. 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, the finish method completes the progress bar. So whenever a command is completed successfully, you can call this method so that the progress bar is refreshed with 100% completion.

In our example, we've used the sleep command so you can 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.

1
$bin/console clear-cache --groups=group1,group2,group3,group4,group5
2
 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% every five seconds, and it'll reach 100% after 25 seconds.

So that's how you can implement a 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 to help 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.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.