Build a PHP Console Application using Symfony

Chidume Nnamdi šŸ”„šŸ’»šŸŽµšŸŽ®
codeburst
Published in
6 min readNov 14, 2017

--

Brief prelude

Ever used Laravelā€™s installer utility? What about Homestead, or Behat, or PHPSpec? If so, then youā€™ve indirectly benefited from the Symfony Console component.

The Console component eases the creation of beautiful and testable command line interfaces.

Introduction

When I first saw Laravel framework, I really liked its Artisan console tool, it seemed like magic providing us with a bunch of stuff we could do with it such as creating MVC triads, running migrations and a lot more. Although similar concepts already existed in frameworks like CakePHP but Laravel did a good job of making us realize how useful a console app can be and that we can use it beyond basic CRUD operations.

In this article, weā€™ll learn how to build command-line app in PHP from scratch, using Symfonyā€™s excellent console component. In no time, youā€™ll be whipping up executables to perform all sorts of tasks.

Installation

Create a new directory.

mkdir php-console-app

Move into the folder.

cd php-console-app

We are now at the root of our project directory. letā€™s create a console.php file. This file will be our command manager.

touch console.php

Letā€™s make it executable like a regular shell command. First, letā€™s add a shebang at the top of console.php, which will tell the shell how to execute this script.

/** console.php **/
#!/usr/bin/env php
<?php
...

Letā€™s install the symfony/console component.

composer require symfony/console

After the execution of the above command, our directory will look like this.

--php-console-app
--vendor/
--composer.json
--composer.lock
--console.php

Open the console.php, and add the following code to it.

/** console.php **/
#!/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.

#!/usr/bin/env php

This tells the system that is a php env file and should be run by php executable. You may need to apply execute permission on this file if you are on Linux.

use Symfony\Component\Console\Application;

This will automatically include our dependencies which in this case is Symfony Console Component. Without this line, your application wonā€™t be able to find the classes of this Symfony component.

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

We are creating a new instance of the Application and running it.

OK, letā€™s execute the console.php script.

./console.php

We will get the following on our console.

Thatā€™s it. Notice this only has built-in commands in the Symfony/Console component because we havenā€™t registered any commands yet, we only built the basic framework for them.

Symfony/Console Command Structure

namespace Console;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class MyCommand extends Command
{
protected function configure()
{
// ...
}

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

Any class that extends the Command class must follow the above structure.

For demonstration in this article, we will build an app that greets a user based on the time of the day.

This is how our app will look like when we are done.

Final App

Creating our Command files

Letā€™s get started. Weā€™ll create a /src folder in which we will put our command files.

mkdir src

We will create two files Command.php and TimeCommand.php. Command.php will be our base command file while TimeCommand.php file will extend the Command class and define our commands.

touch src/TimeCommand.php && touch src/Command.php

The above command will generate two files TimeCommand.php and Command.php in the src directory. Our project folder will now look like this.

--php-console-app 
---src/
---src/TimeCommand.php
---src/Command.php
--vendor/
--composer.json
--composer.lock
--console.php

Configure Command.php

In Command.php, paste in these contents.

This is the base class for our commands, it has a method greetUser which will be called by a child class. The greetUser method accepts OutputInterface and InputInterface as arguments which it uses to get userā€™s inputs and prints the greeting message to the screen. Next, we defined a getGreeting method which does calculations based on the time of the day and processes the greeting message accordingly. In other words, It generates the greeting message based on the current time of the day.

Configure TimeCommand.php

The Symfony Console Component requires that we should extend it and provide at least two methods called configure() and execute(). As the names suggest, the configure() method can be used to configure our commands such as what command will be called, what arguments and options it will accept and the execute() command will actually execute our command.

Open the TimeCommand.php, and make it look like this.

In the configure portion, the setName method is how we will be calling our command, setDescription is a description of our command, setHelpthe full command description shown when running the command with the ā€œ ā€” helpā€ option, and addArgument is where we are saying that our command will take one argument called username and that it is required.

In the execute portion, we are calling the inherited method greetUser passing InputInterface and OutputInterface as arguments. The TimeCommand is a child class of Command.

Register our command

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 TimeCommandin the console.

/** console.php **/
#!/usr/bin/env php
<?php
require_once __DIR__ . '/vendor/autoload.php';use Symfony\Component\Console\Application;
use Console\TimeCommand;
/**
* Author: Chidume Nnamdi <kurtwanger40@gmail.com>
*/
$app = new Application('Console App', 'v1.0.0');
$app -> add(new TimeCommand());
$app -> run();

Configure composer.json

If you run the console.php script it would throw an error on the console. The reason is that TimeCommand.php file was not found. To stave off the errors, we have to tweak the composer.json a little. Open the composer.json, and edit it to look like this.

/** composer.json **/
{
"require": {
"symfony/console": "^3.3"
},
"autoload": {
"psr-4": {
"Console\\": "src"
},
"classmap": ["src"]
}
}

Then, run the command.

composer dump -o

Run our app

OK, our app is set. To see it in action, use the command format.

./console.php greet <your-username>

Substitute your name for ā€˜<your-username>ā€™.

Iā€™ll use my name ā€˜Nnamdiā€™.

./console.php greet Nnamdi

Thatā€™s it. You now have a PHP command-line app. We can make it look a little like Laravelā€™s artisan tool by removing the .php on console.php. Then, we can run our app like this.

./console greet Nnamdi

Conclusion

We have seen how easy it is to build a PHP console app using Symfony/Console component. You can add any commands you want to your new console app. You can even run composer or git commands through your new console app or maybe some deployment/build scripts or even system commands. If you are using some MVC framework, you can use this tool to for example create your own way of creating controllers, entity classes, run your custom migrations, call methods from your controllers and more.

You can visit the Symfony website to see their components made for PHP devs that can help you create complex PHP apps with ease.

Github repo

You can find the full source code in my Github repo.

Special thanks to

  • Grammarly ā€” for proof-reading.
  • Symfony ā€” for providing tools that enable PHP developers to easily start new projects and create new tools.

Social media

Feel free to reach out if you have any problems.

Follow me on Medium and Twitter to read more about TypeScript, JavaScript, and Angular.

--

--

JS | Blockchain dev | Author of ā€œUnderstanding JavaScriptā€ and ā€œArray Methods in JavaScriptā€ - https://app.gumroad.com/chidumennamdi šŸ“•