Architecting Custom Artisan Commands with Advanced I/O

The Artisan CLI is one of Laravel’s most beloved features. While you’ve likely used it to migrate databases or clear caches, building your own custom commands allows you to automate repetitive administrative tasks and script complex deployments.

Let’s dive into building advanced interactive commands.

1. Creating the Command

Generate a new command skeleton:

php artisan make:command ImportUserData

Define the signature and description in the generated class:

protected $signature = 'users:import {file : The path to the CSV file} {--force : Overwrite existing users}';
protected $description = 'Import users from a CSV file with progress tracking';

2. Advanced Interactive Prompts

Instead of forcing users to pass arguments via the command line, you can make your CLI tools highly interactive using Laravel Prompts.

use function LaravelPromptstext;
use function LaravelPromptsconfirm;

public function handle()
{
    $file = $this->argument('file');

    if (!file_exists($file)) {
        $this->error("File not found!");
        // Interactively ask for the correct path
        $file = text('Please provide the correct path to the CSV file:');
    }

    if (!$this->option('force')) {
        $confirmed = confirm('Are you sure you want to import these users? Existing records may be overwritten.');
        if (!$confirmed) {
            $this->info('Import aborted.');
            return;
        }
    }

    // Proceed with import...
}

3. Using Progress Bars

If your command processes hundreds of records (like importing a CSV), a progress bar provides critical feedback to the user so they know the script hasn’t frozen.

public function handle()
{
    $users = $this->getUsersFromCsv(); // Assume this returns an array of 500 users

    $this->info("Starting user import...");

    $bar = $this->output->createProgressBar(count($users));
    $bar->start();

    foreach ($users as $user) {
        $this->performImportLogic($user);

        // Advance the progress bar
        $bar->advance();
    }

    $bar->finish();
    $this->newLine();
    $this->info("Import completed successfully!");
}

4. Scheduling Commands

Once you have built a command, you often want it to run automatically in the background. Laravel’s Task Scheduler makes this trivial.

In your routes/console.php (or app/Console/Kernel.php in older versions), you can schedule your custom command:

use IlluminateSupportFacadesSchedule;

Schedule::command('users:import /path/to/nightly.csv --force')
    ->dailyAt('02:00')
    ->onOneServer()
    ->appendOutputTo(storage_path('logs/import.log'));

The onOneServer() method is particularly important if your application is deployed across multiple load-balanced servers; it ensures the cron job only runs once, rather than on every server simultaneously.

Mastering Artisan allows you to build powerful administration interfaces that run entirely within the terminal.