There are times when your application needs to run administrative tasks periodically on the server. Whether you want to send out emails to your users or clean up the database tables at the end of the day, you will need a task scheduling mechanism to take care of the tasks, when it’s time.
Cron is a task scheduler in unix-like systems, which runs shell commands at certain intervals. This article is not meant for introducing Cron, but since it is a key concept in our tutorial, we’ll will describe the basics of how it works.
Cron basics
Cron is a task scheduler daemon which runs scheduled tasks at certain intervals. Cron uses a configuration file called crontab, also known as cron table, to manage the scheduling process.
Crontab contains cron jobs, each related to a specific task. Cron jobs are composed of two parts, the cron expression, and a shell command to be run:
* * * * * command/to/run
Each field in the above expression (* * * * *
) is an option for setting the schedule frequency. It is composed of minute, hour, day of month, month and day of week in order of the placement. The asterisk symbol refers to all possible values for the respective field. As a result, the above cron job will be run every minute in the day.
The following cron job is executed at 12:30
every day:
30 12 * * * command/to/run
This is just the tip of the Cron iceberg; to learn more about it, you might want to visit the wikipedia page.
In PHP powered applications, administrative tasks are normally standalone PHP scripts which are run in CLI mode. These scripts are written for performing different jobs at certain times.
However, we can’t do much without the power of other PHP libraries and frameworks. In this article, you will learn how to use the Laravel framework to create robust PHP scripts for the command line and schedule them right from the source code.
Creating Commands in Laravel
Creating a command in PHP is as simple as creating a PHP script, then running it in the command line, using the php
command:
php somefile.php
As you can see, the file is passed as an argument to the command php
.
Whether your application has been developed in Laravel, or you just want to use its facades and helpers to create your scripts, you will need to bootstrap Laravel before using it. However, there’s a better alternative to this: creating a Laravel Artisan command.
When using Artisan commands, we will have access to all features of Laravel, including helpers, facades, and other Artisan commands, just to name a few.
We’re not going to go into the details of Artisan commands here, as they’re beyond the scope of this tutorial, but let’s discuss the basics, just to get started. We’ll will be using the latest version of Laravel, which is 5.1
at the time of writing this article.
We use the make:console
Artisan command to generate a command class skeleton to work with. As an example, we’re going to create a command which sends a happy birthday SMS message to our users on their birthday.
$ php artisan make:console HappyBirthday --command=sms:birthday
The above command will create a class named HappyBirthday
in a file of the same name in theapp/Console/Commands
directory. We also picked a name for the command via the command
option. This is the name that we’ll use when calling the command.
Now let’s open the file, and see what we have so far. There are several properties and methods inside the class that build the command’s backend:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class HappyBirthday extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'sms:birthday'; /** * 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() { // } }
For the $description
, we can put a simple description of what the command does when executed.
protected $description = 'Sends a Happy birthday message to users via SMS';
In Laravel 5.1
, whenever a command is executed in the terminal, the handle
method of the command class is called. That’s where we need to put our logic.
In our case, to send a birthday message to users on their birthday, we can modify handle
method like so:
<?php // ... public function handle() { User::whereBirthDate(date('m/d'))->get(); foreach( $users as $user ) { if($user->has('cellphone')) { SMS::to($user->cellphone) ->msg('Dear ' . $user->fname . ', I wish you a happy birthday!') ->send(); } } $this->info('The happy birthday messages were sent successfully!'); }
Once the command is finished, we need to register it with Artisan, so that it will be available in the terminal. To do this, we just need to add the command’s classname to the commands
array of theKernel
class, which is located at app/Console/Kernel.php
:
<?php class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $commands = [ // ... 'App\Console\Command\HappyBirthday' ]; // ...
If we run php artisan list
in the terminal, we will see our command’s description:
$ php artisan list ... sms sms:birthday Sends a Happy birthday to users via SMS ...
It’s a good habit to namespace the command names. This will help us categorize them based on their usage.
As a result, whenever we run the command in the terminal, a happy birthday message would be sent to the matched group of users:
$ php artisan sms:birthday The happy birthday messages were sent successfully!
This is just a hypothetical use case. For a more concrete example, see Younes Rafie’s post about a minification command.
Scheduling the Commands
Here comes the fun part. Let’s schedule a task for running the command we just built. To do this, we’ll use a feature you’ll undoubtedly come to love: Laravel Task Scheduler.
The tasks are defined inside the schedule
method of the Kernel
class. We can add as many Artisan commands as we need by using the command
method.
Our task, according to its usage, is supposed to be run once a day. So we can use the daily()
method like so:
<?php // ... protected function schedule(Schedule $schedule) { $schedule->command('sms:birthday')->daily(); }
We can schedule all the commands right from the schedule
method. As the documentation states, there are a variety of schedule frequencies we may assign to the tasks. We’ll list a few of them here, but you may want to read the documentation to see the full list and decide which best suits your circumstances.
To run a task every hour every day:
<?php $schedule->command('myTask') ->hourly();
To run a task every day at midnight:
<?php $schedule->command('myTask') ->daily();
To run a task every day at 9:30:
<?php $schedule->command('myTask') ->dailyAt('09:30');
To run a task every week:
<?php $schedule->command('myTask') ->weekly();
To run it every month:
<?php $schedule->command('myTask') ->monthly();
We can also use a custom cron schedule, like an ordinary cron job expression:
$schedule->command('myTask') ->cron('* * * * *');
The above task will be run every minute.
To see the full list of options, please refer to the documentation, section Schedule Frequency Options.
Laravel also provides a set of schedule constraints, which can be combined with the above methods. For instance, we can schedule a task to be run weekly, but limit it to a certain day and hour.
<?php $schedule->command('theTask') ->weekly() ->mondays() ->at(12:30);
or
<?php $schedule->command('theTask') ->weekly() ->sundays()
We can go further and limit the execution of the task to a certain condition, using the when
method which accepts a closure. The task will be executed only if the closure returns true.
<?php $schedule->command('table:clean') ->daily() ->when(function() { return SMS::isWorkingFine(); });
Starting the Laravel Scheduler
To start the scheduler itself, we only need to add one cron job on the server (using the crontab -e
command), which executes php /path/to/artisan schedule:run
every minute in the day:
* * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1
Please note that we need to provide the full path to the Artisan command of our Laravel installation.
To discard the cron output we put /dev/null 2>&1
at the end of the cronjob expression.
To read more about the Scheduler, see the Scheduling chapter in the documentation.
Conclusion
In this tutorial, we made use of Laravel Artisan commands to create terminal commands. Rather than add many cron job entries on the server per task, we only created one which is executed every minute and delegates responsibility to Laravel’s task scheduler.
By using custom Artisan commands alongside Laravel’s task scheduler, we can focus on creating the commands and Laravel will take care of the rest. In addition to this, the scheduling frequencies are manageable by other team members since it is now tracked by the version control system.
If you have an questions or comments, please post them below and we’ll do our best to reply in a timely manner.
Be the first one to write a response :(
{{ reply.member.name }} - {{ reply.created_at_human_readable }}