Sabbir Ahmed

Sabbir Ahmed

1 month ago

Laravel Custom Commands Tutorial with Example: Master Artisan Commands

Laravel has a very good support for developers to create custom commands to use globally anywhere in the project. There are built in custom commands surely, but you can create custom commands to boost your workflow. These commands you can use anytime for any functionality in the application. You can use it for test purpose or for automating the processes like sending notifications, emails to users periodically. For even database operations you can use these commands too. 

Laravel uses artisan CLI which provides developers a lot of built in commands to make the workflow flexible. For example, our favourite "php artisan serve". When working in this framework, we need to use many php artisan command in every steps. Besides that, you can create your own artisan commands by just following some easy steps. In this article, we will see how we can create own commands quickly, dive deeper by seeing multiple examples in different scenarios. 

Level Up Your Development: A Guide to Building Custom Artisan Commands in Laravel 


To create custom artisan command, you can start with running this command first: 


php artisan make:command CustomCommand

This command will create a file named CustomCommand.php under app/Console/Commands directory.

  • Lets add logic to our command


In the file, you will have a handle() function, which runs the logic when you execute the command. 

You can also take arguments from command, in that case you have to mention the argument like this: {argument}


namespace App\Console\Commands;

use Illuminate\Console\Command;

class CustomCommand extends Command
{
    protected $signature = 'custom:command {argument}';
    protected $description = 'Description of your custom command';

    public function handle()
    {
        // Logic for your command goes here
        $argument = $this->argument('argument');
        $this->info("Argument passed: $argument");
    }
}

Here, in the $signature, we are assigning the pattern, how our command would be like. Also it will take an argument from the command as assigned in {argument}

With info method, we are just displaying a message with the given argument value. 

  • Now Register your command 


Now you need to register your command in app/Console/Kernel.php


protected $commands = [
    Commands\CustomCommand::class,
];

  • Run the command


Now you can run your command like this: 


php artisan custom:command MyFirstCommand

  • Example 1: Generate user data


Lets see some example now. Assume, you want to add some dummy data to users table and you want to make your own command to do that. You can create a new command named GenerateDummyData with above process. 

Now you can add the logics like this: 


namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\User;

class GenerateDummyData extends Command
{
    protected $signature = 'generate:dummy-data {count}';
    protected $description = 'Generate dummy data for testing purposes';

    public function handle()
    {
        $count = (int)$this->argument('count');
        
        // Generate and save dummy data
        for ($i = 0; $i < $count; $i++) {
            User::create([
                'name' => 'Dummy User ' . $i,
                'email' => 'dummy' . $i . '@example.com',
                'password' => bcrypt('password'),
            ]);
        }
        
        $this->info("$count dummy users created successfully.");
    }
}

Note: the command will take the count argument for deciding how many users data should be generated. 

Now you can run the command like: 


php artisan generate:dummy-data 5

  • Example 2: Send an email with the command


We can also create custom command for sending an user email. Lets say you want to test sending all users a notification. So you can make command file like this: 


namespace App\Console\Commands;

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

class SendEmailNotifications extends Command
{
    protected $signature = 'send:email-notifications';
    protected $description = 'Send email notifications to all users';

    public function handle()
    {
        $users = User::all();

        foreach ($users as $user) {
            Mail::to($user->email)->send(new NotificationMail($user));
        }

        $this->info('Email notifications sent successfully.');
    }
}

A Hands-on Guide to Database Management With Laravel's Custom Commands


When working with database locally, or also in servers like testing and staging, sometimes we need to interact directly with database to save time or remove a buggy data from a table. If you want to handle these actions with codes, it will take a good amount of time. Wont that be better, if you could write a single command to do all those in backend in a swift? Sometimes we may need these kind of techniques to use, lets demonstrate an example how to interact with databases with custom commands. 

  • How to use custom commands for database operations?


Lets assume that, in our application we have multiple databases like database1 and database2, both are functioning together. These are test databases that we are trying to do some experiments. Now lets see, how we can clean the databases from a single command in a Laravel app.  

After creating a fresh laravel application, you can follow this database structure for this lesson: 

.env file: 


    
# Primary Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=primary_database
DB_USERNAME=root
DB_PASSWORD=secret

# Secondary Database
DB2_CONNECTION=mysql
DB2_HOST=127.0.0.1
DB2_PORT=3306
DB2_DATABASE=secondary_database
DB2_USERNAME=root
DB2_PASSWORD=secret

And in config/database.php: 


    
<?php

