Alternatives to Laravel Artisan Command Signatures

December 1, 2016 —John Koster

The command signature feature was introduced in Laravel version 5.1. In older versions of the framework the instance methods getArguments and getOptions were used to define the input expectations for commands. Both methods were expected to return arrays. These methods still exist and can still be used. This section will explain how these methods are used and the subtle changes that are required in order to use them.

When looking at a basic command class we see something similar to this (the methods have been omitted in the following example):

1<?php
2 
3namespace App\Console\Commands;
4 
5use Illuminate\Console\Command;
6 
7class NewCommand extends Command
8{
9 /**
10 * The name and signature of the console command.
11 *
12 * @var string
13 */
14 protected $signature = 'new:command';
15 
16 /**
17 * The console command description.
18 *
19 * @var string
20 */
21 protected $description = 'Command description';
22 
23 // Methods omitted...
24 
25}

The first thing to notice is that there are two protected variables. One is named $signature and the other is named $description; for this section, the $description variable is irrelevant. When the $signature variable is present in the command class, Laravel will expect there to be a valid command signature. It will then parse it and use that to determine the command's name, parameters and options.

The following code example is the start of a typical command class from older versions of the Laravel framework (again, instance methods have been omitted):

1<?php
2 
3namespace App\Console\Commands;
4 
5use Illuminate\Console\Command;
6 
7class NewCommand extends Command
8{
9 /**
10 * The name and signature of the console command.
11 *
12 * @var string
13 */
14 protected $name = 'new:command';
15 
16 /**
17 * The console command description.
18 *
19 * @var string
20 */
21 protected $description = 'Command description';
22 
23 // Methods omitted...
24 
25}

At first glance there does not look to be any difference between the two code examples. However, in the second example there is a $name protected variable instead of a $signature protected variable. When this is the case, Laravel will use the getArguments and getOptions instance methods to determine the input expectations for the command.

If you would like to use the getArguments or getOptions methods for defining input expectations, or simply want to ease the transition from an older code base, the $signature property cannot be defined in your command class. The signature will be used if it is present, not necessarily if it has been supplied a value. This means that if both a $name and a $signature property have been defined, the signature method for defining input expectations will take precedence.

The getArguments and getOptions methods should return an array containing arrays that represent the command arguments (referred to as parameters in previous sections) and options. The format for defining arguments versus options is slightly different.

The following table shows the difference between the formats for options and arguments. Both of arguments and options are represented as an array:

Input Type Format
Argument [$name, $mode, $description, $defaultValue]
Option [$name, $shortcut, $mode, $description, $defaultValue]

As you can see, the only difference between the two formats is that options can specify a shortcut.

When working with the getOptions and getArguments methods, there are two classes that are useful to work with. Both the options and arguments are part of the Symfony code base (Laravel's console application is an extension of Symfony's console application). The following two classes are required:

  • Symfony\Component\Console\Input\InputArgument - This class is required when defining input arguments.
  • Symfony\Component\Console\Input\InputOption - This class is required when defining input options.

The InputArgument class defines a few constants that are required when adding command arguments to the getArguments method. These constants are used to set each of the arguments mode. The following table lists each of these constants, a description of them and their value (the value can be used in situations where you do not want to import the class, but this practice is generally not recommended).

Constant Value Description
REQUIRED 1 Indicates that the input argument is required.
OPTIONAL 2 Indicates that the input argument is optional.
IS_ARRAY 4 Indicates that the input argument is an array, and users can supply multiple values for the same argument.

Default values can only be defined for arguments that are using the OPTIONAL mode.

The InputOption class is similar to the InputArgument class in that it defines useful constants that are required when implementing the getOptions method. Like the arguments, the constants below set the mode of the option. The following table lists each of these constants:

Constant Value Description
VALUE_NONE 1 Indicates that the option should not accept any input value from the user. This will cause the option to behave like a switch or flag and adopt a boolean value.
VALUE_REQUIRED 2 Indicates that the option is required.
VALUE_OPTIONAL 4 Indicates that the option is optional.
VALUE_IS_ARRAY 8 Indicates that the option should accept multiple values.

The following sections will take a second look at all the previously explored examples using the getOptions and getArguments instance methods. Each section will contain code samples for both methods as well as the equivalent command signature.

#Input Parameters

