You can add new console commands to your application or register plugin commands using bootloaders. The component is
configured by default to automatically discover commands located in the app/src
directory.
This documentation page will guide you through the process of creating and using console commands in your application. Whether you are a beginner or an experienced developer, you will find the information you need to get started.
To create a new command, you can either extend Symfony\Component\Console\Command\Command
or Spiral\Console\Command
.
Extending the Spiral\Console\Command
class provides some additional syntax sugar and convenience methods that can make
it easier to build your command.
Note
Which option you choose will depend on your needs and preferences. Both approaches are valid and can be used to create functional console commands.
To create your first command effortlessly, use the scaffolding command:
php app.php create:command My
Note
Read more about scaffolding in the Basics — Scaffolding section.
After executing this command, the following output will confirm the successful creation:
Declaration of 'MyCommand' has been successfully written into 'app/src/Endpoint/Console/MyCommand.php'.
namespace App\Endpoint\Console;
use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Attribute\Option;
use Spiral\Console\Attribute\Question;
use Spiral\Console\Command;
#[AsCommand(name: 'my')]
final class MyCommand extends Command
{
public function __invoke(): int
{
// Put your command logic here
$this->info('Command logic is not implemented yet');
return self::SUCCESS;
}
}
To invoke your command, run the following command in the console:
php app.php my
Since 3.6 release Spiral offers the ability to define console commands using PHP attributes. This allows for a more intuitive and streamlined approach to defining commands with clear separation of concerns.
Here's an example of defining a console command using attributes:
namespace App\Api\Cli\Command;
use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Attribute\Option;
use Spiral\Console\Attribute\Question;
use Spiral\Console\Command;
use Symfony\Component\Console\Input\InputOption;
#[AsCommand(
name: 'app:create:user',
description: 'Creates a user with the given data')
]
final class CreateUser extends Command
{
#[Argument]
private string $email;
#[Argument(description: 'User password')]
private string $password;
#[Argument(name: 'username', description: 'The user name')]
private string $userName;
#[Option(shortcut: 'a', name: 'admin', description: 'Set the user as admin')]
private bool $isAdmin = false;
public function __invoke(): int
{
$user = new User(
email: $this->email,
password: $this->password,
);
$user->setIsAdmin($this->isAdmin);
// Save user to database...
return self::SUCCESS;
}
}
To define the name and description of a console command, you can use either the Spiral\Console\Attribute\AsCommand
or Symfony\Component\Console\Attribute\AsCommand
attribute.
You can mark a class property as an argument for a console command using
the Spiral\Console\Attribute\Argument
attribute.
#[Argument]
private string $email;
Argument
attribute without any additional parameters, indicating that it will use the property name as the argument
name and will not include a description.
#[Argument(description: 'User password')]
private string $password;
Use a description parameter to provide a brief description of the argument.
#[Argument(name: 'username', description: 'The user name')]
private string $username;
The name parameter allows you to specify a custom argument name that is different from the property name.
Note
Any property marked with the Argument attribute must have a scalar typehint, such asstring
, to indicate the type of value that the argument should accept.
If you want to set a default value for an argument, you can specify the default value as the property's default value:
#[Argument]
private string $username = 'guest';
In this case if no value is provided for the argument during the command invocation, the default value will be used.
In some cases, you may want to make an argument optional in a console command. To do this, you can use a nullable
typehint for the property that represents the argument and specify the default value as null
.
#[Argument]
private ?string $username = null;
Options are additional parameters that users can specify when running a command. They are defined as properties in your command class, annotated with the #[\Spiral\Console\Attribute\Option] attribute.
use Spiral\Console\Attribute\Option;
#[Option(name: 'admin', description: 'Set the user as admin')]
private bool $isAdmin = false;
The name
parameter allows you to specify a custom option name that is different from the property name.
php app.php app:create:user --admin
You can also specify a shortcut for the option using the shortcut parameter:
#[Option(shortcut: 'a', ...)]
private bool $isAdmin = false;
This option can be invoked with a shortcut -a
instead of typing --admin
.
Options can be defined as required or optional. To make an option required, you don't need to specify default value for the property:
#[Option(...)]
private string $status;
If you want to make an option optional, you can specify the default value as the property's default value:
#[Option(...)]
private ?string $status = null;
Using PHP enums, the value of the option will be validated against the enum values.
#[Option(description: 'Set the user status')]
private Status $status = Status::new;
To accept multiple values for an option, you can use array
typehint for the property that represents the option:
#[Option(name: 'role', description: 'Set the user roles')]
private array $role = [];
php app.php app:create:user --role=foo --role=bar
By default, when you invoke a console command without passing required arguments, the application will prompt you to
provide a value for each missing argument. However, you can customize the prompt message for each argument using the
Spiral\Console\Attribute\Question
attribute.
It can be used both as a property attribute and as a class attribute.
#[Option(
mode: \Symfony\Component\Console\Input\InputOption::VALUE_REQUIRED,
...
)]
private bool $isAdmin = false;
When used as a class attribute, you need to define the corresponding argument
name for each property that requires a
custom prompt.
#[Question(question: 'Provide user email', argument: 'email')]
final class CreateUserCommand extends Command
{
#[Argument]
private string $email;
// ...
}
By setting a custom prompt for each argument, you can provide more specific and relevant information to the user, which can make the interaction more intuitive and streamlined. It is a good practice to use prompts that are clear, concise, and easy to understand.
The SIGNATURE
constant provides an alternative way to define the name of your command, as well as
its arguments and options. This can be a convenient way to specify all of this information in a single place,
rather than defining the name, arguments, and options separately.
class SomeCommand extends Command
{
protected const SIGNATURE = <<<CMD
check:http
{url : Site url}
{--S|skip-ssl-errors : Skip SSL errors}
CMD;
public function perform(): int
{
$url = $this->argument('url');
$skipErrors = $this->option('skip-ssl-errors');
// ...
}
}
In this example the SIGNATURE
constant defines a command named check:http
with a required argument url
, and an
optional option skip-ssl-errors
.
You can make an argument optional by including a ?
character after its name. For example, the check:http {url?}
defines an optional argument.
You can also define a default value for an argument by including an =
character followed by the default value after
the argument name. For example, check:http {url=foo}
defines an argument with a default value.
If you want to define an argument that expects multiple input values, you can use the []
character. For example,
check:colors {colors[]}
defines an argument that expects multiple values.
If you want to make the argument optional, you can include a ?
character after the []
characters, as in
check:colors {colors[]?}
. This will allow the user to omit the argument if desired.
Options are useful for specifying additional information or modifying the behavior of a command. They can be used to enable or disable certain features, specify a configuration file or other input file, or set other parameters that influence the command's behavior.
Options are a form of user input that is prefixed by two hyphens --
when specified on the command line. In the
SIGNATURE
constant, options are defined using the syntax {--name}
, {--name=value}
or {--n|name}
if you want to
use shortcut.
You can use shortcuts for options to make it easier for users to specify the option when calling the command.
For example, {--S|skip-ssl-errors}
defines an option named skip-ssl-errors
with a shortcut of S
. This means that
the option can be specified using either --skip-ssl-errors
or --S
on the command line.
Using shortcuts for options can make it easier and more convenient for users to specify the options they want to use when calling your command. It's a good idea to choose clear and concise shortcut names that are easy to remember and type.
If you want to define an option that expects multiple input values, you can use the []
character. For example,
check:colors {--colors[]=}
defines an option that expects multiple values.
It's a good idea to include a description for each argument
and option
you define, as it will help users understand
the purpose and format of the input expected by your command. This can make it easier for users to use your command
effectively and avoid errors.
Here is an example of how you might use an argument with a description in a console command:
check:http
{url : Site url}
{--S|skip-ssl-errors : Skip SSL errors}
You can put your user code into the perform
method. The perform
supports method injection and
provides $this->input
and $this->output
properties to work with user input.
protected function perform(MyService $service): int
{
$this->output->writeln($service->doSomething());
return self::SUCCESS;
}
To get user's data via arguments and/or options, you can make use of $this->argument("argName")
or
$this->option("optName")
.
Note
In addition here you can find information how to usespiral/filters
component for console commands.
You can use a set of helper methods available inside the Spiral\Console\Command
. Given examples are intended to be
called in the perform
method.
To write into output:
$this->writeln('hello world');
To write into output without advancing to a new line:
$this->write('hello world');
To write formatted output without advancing to a new line:
$this->sprintf('Hello, <comment>%s</comment>', $name);
Note
This method is compatible with thesprintf
definition.
To check if the current verbosity mode is higher than OutputInterface::VERBOSITY_VERBOSE
:
dump($this->isVerbose());
Note
You can freely use thedump
method in console commands.
To render a table:
$table = $this->table([
'Column #1:',
'Column #2:',
]);
foreach ($data as $row)
{
$table->addRow([
$row[1],
$row[2]
]);
}
$table->render();
To add a table separator:
$table->addRow(new Symfony\Component\Console\Helper\TableSeparator());
To determine if the input option is present:
$this->hasOption(...);
To determine if the input argument is present:
$this->hasArgument(...);
To asks for confirmation:
$status = $this->confirm('Are you sure?', default: false);
To ask a question:
$status = $this->ask('Are you sure?', default: 'no');
To ask a multiple choice question:
$name = $this->choiceQuestion(
'Which of the following is package manager?',
['composer', 'django', 'phoenix', 'maven', 'symfony'],
default: 2,
allowMultipleSelections: true
);
To prompt the user for input but hide the answer from the console:
$status = $this->secret('User password');
To write a message as information output:
$this->info('Some message');
To write a message as comment output:
$this->comment('Some message');
To write a message as question output:
$this->question('Some question');
To write a message as error output:
$this->error('Some error');
To write a message as warning output:
$this->warning('Some warning');
To write a message as alert output:
$this->alert('Some alert');
To write a blank line:
$this->newLine();
$this->newLine(count: 5);
The Spiral\Console\Confirmation\ApplicationInProduction
class provided by the component makes it easy to
ask the user for confirmation before running a command if the application is running in production mode. This can help
prevent accidental or unintended changes to the production environment.
To use it, you can inject an instance of it into your command's perform()
method. Then, you can use
the confirmToProceed()
method to ask the user for confirmation before proceeding with the command.
use Spiral\Console\Confirmation\ApplicationInProduction;
final class MigrateCommand extends Command
{
protected const NAME = 'db:migrate';
public function perform(ApplicationInProduction $confirmation): int
{
if (!$confirmation->confirmToProceed()) {
return self::FAILURE;
}
// run migrations...
}
}
The Command class makes it easy to define arguments and options for your console command. By setting
the ARGUMENTS
and OPTIONS
constants:
const ARGUMENTS = [
['argName', InputArgument::REQUIRED, 'Argument name.']
];
const OPTIONS = [
['optName', 'c', InputOption::VALUE_NONE, 'Some option.']
];
Event | Description |
---|---|
Spiral\Console\Event\CommandStarting | The Event will be fired before executing the console command. |
Spiral\Console\Event\CommandFinished | The Event will be fired after executing the console command. |
Note
To learn more about dispatching events, see the Events section in our documentation.