return [

    'default' => env('DB_CONNECTION', 'mysql'),

    'connections' => [

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

        'mysql2' => [
            'driver' => 'mysql',
            'host' => env('DB2_HOST', '127.0.0.1'),
            'port' => env('DB2_PORT', '3306'),
            'database' => env('DB2_DATABASE', 'forge'),
            'username' => env('DB2_USERNAME', 'forge'),
            'password' => env('DB2_PASSWORD', ''),
            'unix_socket' => env('DB2_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],

    ],

];

Now, lets create a new command named DropAllTables: 


    
php artisan make:command DropAllTables

A new command file will be generated under app/Console/Commands/DropAllTables.php. Lets modify the file like our expected requirements: 


    
namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class DropAllTables extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'db:drop-tables {--database= : The database connection to use}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Drop all tables in the specified database';

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        $connection = $this->option('database') ?: config('database.default');
        $this->info("Using connection: $connection");

        $schemaBuilder = Schema::connection($connection);
        $tables = DB::connection($connection)->select('SHOW TABLES');

        // Dynamically get the property name
        $tableProperty = 'Tables_in_' . DB::connection($connection)->getDatabaseName();

        DB::connection($connection)->statement('SET FOREIGN_KEY_CHECKS=0;');

        foreach ($tables as $table) {
            $tableName = $table->$tableProperty;
            $schemaBuilder->drop($tableName);
            $this->info("Dropped table: $tableName");
        }

        DB::connection($connection)->statement('SET FOREIGN_KEY_CHECKS=1;');

        $this->info("All tables dropped successfully.");
    }
}

We have named the command as db:drop-tables, as we are dropping all the tables in our selected database. To specify or select which database to use for the command, we have kept a flag where we can pass the connection name to use defined in config/database.php.

In the handle method, with $schemaBuilder, we are getting the schema for the connection, and after fetching all the tables in $tables. 

In the foreach, for every table, first we getting the table name, and dropping the table with our $schemaBuilder. 

Also when dropping tables, there might be foreign dependencies, and those foreign keys sometime blocks the drop operation because of dependent data in other tables. To prevent that we have to turn off the foreign check for database. For that, we are passing the related query in statement method. After we are done dropping all the tables, we are turning the checks back active.

Along the way, we are showing in the console the status of every actions as message with info method. 

Now register the command in  app/Console/Kernel.php:


    
protected $commands = [
    \App\Console\Commands\DropAllTables::class,
];

And then run the code in console: 


    
php artisan db:drop-tables --database=mysql

That will efficiently clean all the tables for your database. But be careful please, because this type of operations are dangerous and they can delete all the important data also if you have any. Be sure to have a backup if you require. It is a quick demo to work with custom commands for database operation. Feel free to modify the logics as you need, but the point is simplification and being smart about your workflow. 

Some Tips and Tricks


  • Styling Command Output


To make it easier to read and understand, you can stylize your command line like this:


                
public function handle()
{
    $this->line('Standard message');
    $this->info('Info message');
    $this->error('Error message');
}

This will help to make the command line user friendly, specially in multi step processes.

  • Progress Bar for Lengthy Processes


You can add a progress bar for long running processes like importing like datasets:


                
public function handle()
{
    $users = User::all();
    $bar = $this->output->createProgressBar(count($users));

    foreach ($users as $user) {
        // Process user data
        $bar->advance();
    }

    $bar->finish();
    $this->info('Processing complete!');
}

This displays a visual indication of current progress which will improve user experience.

  • Scheduling Commands Automatically


Laravel has task scheduler which can help you to run commands at specified intervals. For example, perodic tasks like sending newsletters or clearing up data. This helps to automate the processes in the application.

In app/Console/Kernel.php:


                
protected function schedule(Schedule $schedule)
{
    $schedule->command('send:email-notifications')->dailyAt('08:00');
}

This example shows, how we can schedule to send an email notification daily at 8AM to user by triggering specific command written for this.

  • User Interactive Console Input


You can also prompt users for input and take necessary action based on user's feedback:


                
public function handle()
{
    if ($this->confirm('Do you wish to proceed?')) {
        $name = $this->ask('What is your name?');
        $this->info("Hello, $name!");
    } else {
        $this->info("Command cancelled.");
    }
}

This adds flexibility for users and they can interact with command line real time.

Summary


I hope you got the big picture about creating and using custom commands.

Generating your own custom commands just feels like setting up your own environment to work with. Working with command lines is a integral part for every developer. Considering that, having your own custom commands will make your workflow faster and effective. 

What is your thoughts, I am very interest to know. Please let me know in the comments below. 

I wish you a happy day. 

Comments

Login As User
Word Count: 0