Cos’è Artisan
Artisan è lo strumento a riga di comando (CLI) incluso in Laravel.
Esiste come script artisan nella root del progetto e offre molti comandi che rendono efficienti sviluppo e gestione operativa.
Per vedere l’elenco dei comandi disponibili usa list.
Per vedere come si usa un comando anteponi help.
Se usi Laravel Sail, sostituisci php artisan con sail artisan.
I comandi verranno eseguiti nel container Docker../vendor/bin/sail artisan list
Tinker
Laravel Tinker è un ambiente REPL che permette di interagire in modo interattivo con l’intera applicazione — modelli Eloquent, job, eventi — da riga di comando.
Dopo l’avvio puoi eseguire direttamente codice PHP.
// Recupera un utente e verifica
>>> App\Models\User::find(1)
// Crea un record con una factory
>>> App\Models\User::factory()->create()
// Chiama direttamente una classe di servizio
>>> app(App\Services\OrderService::class)->process(1)
Tinker modifica realmente i dati. Fai molta attenzione a eseguirlo in produzione.
È adatto a verifica e debug in ambiente locale o di staging.
Creazione di comandi personalizzati
Generare un comando
Con make:command generi lo scheletro di una classe comando.
php artisan make:command ImportProducts
Viene generato app/Console/Commands/ImportProducts.php.
Struttura base del comando
La classe comando generata ha tre elementi principali: $signature, $description e handle().
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
/**
* Definizione del nome del comando, argomenti e opzioni
*/
protected $signature = 'import:products';
/**
* Descrizione del comando (mostrata in php artisan list)
*/
protected $description = 'Importa i dati dei prodotti da CSV';
/**
* Esecuzione del comando
*/
public function handle(): void
{
$this->info('Avvio dell\'importazione...');
// Scrivi qui la logica
$this->info('Completato.');
}
}
In Laravel 13 puoi usare anche la sintassi con gli attribute PHP.use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
#[Signature('import:products')]
#[Description('Importa i dati dei prodotti da CSV')]
class ImportProducts extends Command
{
public function handle(): void
{
// ...
}
}
Definizione di argomenti e opzioni
In $signature definisci in un’unica stringa nome, argomenti e opzioni del comando.
protected $signature = 'import:products
{file : Path del file CSV da importare}
{--limit= : Numero massimo di elementi da importare}
{--dry-run : Non salva realmente sul DB (solo verifica)}';
| Sintassi | Tipo | Descrizione |
|---|
{file} | Argomento obbligatorio | Omesso genera errore |
{file?} | Argomento opzionale | Se omesso vale null |
{file=products.csv} | Argomento con default | Se omesso usa il valore predefinito |
{--queue} | Opzione flag | true se indicata, false se omessa |
{--limit=} | Opzione con valore | Si passa come --limit=100 |
{--limit=50} | Opzione con default | Se omessa vale 50 |
{--Q|queue} | Con abbreviazione | Puoi indicarla anche come -Q |
Lettura di argomenti e opzioni
All’interno di handle() usa argument() e option() per leggere i valori.
public function handle(): void
{
$file = $this->argument('file'); // Lettura di un argomento
$limit = $this->option('limit'); // Lettura di un'opzione
$dryRun = $this->option('dry-run'); // Opzione flag (bool)
$this->info("File: {$file}");
if ($dryRun) {
$this->warn('Modalità dry-run: il salvataggio sul DB verrà saltato');
}
}
Con il metodo input() puoi leggere argomenti e opzioni con gli stessi accessor tipizzati delle richieste HTTP.
use App\Enums\ReportType;
public function handle(): void
{
// Ottieni argomenti e opzioni come istanza CommandInput
$from = $this->input()->date('from');
$type = $this->input()->enum('type', ReportType::class);
$limit = $this->input()->integer('limit');
}
Se vuoi leggere per nome, passalo direttamente (viene cercato sia negli argomenti sia nelle opzioni).
$queue = $this->input('queue', 'default');
Mentre argument() e option() restituiscono stringhe, gli accessor tipizzati di input() convertono nel tipo appropriato. Comodi per gestire in modo type-safe date, numeri ed enum.
Interazione con l’utente
Emissione di messaggi
Sono disponibili metodi per emettere messaggi colorati in console.
$this->info('Elaborazione completata con successo'); // Verde
$this->warn('Questa operazione non è reversibile'); // Giallo
$this->error('Si è verificato un errore'); // Rosso
$this->line('Testo normale'); // Senza colore
$this->comment('Informazione aggiuntiva'); // Grigio chiaro
Richiesta all’utente
Puoi accettare input interattivamente dall’utente.
// Input testuale
$name = $this->ask('Inserisci il nome del responsabile');
// Con valore predefinito
$env = $this->ask('Seleziona l\'ambiente di esecuzione', 'production');
// Informazioni sensibili come password (input non visibile a schermo)
$password = $this->secret('Inserisci la chiave API');
// Conferma Yes/No
if (! $this->confirm('Importare nel DB di produzione?')) {
$this->info('Operazione annullata.');
return;
}
// Scelta tra opzioni
$format = $this->choice('Seleziona il formato di output', ['csv', 'json', 'xml'], 0);
Barra di avanzamento
Mostra chiaramente il progresso durante l’elaborazione di grandi volumi di dati.
use App\Models\Product;
// Passando una collection, la progress bar viene mostrata automaticamente
$this->withProgressBar(Product::cursor(), function (Product $product) {
$this->processProduct($product);
});
Per un controllo più granulare usa il seguente pattern.
$total = Product::count();
$bar = $this->output->createProgressBar($total);
$bar->start();
Product::cursor()->each(function (Product $product) use ($bar) {
$this->processProduct($product);
$bar->advance();
});
$bar->finish();
$this->newLine();
Casi d’uso pratici
Comando di importazione dati
Esempio pratico di comando che importa i dati dei prodotti da un CSV.
Genera il comando
php artisan make:command ImportProducts
Implementa il comando
<?php
namespace App\Console\Commands;
use App\Models\Product;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
protected $signature = 'import:products
{file : Path del file CSV}
{--limit= : Numero massimo di elementi da importare}
{--dry-run : Solo verifica (non salva sul DB)}';
protected $description = 'Importa i dati dei prodotti da un file CSV';
public function handle(): void
{
$filePath = $this->argument('file');
$limit = $this->option('limit') ? (int) $this->option('limit') : null;
$dryRun = $this->option('dry-run');
if (! file_exists($filePath)) {
$this->error("File non trovato: {$filePath}");
return;
}
// Leggi il CSV con le funzioni built-in di PHP
$handle = fopen($filePath, 'r');
$headers = fgetcsv($handle); // Prima riga come header
$rows = [];
while (($row = fgetcsv($handle)) !== false) {
$rows[] = array_combine($headers, $row);
if ($limit !== null && count($rows) >= $limit) {
break;
}
}
fclose($handle);
$count = 0;
$this->withProgressBar($rows, function (array $row) use ($dryRun, &$count) {
if (! $dryRun) {
Product::updateOrCreate(
['sku' => $row['sku']],
[
'name' => $row['name'],
'price' => $row['price'],
]
);
}
$count++;
});
$this->newLine();
if ($dryRun) {
$this->warn("{$count} elementi identificati (dry-run: salvataggio saltato)");
} else {
$this->info("Importazione completata: {$count} elementi.");
}
}
}
Esegui il comando
# Importazione normale
php artisan import:products storage/products.csv
# Limita il numero di elementi
php artisan import:products storage/products.csv --limit=100
# Verifica in dry-run
php artisan import:products storage/products.csv --dry-run
Comando di manutenzione periodica
Esempio di comando di manutenzione periodica che elimina i dati vecchi.
<?php
namespace App\Console\Commands;
use App\Models\Order;
use Illuminate\Console\Command;
class PruneOldOrders extends Command
{
protected $signature = 'orders:prune {--days=90 : Elimina i dati più vecchi di questi giorni}';
protected $description = 'Elimina gli ordini completati più vecchi del numero di giorni indicato';
public function handle(): void
{
$days = (int) $this->option('days');
if (! $this->confirm("Eliminare gli ordini completati più vecchi di {$days} giorni?")) {
$this->info('Operazione annullata.');
return;
}
$deleted = Order::where('status', 'completed')
->where('created_at', '<', now()->subDays($days))
->delete();
$this->info("Eliminati {$deleted} ordini.");
}
}
Combinazione con l’esecuzione pianificata
Puoi pianificare i comandi creati in routes/console.php.
Per i dettagli consulta Task scheduling.
use Illuminate\Support\Facades\Schedule;
// Esegui ogni giorno alle 2 del mattino
Schedule::command('orders:prune --days=90')->dailyAt('2:00');
// Esegui ogni lunedì alle 9
Schedule::command('import:products storage/weekly.csv')->weeklyOn(1, '9:00');
Test dei comandi
Con le funzionalità di test di Laravel puoi verificare il comportamento dei comandi Artisan.
<?php
namespace Tests\Feature\Commands;
use App\Models\Order;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PruneOldOrdersTest extends TestCase
{
use RefreshDatabase;
public function test_it_deletes_old_completed_orders(): void
{
// Crea un ordine completato più vecchio di 90 giorni
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(100),
]);
// Ordine completato recente (non dovrebbe essere eliminato)
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(10),
]);
$this->artisan('orders:prune', ['--days' => 90])
->expectsConfirmation('Eliminare gli ordini completati più vecchi di 90 giorni?', 'yes')
->expectsOutput('Eliminati 1 ordini.')
->assertExitCode(0);
$this->assertDatabaseCount('orders', 1);
}
public function test_it_cancels_when_user_declines(): void
{
Order::factory()->create(['status' => 'completed', 'created_at' => now()->subDays(100)]);
$this->artisan('orders:prune', ['--days' => 90])
->expectsConfirmation('Eliminare gli ordini completati più vecchi di 90 giorni?', 'no')
->expectsOutput('Operazione annullata.')
->assertExitCode(0);
$this->assertDatabaseCount('orders', 1);
}
}
Esempi di metodi di asserzione utilizzabili con artisan():| Metodo | Descrizione |
|---|
expectsOutput('...') | Verifica che il testo indicato sia emesso |
expectsQuestion('?', 'risposta') | Simula l’input di ask() |
expectsConfirmation('?', 'yes') | Simula la risposta di confirm() |
expectsChoice('?', 'scelta') | Simula la selezione di choice() |
assertExitCode(0) | Verifica il codice di uscita (0 = successo) |
assertFailed() | Verifica che il codice di uscita sia diverso da 0 |
Comandi frequenti
# Crea un nuovo comando
php artisan make:command CommandName
# Elenco dei comandi disponibili
php artisan list
# Verifica come si usa un comando
php artisan help command:name
# Avvia Tinker
php artisan tinker