Artisan Console Commands
Artisan Console Commands
Artisan is Laravel's command-line interface, providing dozens of helpful commands for building your application. Beyond using built-in commands, you can create custom commands to automate tasks, run scheduled jobs, process data, and more. This lesson covers creating and working with custom Artisan commands.
Understanding Artisan Commands
Artisan commands are PHP classes that can be executed from the command line. They're perfect for:
- Automated tasks and cron jobs
- Data processing and imports
- Database maintenance and cleanup
- Generating reports
- Sending notifications or emails in bulk
- Running tests or health checks
// Generate a new command
php artisan make:command SendNewsletterCommand
// app/Console/Commands/SendNewsletterCommand.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class SendNewsletterCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'newsletter:send';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send newsletter to all subscribers';
/**
* Execute the console command.
*/
public function handle()
{
$this->info('Sending newsletter...');
// Command logic here
$this->info('Newsletter sent successfully!');
return Command::SUCCESS;
}
}
app/Console/Commands directory. You can run your command with php artisan newsletter:send.
Command Signature and Arguments
The command signature defines how the command is called, including arguments and options:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class UserManagementCommand extends Command
{
// Simple command
protected $signature = 'user:create';
// With required argument
protected $signature = 'user:create {name}';
// With optional argument
protected $signature = 'user:create {name?}';
// With default value
protected $signature = 'user:create {name=John}';
// With argument description
protected $signature = 'user:create {name : The name of the user}';
// Multiple arguments
protected $signature = 'user:create {name} {email}';
// With option (flag)
protected $signature = 'user:create {name} {--admin}';
// Option with value
protected $signature = 'user:create {name} {--role=}';
// Option with default value
protected $signature = 'user:create {name} {--role=user}';
// Option shortcut
protected $signature = 'user:create {name} {--R|role=}';
// Option array
protected $signature = 'user:create {name} {--role=*}';
// Complete example
protected $signature = 'user:create
{name : The user name}
{email : The user email}
{--admin : Make user an administrator}
{--role=* : Assign roles to user}
{--force : Force creation without confirmation}';
protected $description = 'Create a new user account';
public function handle()
{
// Access arguments
$name = $this->argument('name');
$email = $this->argument('email');
// Access options
$isAdmin = $this->option('admin');
$roles = $this->option('role');
$force = $this->option('force');
// Get all arguments/options
$allArguments = $this->arguments();
$allOptions = $this->options();
return Command::SUCCESS;
}
}
// Usage examples:
// php artisan user:create "John Doe" john@example.com
// php artisan user:create "Jane" jane@example.com --admin
// php artisan user:create "Bob" bob@example.com --role=editor --role=author
// php artisan user:create "Alice" alice@example.com --force -R admin
Interactive Input and Output
Commands can interact with users through various input and output methods:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class InteractiveCommand extends Command
{
protected $signature = 'app:interactive';
protected $description = 'Demonstrate interactive input/output';
public function handle()
{
// Output methods
$this->info('This is informational text');
$this->comment('This is a comment');
$this->question('This is a question');
$this->error('This is an error message');
$this->warn('This is a warning');
$this->line('This is plain text');
// New line
$this->newLine();
$this->newLine(3); // Three blank lines
// Ask for input
$name = $this->ask('What is your name?');
$email = $this->ask('What is your email?', 'default@example.com');
// Secret input (password)
$password = $this->secret('What is the password?');
// Confirmation
if ($this->confirm('Do you want to continue?')) {
$this->info('Continuing...');
}
// Confirmation with default
if ($this->confirm('Delete all records?', false)) {
// Only runs if user explicitly confirms
}
// Choice selection
$role = $this->choice(
'What role should the user have?',
['admin', 'editor', 'viewer'],
0 // Default index
);
// Multiple choice
$roles = $this->choice(
'Select roles (separate multiple with comma)',
['admin', 'editor', 'viewer'],
0,
$maxAttempts = null,
$allowMultipleSelections = true
);
// Anticipate - autocomplete
$country = $this->anticipate('Select country', ['USA', 'UK', 'Canada']);
// Table output
$this->table(
['Name', 'Email', 'Role'],
[
['John Doe', 'john@example.com', 'Admin'],
['Jane Smith', 'jane@example.com', 'Editor'],
]
);
return Command::SUCCESS;
}
}
confirm() for destructive operations to prevent accidents.
Progress Bars and Task Tracking
For long-running operations, progress bars provide visual feedback:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\User;
class ProcessUsersCommand extends Command
{
protected $signature = 'users:process';
protected $description = 'Process all users';
public function handle()
{
$users = User::all();
// Simple progress bar
$bar = $this->output->createProgressBar($users->count());
$bar->start();
foreach ($users as $user) {
// Process user
$this->processUser($user);
$bar->advance();
}
$bar->finish();
$this->newLine();
// withProgressBar helper
$this->withProgressBar($users, function ($user) {
$this->processUser($user);
});
$this->newLine();
return Command::SUCCESS;
}
protected function processUser($user)
{
// Simulate processing
sleep(0.1);
}
}
Calling Other Commands
Commands can call other Artisan commands programmatically:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
class DeployCommand extends Command
{
protected $signature = 'app:deploy';
protected $description = 'Deploy the application';
public function handle()
{
$this->info('Starting deployment...');
// Call another command
$this->call('down');
// Call with arguments and options
$this->call('migrate', [
'--force' => true,
]);
// Call silently (no output)
$this->callSilently('db:seed');
// Call and capture output
$exitCode = $this->call('config:cache');
if ($exitCode === 0) {
$this->info('Config cached successfully');
}
// Using Artisan facade
Artisan::call('optimize');
// Get output from Artisan facade
Artisan::call('inspire');
$output = Artisan::output();
$this->line($output);
$this->call('up');
$this->info('Deployment complete!');
return Command::SUCCESS;
}
}
Dependency Injection in Commands
Commands support dependency injection in the handle method:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\ReportGenerator;
use App\Services\EmailService;
use Illuminate\Support\Facades\Storage;
class GenerateReportCommand extends Command
{
protected $signature = 'report:generate {type}';
protected $description = 'Generate and email reports';
/**
* Dependencies injected into handle method
*/
public function handle(
ReportGenerator $generator,
EmailService $emailService
) {
$type = $this->argument('type');
$this->info("Generating {$type} report...");
// Use injected services
$report = $generator->generate($type);
$filename = "report-{$type}-" . now()->format('Y-m-d') . '.pdf';
Storage::put("reports/{$filename}", $report);
$this->info('Report generated: ' . $filename);
if ($this->confirm('Email the report?')) {
$email = $this->ask('Email address?');
$emailService->sendReport($email, $report);
$this->info('Report emailed to ' . $email);
}
return Command::SUCCESS;
}
}
Scheduling Commands
Commands can be scheduled to run automatically using Laravel's task scheduler:
// app/Console/Kernel.php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule): void
{
// Run command every day at midnight
$schedule->command('newsletter:send')
->daily();
// Run command every hour
$schedule->command('backup:database')
->hourly();
// Run command with arguments and options
$schedule->command('report:generate monthly --email')
->monthlyOn(1, '09:00');
// Using call method
$schedule->call(function () {
// Closure logic
})->everyFifteenMinutes();
// Frequency options
$schedule->command('emails:send')->everyMinute();
$schedule->command('backup:run')->everyFiveMinutes();
$schedule->command('report:weekly')->weekly();
$schedule->command('cleanup')->dailyAt('13:00');
$schedule->command('invoice:generate')->monthlyOn(15, '08:00');
// Conditional scheduling
$schedule->command('emails:send')
->daily()
->when(function () {
return date('w') !== 0; // Don't run on Sundays
});
// Prevent overlaps
$schedule->command('process:large-dataset')
->hourly()
->withoutOverlapping();
// Run in background
$schedule->command('backup:run')
->daily()
->runInBackground();
// Send output to file
$schedule->command('report:generate')
->daily()
->sendOutputTo(storage_path('logs/report.log'));
}
}
// Setup cron job to run scheduler (only once):
// * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
users:cleanup that deletes users who haven't logged in for over 180 days. Add a --dry-run option to preview what would be deleted without actually deleting. Show a confirmation prompt before deleting (unless --force is used). Display a table of users to be deleted and use a progress bar during deletion.
report:sales command that accepts {period} argument (daily/weekly/monthly) and generates a sales report. Ask for email recipients interactively if --email option is present. Inject ReportGenerator and EmailService dependencies. Display report summary in a formatted table and save the report to storage.
db:backup-and-optimize command that calls multiple commands in sequence: backs up the database, runs migrations, optimizes tables, and clears old logs. Add proper error handling and rollback if any step fails. Schedule it to run daily at 3 AM in the Kernel.
Summary
Artisan commands are powerful tools for automating Laravel applications:
- Command Signature: Define arguments and options flexibly
- Interactive I/O: Ask questions, show progress, format output
- Calling Commands: Execute other commands programmatically
- Dependency Injection: Inject services into handle method
- Scheduling: Automate command execution with cron
- Return Codes: Use Command::SUCCESS and Command::FAILURE
With Eloquent advanced queries, API Resources, the Service Container, Service Providers, and Artisan Commands, you now have a comprehensive understanding of Laravel's core architecture and can build sophisticated applications efficiently.