Creating Artisan commands — make:command, $signature, $description
Concept
Arguments, options, and interactive input make Artisan commands usable by both humans and scheduled processes.
Arguments: Positional values required (or optional) from the command line. {name} = required. {name?} = optional. {name=default} = with default. {names*} = variadic (array of values).
Options: Named flags. {--force} = boolean (present or not). {--count=} = option with required value. {--count=10} = option with default value. {--C|count=} = with short alias -C.
Accessing in handle(): $this->argument('name'), $this->arguments() (all), $this->option('force'), $this->options() (all).
Interactive input:
$this->ask(string $question, $default = null): Free-text prompt.$this->secret(string $question): Hidden input (for passwords).$this->confirm(string $question, bool $default = false): Yes/no prompt. Returns bool.$this->choice(string $question, array $choices, $default = null): Selection from list.$this->anticipate(string $question, array $choices): Auto-completing prompt.
$this->runningInConsole(): Check if running in console context (vs HTTP). Actually use app()->runningInConsole().
Production safeguard: Use $this->confirm('Are you sure? This affects production!') before destructive operations.
Code Example
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ImportUsers extends Command
{
protected $signature = 'users:import
{file : Path to the CSV file}
{--skip-header : Skip the first row (header)}
{--batch=100 : Batch size for processing}
{--dry-run : Validate without actually importing}
{--email=* : Only import users with these emails}';
protected $description = 'Import users from a CSV file';
public function handle(): int
{
$file = $this->argument('file');
$batch = (int) $this->option('batch');
$dryRun = $this->option('dry-run');
$emails = $this->option('email'); // array
// Validation
if (!file_exists($file)) {
$this->error("File not found: {$file}");
return self::FAILURE;
}
// Interactive confirmation in production
if (!$this->option('dry-run') && app()->isProduction()) {
if (!$this->confirm('You are running this in PRODUCTION. Continue?')) {
$this->line('Aborted.');
return self::SUCCESS;
}
}
// Dynamic option asking
$sendWelcome = $this->confirm('Send welcome emails to imported users?', false);
// Reading with access to all option types
$this->info("Config:");
$this->table(
['Setting', 'Value'],
[
['File', $file],
['Batch size', $batch],
['Dry run', $dryRun ? 'Yes' : 'No'],
['Welcome mail', $sendWelcome ? 'Yes' : 'No'],
['Email filter', $emails ? implode(', ', $emails) : 'None'],
]
);
// Process
// ...
return self::SUCCESS;
}
}
// Calling with options
// php artisan users:import users.csv
// php artisan users:import users.csv --skip-header --batch=500
// php artisan users:import users.csv --dry-run
// php artisan users:import users.csv --email=a@b.com --email=c@d.com
// php artisan users:import users.csv -vvv (verbose output)