Artisan Commands

Writing Custom Artisan Commands

make:command RestockProducts writes an auto-registered class in app/Console/Commands; Laravel 13 2,157 's stub uses #[Signature] and #[Description] attributes instead of $signature:

app/Console/Commands/RestockProducts.php (imports and chooseTitles() omitted)PHP
#[Signature('shop:restock {sku?* : Only these SKUs} {--t|threshold=5 : Restock below this}
    {--amount=20 : Copies to add to each title} {--dry-run : List the titles only}')]
#[Description('Top up stock for titles that are running low')]
class RestockProducts extends Command
{
    public function handle(): int
    {
        $low = Product::where('stock', '<', (int) $this->option('threshold'))
            ->when($this->argument('sku'), fn ($q, $skus) => $q->whereIn('sku', $skus))
            ->orderBy('sku')->get();
        $this->table(['SKU', 'Title', 'Stock'], $low->map->only('sku', 'title', 'stock'));
        if ($low->isEmpty() || $this->option('dry-run')) {
            return self::SUCCESS;
        }
        $amount = (int) $this->option('amount');
        $chosen = $this->chooseTitles($low, $amount);
        $this->withProgressBar($chosen, function (Product $p) use ($amount) {
            $p->increment('stock', $amount);
            ProductRestocked::dispatch($p, $amount);
        });
        $this->newLine();
        $this->info("Added {$amount} copies to each title.");
        return self::SUCCESS;
    }
Output
$ php artisan shop:restock BK-103 --no-interaction
+--------+--------------------+-------+
| SKU    | Title              | Stock |
+--------+--------------------+-------+
| BK-103 | Apache in Practice | 0     |
+--------+--------------------+-------+
 0/1 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░]   0%
 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
Added 20 copies to each title.

{sku?*} is an optional array argument, {--t|threshold=5} an option with shortcut and default, {--dry-run} a switch; text after a colon feeds help shop:restock. handle() may type-hint services, and returns the exit code. Of the 127 commands here, 37 are make:*; the daily ones are about, route:list, migrate:status, db:show, tinker, queue:work, schedule:list, optimize:clear, down and up.