Was ist Artisan
Artisan ist die Kommandozeilenschnittstelle (CLI), die Laravel mitbringt.
Sie liegt als Skript artisan im Projekt-Root und stellt zahlreiche Befehle bereit, die Ihre Entwicklung und Ihren Betrieb effizienter machen.
Um die verfügbaren Befehle anzuzeigen, verwenden Sie den Befehl list.
Um sich die Nutzung eines Befehls anzeigen zu lassen, stellen Sie help voran.
Wenn Sie Laravel Sail verwenden, nutzen Sie statt php artisan den Befehl sail artisan.
Der Befehl wird im Docker-Container ausgeführt../vendor/bin/sail artisan list
Tinker
Laravel Tinker ist eine REPL-Umgebung, mit der Sie Eloquent-Modelle, Jobs, Events und die gesamte Anwendung interaktiv auf der Kommandozeile steuern.
Nach dem Start können Sie beliebigen PHP-Code direkt ausführen.
// Benutzer laden und prüfen
>>> App\Models\User::find(1)
// Einen Datensatz per Factory anlegen
>>> App\Models\User::factory()->create()
// Eine Serviceklasse direkt aufrufen
>>> app(App\Services\OrderService::class)->process(1)
Tinker verändert Daten tatsächlich. In der Produktionsumgebung sollten Sie daher besonders vorsichtig sein.
Für lokale oder Staging-Umgebungen ist es ideal, um Verhalten zu prüfen und zu debuggen.
Eigene Befehle erstellen
Befehl erzeugen
Mit make:command erzeugen Sie das Grundgerüst einer Befehlsklasse.
php artisan make:command ImportProducts
Das erzeugt die Datei app/Console/Commands/ImportProducts.php.
Grundaufbau eines Befehls
Die erzeugte Klasse besteht im Wesentlichen aus drei Elementen: $signature, $description und handle().
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
/**
* Definition von Befehlsname, Argumenten und Optionen
*/
protected $signature = 'import:products';
/**
* Beschreibung des Befehls (wird in `php artisan list` angezeigt)
*/
protected $description = 'Produktdaten aus CSV importieren';
/**
* Ausführung des Befehls
*/
public function handle(): void
{
$this->info('Import wird gestartet...');
// Verarbeitung hier
$this->info('Fertig.');
}
}
In Laravel 13 können Sie auch die Schreibweise über PHP-Attribute verwenden.use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
#[Signature('import:products')]
#[Description('Produktdaten aus CSV importieren')]
class ImportProducts extends Command
{
public function handle(): void
{
// ...
}
}
Argumente und Optionen definieren
Über $signature legen Sie Namen, Argumente und Optionen des Befehls gebündelt fest.
protected $signature = 'import:products
{file : Pfad zur zu importierenden CSV-Datei}
{--limit= : Maximale Anzahl zu importierender Einträge}
{--dry-run : Nicht in die DB speichern (nur zur Prüfung)}';
| Notation | Typ | Beschreibung |
|---|
{file} | Pflicht-Argument | Wird bei Auslassung als Fehler behandelt |
{file?} | Optionales Argument | Ohne Angabe null |
{file=products.csv} | Argument mit Default | Ohne Angabe wird der Default verwendet |
{--queue} | Flag-Option | Vorhanden: true, sonst false |
{--limit=} | Option mit Wert | Wert über --limit=100 übergeben |
{--limit=50} | Option mit Default | Ohne Angabe 50 |
{--Q|queue} | Mit Shortcut | Auch über -Q angebbar |
Argumente und Optionen abrufen
In handle() greifen Sie mit argument() und option() auf die Werte zu.
public function handle(): void
{
$file = $this->argument('file'); // Argument abrufen
$limit = $this->option('limit'); // Option abrufen
$dryRun = $this->option('dry-run'); // Flag-Option (bool)
$this->info("Datei: {$file}");
if ($dryRun) {
$this->warn('Dry-Run-Modus: Speicherung in der DB wird übersprungen');
}
}
Mit input() erhalten Sie typisierten Zugriff auf Argumente und Optionen, ähnlich wie bei HTTP-Requests.
use App\Enums\ReportType;
public function handle(): void
{
// Argumente/Optionen als CommandInput-Instanz abrufen
$from = $this->input()->date('from');
$type = $this->input()->enum('type', ReportType::class);
$limit = $this->input()->integer('limit');
}
Wenn Sie nur einen bestimmten Namen abrufen möchten, übergeben Sie diesen direkt (es wird sowohl in Argumenten als auch Optionen gesucht).
$queue = $this->input('queue', 'default');
Während argument() und option() Strings zurückgeben, konvertieren die typisierten Accessoren von input() in den passenden Typ. Praktisch, wenn Sie Datumsangaben, Zahlen oder Enums typsicher verarbeiten möchten.
Interaktion mit dem Benutzer
Ausgabe von Nachrichten
Für farbige Konsolenausgaben stehen fertige Methoden bereit.
$this->info('Verarbeitung erfolgreich abgeschlossen'); // grün
$this->warn('Diese Aktion kann nicht rückgängig gemacht werden'); // gelb
$this->error('Ein Fehler ist aufgetreten'); // rot
$this->line('Normaler Text'); // ohne Farbe
$this->comment('Zusatzinfo'); // hellgrau
Benutzer befragen
Sie können interaktiv Eingaben vom Benutzer einholen.
// Texteingabe
$name = $this->ask('Bitte den Namen des Verantwortlichen eingeben');
// Mit Default
$env = $this->ask('Ausführungsumgebung wählen', 'production');
// Verdeckte Eingabe (z. B. Passwörter, Eingabe nicht sichtbar)
$password = $this->secret('Bitte API-Schlüssel eingeben');
// Ja/Nein-Bestätigung
if (! $this->confirm('In die produktive DB importieren?')) {
$this->info('Abgebrochen.');
return;
}
// Auswahl aus Optionen
$format = $this->choice('Ausgabeformat wählen', ['csv', 'json', 'xml'], 0);
Fortschrittsanzeige
Bei der Verarbeitung großer Datenmengen können Sie den Fortschritt übersichtlich anzeigen.
use App\Models\Product;
// Übergeben Sie eine Collection – der Fortschrittsbalken erscheint automatisch
$this->withProgressBar(Product::cursor(), function (Product $product) {
$this->processProduct($product);
});
Für feinere manuelle Steuerung nutzen Sie folgendes Muster.
$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();
Praxisnahe Anwendungsfälle
Datenimport-Befehl
Ein praktisches Beispiel eines Befehls, der Produktdaten aus einer CSV-Datei importiert.
Befehl erzeugen
php artisan make:command ImportProducts
Befehl implementieren
<?php
namespace App\Console\Commands;
use App\Models\Product;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
protected $signature = 'import:products
{file : Pfad zur CSV-Datei}
{--limit= : Maximale Anzahl zu importierender Einträge}
{--dry-run : Nur zur Prüfung (nicht in die DB speichern)}';
protected $description = 'Produktdaten aus einer CSV-Datei importieren';
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("Datei nicht gefunden: {$filePath}");
return;
}
// CSV mit den eingebauten PHP-Funktionen einlesen
$handle = fopen($filePath, 'r');
$headers = fgetcsv($handle); // Erste Zeile als Header verwenden
$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} Einträge betroffen (Dry-Run: Speicherung übersprungen)");
} else {
$this->info("{$count} Einträge erfolgreich importiert.");
}
}
}
Befehl ausführen
# Normaler Import
php artisan import:products storage/products.csv
# Anzahl begrenzen
php artisan import:products storage/products.csv --limit=100
# Als Dry-Run prüfen
php artisan import:products storage/products.csv --dry-run
Regelmäßiger Wartungsbefehl
Ein Beispiel für einen regelmäßig ausgeführten Wartungsbefehl, etwa zum Entfernen alter Daten.
<?php
namespace App\Console\Commands;
use App\Models\Order;
use Illuminate\Console\Command;
class PruneOldOrders extends Command
{
protected $signature = 'orders:prune {--days=90 : Alter (in Tagen), ab dem gelöscht wird}';
protected $description = 'Abgeschlossene Bestellungen löschen, die älter als die angegebene Anzahl an Tagen sind';
public function handle(): void
{
$days = (int) $this->option('days');
if (! $this->confirm("Abgeschlossene Bestellungen älter als {$days} Tage löschen?")) {
$this->info('Abgebrochen.');
return;
}
$deleted = Order::where('status', 'completed')
->where('created_at', '<', now()->subDays($days))
->delete();
$this->info("{$deleted} Bestellungen gelöscht.");
}
}
Kombination mit dem Scheduler
Ihre Befehle können in routes/console.php geplant ausgeführt werden.
Details finden Sie unter Task-Scheduling.
use Illuminate\Support\Facades\Schedule;
// Täglich um 2 Uhr nachts
Schedule::command('orders:prune --days=90')->dailyAt('2:00');
// Jeden Montag um 9 Uhr
Schedule::command('import:products storage/weekly.csv')->weeklyOn(1, '9:00');
Befehle testen
Mit den Testfunktionen von Laravel können Sie das Verhalten Ihrer Artisan-Befehle überprüfen.
<?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
{
// Abgeschlossene Bestellung erzeugen, die älter als 90 Tage ist
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(100),
]);
// Kürzlich abgeschlossene Bestellung (sollte erhalten bleiben)
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(10),
]);
$this->artisan('orders:prune', ['--days' => 90])
->expectsConfirmation('Abgeschlossene Bestellungen älter als 90 Tage löschen?', 'yes')
->expectsOutput('1 Bestellungen gelöscht.')
->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('Abgeschlossene Bestellungen älter als 90 Tage löschen?', 'no')
->expectsOutput('Abgebrochen.')
->assertExitCode(0);
$this->assertDatabaseCount('orders', 1);
}
}
Beispiele für Assertion-Methoden, die mit artisan() genutzt werden können:| Methode | Beschreibung |
|---|
expectsOutput('...') | Prüft, dass der angegebene Text ausgegeben wird |
expectsQuestion('?', 'Antwort') | Simuliert die Eingabe von ask() |
expectsConfirmation('?', 'yes') | Simuliert die Antwort auf confirm() |
expectsChoice('?', 'Auswahl') | Simuliert die Auswahl von choice() |
assertExitCode(0) | Prüft den Exit-Code (0 = Erfolg) |
assertFailed() | Prüft, dass der Exit-Code nicht 0 ist |
Häufig verwendete Befehle im Überblick
# Neuen Befehl erzeugen
php artisan make:command CommandName
# Verfügbare Befehle auflisten
php artisan list
# Nutzung eines Befehls anzeigen
php artisan help command:name
# Tinker starten
php artisan tinker
Zuletzt geändert am 13. Juli 2026