Re-Introducing Symfony Console – CLI PHP for the Uninitiated!

Share this article

Re-Introducing Symfony Console – CLI PHP for the Uninitiated!

Key Takeaways

  • Symfony Console is a standalone package that provides a simple framework for creating command line tools, useful for recurring tasks like data migration, imports, or creating cron jobs.
  • To create a new command, a file needs to be made executable. This is done by creating a console file in the root of the project, ensuring the file is executable, and defining the console application.
  • Commands can be tested using Symfony’s CommandTester class, which provides special input and output classes to test commands without the need for a command line.
  • Symfony Console is installed using Composer, a dependency management tool in PHP. It provides a simple API to create command-line commands and supports colorization of output, progress bars, tables, and other interactive features.

This popular article was updated on May 24th, 2017 to provide a more comprehensive introduction into an essential, modern tool.


“The console component eases the creation of beautiful and testable command line interfaces.”

This is how we are welcomed when we visit the Symfony Console component tool page.

As software developers, we often feel the need to resort to command line tools. These kinds of tools are helpful when we need to do a sort of recurring task like migrating data, performing imports, or creating cron jobs.

Vector image of a terminal or console application

The Symfony Console component tool provides us with a simple framework to create our own command line tools.

Unlike many components in Symfony, this is a standalone package and is used by the likes of Laravel‘s Artisan and many other famous PHP packages.

To read up on alternatives to Symfony Console, see our comparison post: PHP Console Wars!

Installation

composer require symfony/console

Essential information about Composer here.

Creating a New Command

To create a new command, we need to make sure our file will be executable. In order to do that, let’s create a console file in the root of our project. This file will be our command manager.

touch console

Now, let’s make sure the file is executable.

chmod 755 console

Then, let’s make sure our file has the shebang at the beginning. The shebang is a character sequence (a number sign followed by an exclamation mark) that appears at the beginning of a script. When the shebang is present, exec() will instead run the executable specified after the shebang. In our case, it will run as a PHP script.

After this, let’s define our console application. The first iteration of our command manager will look like this:

#!/usr/bin/env php

<?php 

require_once __DIR__ . '/vendor/autoload.php'; 

use Symfony\Component\Console\Application; 

$app = new Application();
$app->run();

