SymfonyWorld Online 2021 Winter Edition December 9 – 10, 2021 100% Online 25 talks and 10 workshops

New in Symfony 4.1: Prepared commands

Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.

Contributed by
Hamza Amrouche
in #24763.


In Symfony 4.1 we improved the Process component to allow writing “prepared commands”, a concept similar to prepared statements in SQL. The basic idea is to replace some parts of the command with placeholders whose values you provide later when actually running the command (or via environment variables):

1
2
3
4
use Symfony\Component\Process\Process;

$process = new Process('ls -lsa "${:path}"');
$process->run(null, ['path' => '/path/to/some/dir']);

Placeholders must follow the "${:placeholder_name}" syntax strictly, which has nothing to do with Twig, except for the coincidence in the use of brackets. If some placeholder value is missing when running the command, you’ll get an InvalidArgumentException.

In addition to passing the placeholder values as the second argument of the run() method you can also pass them in the Process class constructor:

1
2
3
4
use Symfony\Component\Process\Process;

$process = new Process('ls -lsa "${:path}"', null, ['path' => '/path/to/some/dir']);
$process->run();

One of the best features of prepared commands is that placeholder values are escaped automatically, which makes your life as a developer easier and ensures that commands will always work as expected.

1
2
3
4
5
6
7
$process = new Process('mysqldump --user="${:db_user}" --password="${:db_pass}" "${:db_name}" > "${:db_backup_path}"');
$process->run(null, [
    'db_user' => getenv('DB_USER'),
    'db_password' => getenv('DB_PASS'),
    'db_name' => 'symfony',
    'db_backup_path' => '/var/backup/db-'.time().'.sql',
]);

If you don’t like the idea of using placeholders in your commands for some reason, the Process component also allows since Symfony 3.3 to pass an array where the first element is the command to run and the rest of the array elements are its options and arguments, allowing you to build a complex command programmatically:

1
2
3
4
5
6
7
$process = new Process(array(
    'mysqldump',
    '--user='.getenv('DB_USER'),
    '--password='.getenv('DB_PASS'),
    $dbName,
));
$process->run();
Help the Symfony project!

As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.

Comments

Great new !

Thx Javier :)
Genius! This will make some of my commands a lot easier to read!
Thank you!
First they took away ProcessBuilder and now give Prepared commands. Well done...
@Gemorroj we're working on making some changes in this feature before the release of Symfony 4.1. Stay tuned because we'll update this article when those changes are ready.
@Javier Eguiluz yes, the feature is very interesting.
But, in my OPINION, at first it was necessary to release this feature, and then to remove `ProcessBuilder`.
Now I do not understand how to escape arguments. Probably, it is necessary to use native `escapeshellarg`. Which I don't think is good.
Thanks for this feature!
Following along a bit, the behaviour have changed. Now, it should be something like this on unix:

$process = new Process('ls -lsa "${:path}"', null, ['path' => '/path/to/some/dir']);

(See https://github.com/symfony/symfony/pull/34848)

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.