Mikkel Paulson
Contributed by Mikkel Paulson in #30997

The Console component provides an utility to autocomplete the answers to questions created with the Question Helper. This is used for example to autocomplete classes and entities in the MakerBundle to boost your productivity.

However, autocomplete requires to know all the possible suggestions beforehand. This is impossible if the suggestions depend on the user input and not practical if the completion is highly dynamic (e.g. when autocompleting the contents of directories).

In Symfony 4.3 we improved this feature with a new method called setAutocompleterCallback() that allows to use a callback function to generate the autocomplete suggestions dynamically. For example, this example shows how to autocomplete the user input with valid directory contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use Symfony\Component\Console\Question\Question;

// ...
public function execute(InputInterface $input, OutputInterface $output)
{
    // This function is called whenever the input changes and new
    // suggestions are needed.
    $callback = function (string $userInput): array {
        // Strip any characters from the last slash to the end of the string
        // to keep only the last directory and generate suggestions for it
        $inputPath = preg_replace('%(/|^)[^/]*$%', '$1', $userInput);
        $inputPath = '' === $inputPath ? '.' : $inputPath;

        // CAUTION - this example code allows unrestricted access to the
        // entire filesystem. In real applications, restrict the directories
        // where files and dirs can be found
        $foundFilesAndDirs = @scandir($inputPath) ?: [];

        return array_map(function ($dirOrFile) use ($inputPath) {
            return $inputPath.$dirOrFile;
        }, $foundFilesAndDirs);
    };

    $question = new Question('Please provide the full path of a file to parse');
    $question->setAutocompleterCallback($callback);

    $filePath = $helper->ask($input, $output, $question);
}
Published in #Living on the edge