How to create a custom console command (artisan) for Laravel 5.3

How to create a custom console command (artisan) for Laravel 5.3

Laravel has a command-line interface named Artisan. This interface provides the developer a lot of useful commands to speed up the development process.

Furthermore, you may want to extend artisan with your own commands to create and automatizate the unique tasks of your Laravel project. Commands are typically stored in the app/Console/Commands directory however, you are free to choose your own storage location as long as your commands can be loaded by Composer.

In this article, you'll learn how to create a custom command for artisan easily in Laravel 5.3.

Create and register command

Laravel help you to do everything easier, it has already integrated the make:console NewClassName command to speed up your development process. This command expects as first argument the name of the class and optionally, the command option to specify directly the name of the command without modify the class.

To create a new console command named quiz:start with class name QuizStart execute the following command in your console :

php artisan make:command QuizStart --command=quiz:start

Note: in case you don't want to use the console, copy the example class in "Structure of a command"and change the name of the file and class as you wish. Remember too that in previous versions of Laravel < 5.2, instead of make:command, you'll need to use make:console.

This should create a QuizStart class in the /app/console/commands directory with App\Console\Commands namespace.

Finally, our command is not registered, therefore we need to add it into our /app/console/Kernel.php file in the $commands array (provide the class path and name):

protected $commands = [
    // Commands\Inspire::class,
    'App\Console\Commands\QuizStart'
];

Use php artisan cache:clear to clear the cache and try executing your command with the previous given name:

php artisan quiz:start

As expected, this command should do nothing, now you only need to learn how to deal with the command.

Structure of a command

To customize the name of your command and description, change the name directly in the class and all the logic of the command will be stored in the handle function.

<?php
#/App/Console/Commands/QuizStart.php
namespace App\Console\Commands;

use Illuminate\Console\Command;

class QuizStart extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'quiz:start';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

Print text

To send output to the console, you can choose between the following method : line, info, comment, question and error methods. Each of these methods will use appropriate ANSI colors for their purpose.

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $this->line("Some text");
    $this->info("Hey, watch this !");
    $this->comment("Just a comment passing by");
    $this->question("Why did you do that?");
    $this->error("Ops, that should not happen.");
}

Command input : arguments and options

Expect arguments and options in the command

If you don't set which parameters or options expects your function, your command will be unable to work, even if you execute it with parameters.

In Laravel, in the signature property (command name) is where we define our arguments and options, directly in the string (unlike older versions of Laravel) :

/**
 * The name and signature of the console command.
 *
 * @var string
 */
protected $signature = 'quiz:start {user} {age} {--difficulty=} {--istest=}';

The arguments are registered in our commannd with the simple syntax of {argumentName} and the options as {--optionName=}. so now we don't need to create the get options and get arguments methods in our class.

It's syntax is very simple to understand, basically these are all the ways to use arguments and options in our command (if you want more details, please read the docs):

  • Argument: quiz:start {argument}.
  • Optional Argument (note the question mark next to the argument name): quiz:start {argument?}.
  • Argument with default value: quiz:start {argument=defaultValue}.
  • Boolean Option: quiz:start --myOption.
  • Option with Value: quiz:start --myOption=.
  • Option with Value and Default: quiz:start --myOption=12.

Retrieve arguments and options values

If your command needs some values to work (parameters), you'll need to access these values to use them in your command. To achieve this task, you can use the argument and option methods :

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    // Get single Parameters
    $username = $this->argument('user');
    $difficulty = $this->option('difficulty');

    // Get all
    $arguments = $this->arguments();
    $options = $this->options();

    // Stop execution and ask a question 
    $answer = $this->ask('What is your name?');

    // Ask for sensitive information
    $password = $this->secret('What is the password?');

    // Choices
    $name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default);

    // Confirmation

    if ($this->confirm('Is '.$name.' correct, do you wish to continue? [y|N]')) {
        //
    }
}

Example

The following function will create an interactive quiz in the console and you need to answer all of them. Once the quiz has been filled out, it will show the answers that you typed.

/**
 * Execute the console command.
 *
 * @return mixed
 */
public function handle()
{
    $difficulty =  $this->option('difficulty');

    if(!$difficulty){
        $difficulty = 'easy';
    }

    $this->line('Welcome '.$this->argument('user').", starting test in difficulty : ". $difficulty);

    $questions = [
        'easy' => [
            'How old are you ?', "What is the name of your mother?",
            'Do you have 3 parents ?','Do you like Javascript?',
            'Do you know what is a JS promise?'
        ],
        'hard' => [
            'Why the sky is blue?', "Can a kangaroo jump higher than a house?",
            'Do you think i am a bad father?','why the dinosaurs disappeared?',
            "why don't whales have gills?"
        ]
    ];

    $questionsToAsk = $questions[$difficulty];
    $answers = [];

    foreach($questionsToAsk as $question){
        $answer = $this->ask($question);
        array_push($answers,$answer);
    }

    $this->info("Thanks for do the quiz in the console, your answers : ");

    for($i = 0;$i <= (count($questionsToAsk) -1 );$i++){
        $this->line(($i + 1).') '. $answers[$i]);
    }
}

Laravel artisan quiz

Executing a command from a controller or route

Obviously, as we used the ask method, it shouldn't work however for other methods you would be able to execute the command using :

$exitCode = Artisan::call('quiz:start', [
    'user' => 'Carlos', '--difficulty' => 'hard'
]);

If you need more information about artisan, you can read the documentation here. Have fun !

Become a more social person