PHP Development. Symfony Console Component - Tips & Tricks
Software Development
Sebastian Luczak
Sebastian Luczak
PHP Unit Leader
2022-04-14

PHP Development. Symfony Console Component - Tips & Tricks

This article was created with the aim to show you the most useful and retrieving tips and tricks about Symfony Console Development.

If you are a PHP developer that wants to bring your PHP software development to the next level this article is for you. Without further ado let's cut to the chase.

Introduction

You often hear: ​

PHP is only used to make web pages

image

​ This is completely untrue because nowadays PHP development is used in many different business areas, often not so trivial at first sight.

Both the PHP language and its environment perfectly support HTTP communication which, together with the use of the CLI environment, makes it possible to quickly create web bots, web crawlers or tools that synchronize data in external environments. ​ To support this I have some statistics that show that the Console component of the Symfony framework, which allows easy access to the command line, is in the TOP5 most used and downloaded Symfony packages of all time.

image

​ At this point, we'd like to share with you a few tricks that every PHP developer should know when writing code in PHP that is supposed to work in the CLI. ​

Interactive selection table with custom data source

image

Table rendering with the ability to choose entries from can be achieved in an easy way using Symfony Command: ​

// src/App/Command/TestCommand.phpprotected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title("Interactive selection table example");$table = $io->createTable();
        $table->setHeaderTitle("Interactive selection table example");
        $table->setRows(iterator_to_array($this->tagsTableRows()));
        $table->render();
        $io->newLine();return Command::SUCCESS;
    }

​ In above example we're taking advantage of PHP Generators as source of data - which helps with scalability in future. Simple data generator for above example: ​

    protected function tagsTableRows(): Generator
    {
        $apiTagsResponse = $this->someInjectedService->getTags();
        foreach ($apiTagsResponse as $apiTagResponse) {
            yield [ $apiTagResponse->getName(), $apiTagResponse->getId() ];
        }
    }

​ The end result is a Table rendered in CLI. ​ image

To make it interactive we need to use QuestionHelper, provided as wrapper around SymfonyStyle output. ​

  (...)
    $choice = new ChoiceQuestion(
        question: 'Which selection you choose?',
        choices: array_reduce(
            array: $rows,
            callback: function($carry, $item) {
                $carry[] = $item[0];return $carry;
            }
        )
    );
    $answer = $io->askQuestion($choice);
   (...)

As result, we're getting an interactive choice field with a table display from the same source. ​

Always use hidden prompt for sensitive user data

image

Hiding prompt while providing sensitive data is a common practive and it's also easily achievable in Symfony Console. You can use built-in wrapper in SymfonyStyle class by the following example: ​

  (...)
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title("Asking user for sensitive data");
        $io->askHidden(
            question: "Provide your API key here",
            validator: function($answer) { return (42 == strlen($answer)) ?? $answer; }
        );return Command::SUCCESS;
    }

Style your Progress Bars

image

To communicate some progress to the user we can use Progress Bars. Symfony Console has a great way to show progress to the user, but always remember to style your progress output correctly. You can have full controler over different parts and how they're rendered using Formatter. The progress bar format just a string of different placeholders. The available placeholders are: current, max, bar, percent, elapsed, remaining, estimated, memory and message. Fiddle with them with the example below. ​

  (...)
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title("Styled progress bar example");$progressBar = new ProgressBar($io, 10000);
        $progressBar->setFormat('<comment>%current%/%max% [%bar%] %percent:3s%%</comment>
                    <info>%elapsed:6s%/%estimated:-6s%</info> <error>%memory:6s%</error>');
        $progressBar->start();
        for ($i = 0; $i < 10000; $i++) {
            $progressBar->advance();
            usleep(420);
        }$progressBar->finish();
        $io->newLine();return Command::SUCCESS;
    }

​ You can use almost anything as and formatter as long as your terminal is capable of displaying it. Official Symfony documentation ​

Provide suggestions to your Console Commands

image

We're used to console suggestion, autocompletion features, and such in our development life. If you're creating console application you should consider adding it so that your users will not be confused about how to use your low-level CLI solution. PHP Symfony Console can provide that too, out of the box, using CompletionInput class. ​

  (...)
    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
    {
        if ($input->mustSuggestArgumentValuesFor(argumentName: 'someArgument')) {
            $suggestions->suggestValues(['someSuggestion', 'otherSuggestion']);
        }
    }

Symfony 5.1 introduced a new way of handling cursor position in CLI applications. Since then it's possible to read and write at a specific place at screen using handy Cursor class: ​

  (...)
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title("Cursor example");$cursor = new Cursor($io);
        $cursor->clearScreen();
        for ($x = 0; $x <= 10; $x++) {
            for ($y = 0; $y <= 10; $y++) {
                $cursor->moveToPosition($x, $y);if ($y === $x) {
                    $io->write(".");
                }
            }
        }
        $io->write("Hello, World!");
        $io->newLine();return Command::SUCCESS;
    }

image ​ ​

This short list of tricks is just the tip of the iceberg. The possibilities of Symfony Console are endless, as evidenced by the numerous projects like Psalm, PHPStan or Composer that are based on PHP and used by millions of PHP developers around the world.

PHP development free consulting

Read more:

3 Common Challenges of Software Product Development for Startups

The Best Type of Projects for Java

7 Startups & Scaleups that Will Shake the Marketplace Scene in 2022