Custom artisan Command Example

Sometimes 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 temporary tables at the end of the day, you will need a task scheduling mechanism to take care of the tasks. Laravel provides in built scheduler and it's methods for calling it.

We can run those command with scheduler to run Cron job on server.

In this example, first of all we will create users model and feed some data into it. then we set up Cron job which runs midnight and check birthday from user and send birthday wishes using mail functionality.

To create custom command we have split our tutorial into these parts :

  • Step 1: Mail and Database Configuration
  • Step 2: Update User Migration
  • Step 3: Seeding Dummy Data to User
  • Step 4: Create Mailable for Birthday Wishes
  • Step 5: Create Artisan Command
  • Step 6: Scheduling Artisan Command
  • Step 7: Testing Our Application / Functionality

Mail and Database Configuration

First of all, let's configure our database and mail server configuration into our application. For that open .env file from root directory of your project. if .env file is missing from project then copy content from .env.example and create file. .env file defines many common environment variables

    
//Database Configuration
DB_CONNECTION=mysql  
DB_HOST=127.0.0.1
DB_PORT=3306  
DB_DATABASE=database_name
DB_USERNAME=database_username
DB_PASSWORD=password

//Mail configuration
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=mail_address
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=admin@example.com
MAIL_FROM_NAME="${APP_NAME}"
    

Update User Migration

In this example, we will use default User model you can use other model if required. In this model we need to add date of birth column to users table. Update migration as below :

    
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->date('dob'); //Add this line
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}
    

Here we have added dob column with date data type. We will use this field for check user's birthday.

Seeding Dummy Data to User

If you have existing user base then you don't need to follow this step. With fresh application we don't have any data into user table. For that we will use Seeding functionality.

database\factories\UserFactory.php

    
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'dob' => $this->faker->date(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
    public function unverified()
    {
        return $this->state(function (array $attributes) {
            return [
                'email_verified_at' => null,
            ];
        });
    }
}
    

Let's Create Seeder to call factory. Open terminal and enter below command.

    
php artisan make:seeder UserSeeder
    

This command will create UserSeeder.php at database\seeders directory. Let's modify it to create user with factory class.

database\seeders\UserSeeder.php

    
<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
    public function run()
    {
        User::factory()
            ->count(100)
            ->create();
    }
}
    

This Logic will create new 100 users to database. You can change users count as per you requirement.

Create Mailable for Birthday Wishes

In this step, we will create mailable class for sending specific mail to users. Open terminal and enter below command :

    
php artisan make:mail HappyBirthday
    

It will create two files. First it will create mailable class with name HappyBirthday.php at app\Mail directory and view file is resources\views\mail\happy-birthday.blade.php. Let's modify those files one by one :

app\Mail\HappyBirthday.php

    
<?php

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class HappyBirthday extends Mailable
{
    use Queueable, SerializesModels;

    protected $user;
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function build()
    {
        return $this->subject('Happy Birthday From Codewolfy' )
                ->markdown('mail.happy-birthday')
                ->with('user', $this->user);
    }
}
    

We have passed user model to it's construct method and then we set subject and view for mail. Here we have also passed User to view using with() method. This User model can used into our markdown file.

resources\views\mail\happy-birthday.blade.php

    
@component('mail::message')
# Happy Birthday {{$user->name}}
It's your special day — get out there and celebrate!

Thanks,
{{ config('app.name') }} @endcomponent

Create Artisan Command

Now, we ready to create artisan command for birthday wishes. Here we will use make:command to create out custom artisan command like below :

    
php artisan make:command BirthdayWish
    

This command will create BirthdayWish.php at App\console\commands. Our logic for check birthday and send mail will be written here. The Artisan command can be divided into Four parts :

  1. Command Signature : This protected variable define command signature for command like birthday:wish. This will set php artisan birthday:wish to run our custom command.
  2. Command Description : This variable holds command description for user understanding.
  3. Construct() Method : Required logic which we need while calling this command
  4. Handle() Method : Entire logic for our command need to add into this function.

App\console\commands\BirthdayWish.php

    
<?php

namespace App\Console\Commands;

use App\Mail\HappyBirthday;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;

class BirthdayWish extends Command
{
    protected $signature = 'birthday:wish';

    protected $description = 'This command will run everyday and send birthday wishes to users.';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        $today = Carbon::now();
        $birthdays = User::whereMonth('dob', '=', $today->month)
            ->whereDay('dob', '=', $today->day)
            ->get();

        foreach($birthdays as $birthday)
        {
            Mail::to($birthday->email)->queue(new HappyBirthday($birthday));
            $this->info("Birthday Wishes Sent to ".$birthday->name);
        }
        return COMMAND::SUCCESS;
    }
}
    

Into handle method first of all we will get birthday users and then we will loop through them. In this loop, we added two statement. First will add into mail queue and second will print message to console.

Now our custom command is ready to use. We can manually run it or schedule it as cron job using Laravel scheduler.

Scheduling Artisan Command

Laravel provides in-built functionality to schedule cron jobs. We can schedule our newly created command to run at specific time Let's schedule our command to run at midnight.

App\Console\Kernel.php

    
<?php

namespace App\Console;

use App\Console\Commands\BirthdayWish; //import
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    protected $commands = [
        BirthdayWish::class,
    ];

    protected function schedule(Schedule $schedule)
    {
        //This sets command to at 12AM
        $schedule->command('birthday:wish')->dailyAt('00:00');
    }

    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}
    

Testing Our Application / Functionality

You can test command using terminal or using task scheduling. Here we will test our custom artisan command using terminal.

    
php artisan birthday:wish
    

This will print Birthday Wishes Sent to USER for each birthday user into terminal. It will not print those messages while calling scheduler.


Share your thoughts

Ask anything about this examples