Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Custom Artisan commands

Importing products from a file, a mailing, cleaning up stale data — such tasks are started from the terminal or on a schedule rather than from a browser. You write your own Artisan commands for them: they have access to the whole application — models, mail, queues.

Creating

php artisan make:command SendWeeklyReport

The class appears in app/Console/Commands:

namespace App\Console\Commands;
 
use Illuminate\Console\Command;
 
class SendWeeklyReport extends Command
{
    protected $signature = 'reports:send';
 
    protected $description = 'Sends the weekly report to administrators';
 
    public function handle(): int
    {
        $this->info('The report was sent.');
 
        return self::SUCCESS;
    }
}

$signature is the name of the command, handle() is its work. Running it:

php artisan reports:send

Arguments and options

Arguments and options are described right in $signature:

protected $signature = 'users:export {format} {--limit=100} {--active}';
 
public function handle(): int
{
    $format = $this->argument('format');
    $limit = (int) $this->option('limit');
    $onlyActive = $this->option('active');
 
    return self::SUCCESS;
}
php artisan users:export csv --limit=500 --active
FormMeaning
{format}A required argument
{format?}An optional argument
{format=csv}An argument with a default value
{--active}A flag: present or not
{--limit=100}An option with a value

Output

$this->info('Done');        // green text
$this->warn('Careful');     // yellow
$this->error('Error');      // red
$this->line('A plain line');
 
$this->table(['Name', 'Email'], [['Anna', 'anna@example.com']]);

Questions

$name = $this->ask('What should the file be called?');
 
if ($this->confirm('Delete the old records?')) {
    // …
}
 
$format = $this->choice('Format', ['csv', 'json'], 0);

A progress bar

Long operations show a progress bar:

$users = User::all();
 
$this->withProgressBar($users, function (User $user) {
    $user->notify(new WeeklyDigest());
});

Dependencies

The handle() method can ask for any service — the container supplies it:

public function handle(ReportBuilder $builder): int
{
    $builder->build();
 
    return self::SUCCESS;
}

Running on a schedule and from code

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
 
Schedule::command('reports:send')->weeklyOn(1, '9:00');
 
Artisan::call('users:export', ['format' => 'csv', '--limit' => 50]);

Common mistake

A command must return an exit code: self::SUCCESS on success and self::FAILURE on an error. The scheduler and deployment systems use it to tell whether the operation worked. A command that silently returns success on failure hides the problem.

if (!$file) {
    $this->error('File not found.');
 
    return self::FAILURE;
}

Thanks for reading!

Donate to the site — we work hard for you.