OneSheep OneSheep

How to schedule cron tasks via commands in Laravel 5.4

When making applications it’s not surprising to come across a scenario where you need something to happen as a background process. For example, in our last project we needed to be able to send reminders to users via email to give them a nudge to login after x days of absence. My objective was simple, set up a cron job that gets executed daily at a specific time, after querying the Laravel database for users to email, it should then execute silently”. Doing so in Laravel turned out to be quite interesting, and this blog post is going to show you how Laravel allows you to set up custom commands that can be executed via Artisan, it’s command line utility.

Some basics about commands

If you have used Artisan for example to generate a new migration, php artisan make:migration description then you have used commands already. Our goal in creating a command here is to make sure we have an executable command that, for the sake of this example, sends users a welcome message. By the end of this blog post Laravel should be able to have artisan call: send:welcome” and at that point email users who registered at any time yesterday. I think something as simple as that is fine, after all the accepted convention about commands is a command should only do one thing.

Creating a command

To create a command we use the artisan:

php artisan make:command SendWelcomeEmailCommand

That will create a file in App\Console\Commands for our command. Inside the file, we define variables associated with the command, what it will be called by Artisan and any arguments it might take:

We end up with the following:

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
Use App\User;

class SendWelcomeEmailCommand extends Command
{

   /**
    * The name and signature of the console command.
    *
    * @var string
    */

   protected $signature = 'send:welcome';

   /**
    * The console command description.
    *
    * @var string
    */

   protected $description = 'Send a welcome email to all new users who joined yesterday.';

    private $users = null;

   /**
    * Create a new command instance.
    *
    * @return void
    */

   public function __construct()
   {
       parent::__construct();
       $from = Carbon::yesterday();
       $to = Carbon::today();
       $this->users = User::whereBetween(‘created_at’, [$from, $to])->get();
   }

   /**
    * Execute the console command.
    *
    * @return void
    */

   public function handle()
   {
       $this->users->each(function($user) {
       //send user an email here...
     }
   }
}

At the moment, our command works but it’s not yet executable on the command line. To add this command to Artisan, go to App\Console\Kernel.php to add it to commands array that Artisan looks through when looking for matches:

protected $commands = [ Commands\SendWelcomeEmailCommand::class ];

Now the command is executable!

Next up, we need to set this command to execute say, everyday at 9am. In the same file, Kernel.php, the schedule method is exactly for that so let’s go ahead and add our command to be called at that time:

    /**
    * Define the application's command schedule.
    *
    * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
    * @return void
    */

   protected function schedule(Schedule $schedule)
   {
        $schedule->command('send:welcome')
                 ->dailyAt(‘09:00’)->when(function(){
                       return !is_null($this->users);
                    }
   }

The when’ function I’ve chained to the command is there to ensure we only call this command when the returned result from the closure is true. This is just for efficiency and since we’re setting the variable in the constructor, we are able to know ahead of time if we have any users to send emails to before we invoke the handle method.

There’s a little bit more that can be added to a command such as arguments, text to display to a user after completion, even a progress bar, and each is very well documented in the Laravel documentation.


Posted on Apr 15, 2017 by

Back to all posts