Input parameters require the Symfony\Component\Console\Input\InputArgument class to be imported in the current PHP file. Input parameters are defined in the getArguments instance method in the command class. The following signature will be implemented using the InputArgument:

1test:command {firstArgument}

The corresponding getArguments implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputArgument;
4 
5// Beginning of class omitted...
6 
7public function getArguments()
8{
9 return [
10 ['firstArgument', InputArgument::REQUIRED]
11 ];
12}
13 
14// End of class omitted...

In the above example you will notice that we did not have to specify a description or default value when defining the input argument, but we did have to specify a value for the mode. All of the values for the input argument have a default value, except for the name. The default value for the mode is set to InputArgument::OPTIONAL, the description has an empty string as a default value and the arguments default value is set to null by default.

#Input Parameter Default Values

The signature that will be implemented using the getArguments method is:

1test:command {firstArgument=DefaultValue}

The corresponding getArguments implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputArgument;
4 
5// Beginning of class omitted...
6 
7public function getArguments()
8{
9 return [
10 ['firstArgument', InputArgument::OPTIONAL, '', 'DefaultValue']
11 ];
12}
13 
14// End of class omitted...

It is important to note that the mode changed from InputArgument::REQUIRED to InputArgument::OPTION. Only optional arguments can have a default value. Also, an empty string has been supplied for the argument's description field.

#Adding Descriptions to Command Parameters

The signature that will be implemented using the getArguments method is:

1test:command {firstArgument : This is the description }

The corresponding getArguments implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputArgument;
4 
5// Beginning of class omitted...
6 
7public function getArguments()
8{
9 return [
10 ['firstArgument', InputArgument::REQUIRED, 'This is the description']
11 ];
12}
13 
14// End of class omitted...

#Command Options

Input options require the Symfony\Component\Console\Input\InputOption class to be imported in the current PHP file. Input options are defined in the getOptions instance method in the command class. The following signature will be implementing using the InputOption:

1test:command {--optionName}

The corresponding getOptions implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getOptions()
8{
9 return [
10 ['optionName']
11 ];
12}
13 
14// End of class omitted...

In the above example we only had to set the name of the option to optionName. When using the getOptions method we do not have to prefix option names with the double hyphen (--) prefix. Additionally, the shortcut, mode, description and default value for the option did not have to be set.

The following table details the default values that are assigned to each property of an InputOption if none are supplied:

Property Default Value
Shortcut null, meaning no shortcut will be assigned.
Mode InputOption::VALUE_NONE. This means that options by default will behave like flags or switches and assume a boolean value.
Description The description will be an empty string by default.
Default Value The default value for options is a literal value of null.

#Command Option Default Values

The signature that will be implemented using the getOptions method is:

1test:command {--optionName=DefaultValue}

The corresponding getOptions implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getOptions()
8{
9 return [
10 ['optionName', null, InputOption::VALUE_OPTIONAL, '', 'DefaultValue']
11 ];
12}
13 
14// End of class omitted...

#Adding Descriptions to Command Options

The signature that will be implemented using the getOptions method is:

1test:command {--optionName : Option description.}

The corresponding getOptions implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getOptions()
8{
9 return [
10 ['optionName', null, InputOption::VALUE_NONE, 'Option description.']
11 ];
12}
13 
14// End of class omitted...

#Command Option Shortcuts

The signature that will be implemented using the getOptions method is:

1test:command {--q|optionName}

The corresponding getOptions implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getOptions()
8{
9 return [
10 ['optionName', 'q']
11 ];
12}
13 
14// End of class omitted...

#Array Parameters

The signature that will be implemented using the getOptions method is:

1test:command {argumentName=*}

The corresponding getArguments implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getArguments()
8{
9 return [
10 ['argumentName', InputArgument::IS_ARRAY | InputArgument::REQUIRED]
11 ];
12}
13 
14// End of class omitted...

#Array Options

The signature that will be implemented using the getOptions method is:

1test:command {--optionName=*}

The corresponding getOptions implementation would be:

1<?php
2 
3use Symfony\Component\Console\Input\InputOption;
4 
5// Beginning of class omitted...
6 
7public function getOptions()
8{
9 return [
10 ['optionName', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL]
11 ];
12}
13 
14// End of class omitted...

In the above example two option mode values have been combined. If you were to specify just the InputOption::VALUE_IS_ARRAY option an error stating something similar to "Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value".

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.