Console applications with the Symfony Console component

Published by at 29th April 2018 7:59 pm

Recently I've had the occasion to add a series of console commands to a legacy application. This can be made straightforward by using the Symfony console component. In this post I'll demonstrate how to write a simple console command for clearing a cache folder.

The first step is to install the Console component:

$ composer require symfony/console

Then we write the main script for the application. I usually save mine as console - note that we don't want to have to type out a file extension, so instead we use the shebang:

1#!/user/bin/env php
2<?php
3
4require __DIR__.'/vendor/autoload.php';
5
6use Symfony\Component\Console\Application;
7
8define('CONSOLE_ROOT', __DIR__);
9$app = new Application();
10
11$app->run();

In this case, I've defined CONSOLE_ROOT as the directory in which the console command is run - that way, the commands can use it to refer to the application root.

We can then run our console application as follows:

1$ php console
2Console Tool
3
4Usage:
5 command [options] [arguments]
6
7Options:
8 -h, --help Display this help message
9 -q, --quiet Do not output any message
10 -V, --version Display this application version
11 --ansi Force ANSI output
12 --no-ansi Disable ANSI output
13 -n, --no-interaction Do not ask any interactive question
14 -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
15
16Available commands:
17 help Displays help for a command
18 list Lists commands

This displays the available commands, but you'll note that there are none except for help and list. We'll remedy that. First, we'll register a command:

$app->add(new App\Console\ClearCacheCommand);

This has to be done in console, after we create $app, but before we run it.

Don't forget to update the autoload section of your composer.json to register the namespace:

1 "autoload": {
2 "psr-4": {
3 "App\\Console\\": "src/Console/"
4 }
5 },

Then create the class for that command. This class must extend Symfony\Component\Console\Command\Command, and must have two methods:

  • configure()
  • execute()

In addition, the execute() method must accept two arguments, an instance of Symfony\Component\Console\Input\InputInterface, and an instance of Symfony\Component\Console\Output\OutputInterface. There are used to retrieve input and display output.

Let's write our command:

1<?php
2
3namespace App\Console;
4
5use Symfony\Component\Console\Command\Command;
6use Symfony\Component\Console\Input\InputInterface;
7use Symfony\Component\Console\Output\OutputInterface;
8
9class ClearCacheCommand extends Command
10{
11 protected function configure()
12 {
13 $this->setName('cache:clear')
14 ->setDescription('Clears the cache')
15 ->setHelp('This command clears the application cache');
16 }
17
18 protected function execute(InputInterface $input, OutputInterface $output)
19 {
20 $dir = CONSOLE_ROOT.DIRECTORY_SEPARATOR.'cache';
21 $this->deleteTree($dir);
22 $output->writeln('Cache cleared');
23 }
24
25 private function deleteTree($dir)
26 {
27 $files = array_diff(scandir($dir), array('.','..'));
28 foreach ($files as $file) {
29 (is_dir("$dir/$file")) ? $this->deleteTree("$dir/$file") : unlink("$dir/$file");
30 }
31 return rmdir($dir);
32 }
33}

As you can see, in the configure() method, we set the name, description and help text for the command.

The execute() method is where the actual work is done. In this case, we have some code that needs to be called recursively, so we have to pull it out into a private method. Once that's done we use $output->writeln() to write a line to the output.

Now, if we run our console task, we should see our new command:

1$ php console
2Console Tool
3
4Usage:
5 command [options] [arguments]
6
7Options:
8 -h, --help Display this help message
9 -q, --quiet Do not output any message
10 -V, --version Display this application version
11 --ansi Force ANSI output
12 --no-ansi Disable ANSI output
13 -n, --no-interaction Do not ask any interactive question
14 -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
15
16Available commands:
17 help Displays help for a command
18 list Lists commands
19 cache
20 cache:clear Clears the cache

And we can see it in action too:

1$ php console cache:clear
2Cache cleared

For commands that need to accept additional arguments, you can define them in the configure() method:

$this->addArgument('file', InputArgument::REQUIRED, 'Which file do you want to delete?')

Then, you can access it in the execute() method using InputInterface:

$file = $input->getArgument('file');

This tutorial is just skimming the surface of what you can do with the Symfony Console components - indeed, many other console interfaces, such as Laravel's Artisan, are built on top of it. If you have a legacy application built in a framework that lacks any sort of console interface, such as CodeIgniter, then you can quite quickly produce basic console commands for working with that application. The documentation is very good, and with a little work you can soon have something up and running.