`

Let’s take a closer look at things. First, we are autoloading all our dependencies, then importing the Application package from the Console component. After that, we are creating a new instance of the Application and running it.

If we execute our script with ./console, we should get the following help message: Command 1

This is because we haven’t registered any commands yet, we only built the basic framework for them.

Let’s create our script and register it in our newly created command manager.

For this particular example, we will implement two simple commands: one for hashing strings, and another one for confirming a hash belongs to a given string.

We’ll create a /src folder in which we will put our Hash.php class with the contents:

<?php

namespace Hash;

class Hash{

    /**
     * Receives a string password and hashes it.
     *
     * @param string $password
     * @return string $hash
     */
    public static function hash($password){
        return password_hash($password, PASSWORD_DEFAULT);
    }

    /**
     * Verifies if an hash corresponds to the given password
     *
     * @param string $password
     * @param string $hash 
     * @return boolean If the hash was generated from the password
     */
    public static function checkHash($string, $hash){
        if( password_verify( $string, $hash ) ){
            return true;
        }
        return false;
    }

}

It’s time to create our command. Let’s create a new PHP file called HashCommand.php.

This class will extend from Symfony’s Command class and implement the configure and execute methods. These methods are essential for our command as they tell it how to look and behave.

This is what the finished command looks like:

<?php

namespace Hash;

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\Formatter\OutputFormatterStyle;

use Hash\Hash;

class HashCommand extends Command{

    protected function configure(){
        $this->setName("Hash:Hash")
                ->setDescription("Hashes a given string using Bcrypt.")
                ->addArgument('Password', InputArgument::REQUIRED, 'What do you wish to hash)');
    }

    protected function execute(InputInterface $input, OutputInterface $output){

        $hash = new Hash();
        $input = $input->getArgument('Password');

        $result = $hash->hash($input);

        $output->writeln('Your password hashed: ' . $result);

    }

}

In the configure portion, the setName method is how we will be calling our command, setDescription is a description of our command, and addArgument is where we are saying that our command will take one argument called Password, and that it is required.

In the execute portion, we are accessing the argument through the getArgument function, and then using our Hash class to hash it. Finally, we use the OutputInterface‘s writeln method to print our result to the screen.

If we run our command like this, we will see that nothing happens. That’s because we are still missing one very important step. We still need to register our command in the console.

#!/usr/bin/env php

<?php 

require_once __DIR__ . '/vendor/autoload.php'; 

use Symfony\Component\Console\Application; 
use Hash\HashCommand;

$app = new Application();

$app->add(new HashCommand());

$app->run();

With the command registered in our console, let’s run it.

If we run the ./console command once again, we can see that we now have a new command registered.

New command list

Let’s run it:

./console Hash:Hash Sitepoint

And we see the final result:

Command execution

The hash is the result of running the PHP hash() method on the Sitepoint string.

For the hash-confirming functionality, we will use the same method, but instead of one, we will have two arguments. One will be the string to confirm, and the other the hash we want to validate.

We will be creating a new command file, right next to the HashCommand file. Let’s call it ConfirmCommand.

<?php

namespace Hash;

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\Formatter\OutputFormatterStyle;

use Hash\Hash;

class ConfirmCommand extends Command{

    protected function configure(){
        $this->setName("Hash:Confirm")
                ->setDescription("Confirms an Hash given the string.")
                ->addArgument('Password', InputArgument::REQUIRED, 'What password do you wish to confirm?)')
                ->addArgument('Hash', InputArgument::REQUIRED, 'What is the hashyou want to confirm?');
    }

    protected function execute(InputInterface $input, OutputInterface $output){

        $hash = new Hash();
        $inputPassword = $input->getArgument('Password');
        $inputHash = $input->getArgument('Hash');

        $result = $hash->checkHash($inputPassword, $inputHash);

        if($result){
            $output->writeln('The hash belongs to the password!');
            return true;
        }

        $output->writeln('The hash does not belong to the password!');

    }

}

Then, register the command in the console.

#!/usr/bin/env php

<?php 

require_once __DIR__ . '/vendor/autoload.php'; 

use Symfony\Component\Console\Application; 
use Hash\HashCommand;
use Hash\ConfirmCommand;

$app = new Application();

$app->add(new HashCommand());
$app->add(new ConfirmCommand());

$app->run();

Testing

When it comes to testing, Symfony provides us with some handy tools. The most useful of them is the CommandTester class, as it provides special input and output classes to test our commands without the need of a command line.

Let’s use the CommandTester class to implement a test for our Hash:Hash command.

First, let’s create a /tests folder at the same level as our /src folder.

Then, let’s create our test class inside of it and call it HashCommandTest.php:

<?php

use Hash\HashCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

require_once  './vendor/autoload.php'; 

class HashCommandTest extends \PHPUnit_Framework_TestCase{

    public function testHashIsCorrect(){

        $application = new Application();
        $application->add(new HashCommand());

        $command = $application->find('Hash:Hash');
        $commandTester = new CommandTester($command);
        $commandTester->execute(array(
            'command'      => $command->getName(),
            'Password'         => 'Sitepoint'
        ));    

        $this->assertRegExp('/Your password hashed:/', $commandTester->getDisplay());

    }

}

We begin our test by loading our command using the Application class. Then, we instantiate a new CommandTester. With the CommandTester, we can configure how we want to call our command. The last step is just comparing the results of the execution with the result we are expecting using the getDisplay() method.

The getDisplay() method holds the result of our command’s execution, just as we would see it on the command line.

Conclusion

We just created two different commands using the Symfony Console Component. We also saw a good way of testing those commands. I recommend you take a look at the component’s various options and features, and give us some feedback on your experiments in the comments section below.

Would you like to see some more advanced tutorials about Symfony Console on SitePoint? Let us know!

All the code we wrote in this article is available on Github.

Frequently Asked Questions (FAQs) about Symfony Console

How do I install Symfony Console?

Symfony Console is a component of the Symfony framework and can be installed using Composer, a dependency management tool in PHP. To install Symfony Console, you need to run the following command in your terminal: composer require symfony/console. This command will download and install the Symfony Console component into your project.

What are the main features of Symfony Console?

Symfony Console provides a simple API to create command-line commands. These commands can be used for cron jobs, migrations, imports, or any other type of task that can be run via the command line. It also supports colorization of output, progress bars, tables, and other interactive features.

How do I create a new command in Symfony Console?

To create a new command, you need to create a new class that extends the Symfony\Component\Console\Command\Command class. In this class, you define the name, description, arguments, and options of the command in the configure method. The execute method contains the logic of the command.

How do I run a command in Symfony Console?

To run a command, you need to use the bin/console script followed by the name of the command. For example, if you have a command named app:my-command, you can run it with the following command: bin/console app:my-command.

How can I use Symfony Console for database migrations?

Symfony Console can be used in combination with Doctrine, a database abstraction layer in Symfony, to manage database migrations. You can create a new command that executes the necessary SQL queries to migrate your database.

How do I handle command arguments and options in Symfony Console?

Command arguments and options can be defined in the configure method of your command class. You can retrieve the values of these arguments and options in the execute method using the getArgument and getOption methods.

How do I display output in Symfony Console?

Symfony Console provides several methods to display output. You can use the writeln method to display a line of text, the write method to display text without a newline at the end, and the table method to display a table.

How do I handle errors in Symfony Console?

Errors can be handled by throwing exceptions. Symfony Console will catch these exceptions and display an error message. You can also use the exit method to stop the execution of the command and return an exit code.

How do I test commands in Symfony Console?

Symfony Console provides a CommandTester class that can be used to test commands. You can use this class to execute a command with specific arguments and options and assert the output and exit code.

How do I use Symfony Console in a Symfony project?

In a Symfony project, you can use the bin/console script to run commands. You can also create your own commands by creating a new class in the src/Command directory that extends the Symfony\Component\Console\Command\Command class.

Claudio RibeiroClaudio Ribeiro
View Author

Cláudio Ribeiro is a software developer, traveler, and writer from Lisbon. He's the author of the book An IDE Called Vim. When he is not developing some cool feature at Kununu he is probably backpacking somewhere in the world or messing with some obscure framework.

BrunoScliCommand lineCommand line PHPconsoleOOPHPPHPsymfonysymfony frameworksymfony3terminal
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week