Artisanとは
ArtisanはLaravelに同梱されているコマンドラインインターフェース(CLI)ツールです。
プロジェクトルートの artisan スクリプトとして存在し、開発・運用を効率化する多数のコマンドを提供しています。
利用可能なコマンド一覧を確認するには list コマンドを使います。
コマンドの使い方を確認するには help を先頭に付けます。
Laravel Sailを使っている場合は、php artisan の代わりに sail artisan を使ってください。
コマンドはDockerコンテナ内で実行されます。./vendor/bin/sail artisan list
Tinker
Laravel Tinker は、EloquentモデルやJob、イベントなど、アプリケーション全体をコマンドライン上でインタラクティブに操作できるREPL環境です。
起動後はPHPコードをそのまま実行できます。
// ユーザーを取得して確認
>>> App\Models\User::find(1)
// ファクトリでレコードを作成
>>> App\Models\User::factory()->create()
// サービスクラスを直接呼び出す
>>> app(App\Services\OrderService::class)->process(1)
Tinkerはデータを実際に変更します。本番環境での実行は十分注意してください。
ローカルやステージング環境での動作確認・デバッグ用途に適しています。
カスタムコマンドの作成
コマンドを生成する
make:command でコマンドクラスのひな型を生成します。
php artisan make:command ImportProducts
app/Console/Commands/ImportProducts.php が生成されます。
コマンドの基本構造
生成されたコマンドクラスには、$signature、$description、handle() という3つの主要要素があります。
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
/**
* コマンド名と引数・オプションの定義
*/
protected $signature = 'import:products';
/**
* コマンドの説明(php artisan list に表示される)
*/
protected $description = '商品データをCSVからインポートする';
/**
* コマンドの実行処理
*/
public function handle(): void
{
$this->info('インポートを開始します...');
// 処理を記述する
$this->info('完了しました。');
}
}
Laravel 13ではPHPアトリビュートを使った書き方も利用できます。use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
#[Signature('import:products')]
#[Description('商品データをCSVからインポートする')]
class ImportProducts extends Command
{
public function handle(): void
{
// ...
}
}
引数とオプションの定義
$signature にコマンド名・引数・オプションをまとめて定義します。
protected $signature = 'import:products
{file : インポートするCSVファイルのパス}
{--limit= : インポートする最大件数}
{--dry-run : 実際にはDBに保存しない(確認用)}';
| 記法 | 種別 | 説明 |
|---|
{file} | 必須引数 | 省略するとエラーになる |
{file?} | 省略可能な引数 | 省略した場合は null |
{file=products.csv} | デフォルト付き引数 | 省略した場合はデフォルト値を使う |
{--queue} | フラグオプション | 指定で true、省略で false |
{--limit=} | 値付きオプション | --limit=100 のように値を渡す |
{--limit=50} | デフォルト付きオプション | 省略時は 50 |
{--Q|queue} | ショートカット付き | -Q でも指定可能 |
引数とオプションの取得
handle() メソッド内で argument() と option() を使って値を取得します。
public function handle(): void
{
$file = $this->argument('file'); // 引数の取得
$limit = $this->option('limit'); // オプションの取得
$dryRun = $this->option('dry-run'); // フラグオプション(bool)
$this->info("ファイル: {$file}");
if ($dryRun) {
$this->warn('ドライランモード: DBへの保存はスキップします');
}
}
ユーザーとのインタラクション
メッセージの出力
コンソールに色付きのメッセージを出力するメソッドが用意されています。
$this->info('処理が正常に完了しました'); // 緑
$this->warn('この操作は元に戻せません'); // 黄
$this->error('エラーが発生しました'); // 赤
$this->line('通常のテキスト'); // 色なし
$this->comment('補足情報'); // 薄いグレー
ユーザーへの問い合わせ
対話的にユーザーから入力を受け付けることができます。
// テキスト入力
$name = $this->ask('担当者名を入力してください');
// デフォルト値付き
$env = $this->ask('実行環境を選択', 'production');
// パスワードなど秘匿情報(入力が画面に表示されない)
$password = $this->secret('APIキーを入力してください');
// Yes/No確認
if (! $this->confirm('本番DBにインポートしますか?')) {
$this->info('キャンセルしました。');
return;
}
// 選択肢から選ぶ
$format = $this->choice('出力形式を選んでください', ['csv', 'json', 'xml'], 0);
プログレスバー
大量データの処理中に進捗をわかりやすく表示できます。
use App\Models\Product;
// コレクションを渡すだけで自動的にプログレスバーを表示する
$this->withProgressBar(Product::cursor(), function (Product $product) {
$this->processProduct($product);
});
手動で細かく制御したい場合は次の方法を使います。
$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();
実用的なユースケース
データインポートコマンド
CSVファイルから商品データをインポートする実践的なコマンドの例です。
コマンドを生成する
php artisan make:command ImportProducts
コマンドを実装する
<?php
namespace App\Console\Commands;
use App\Models\Product;
use Illuminate\Console\Command;
class ImportProducts extends Command
{
protected $signature = 'import:products
{file : CSVファイルのパス}
{--limit= : インポートする最大件数}
{--dry-run : 確認のみ(DBに保存しない)}';
protected $description = '商品データを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("ファイルが見つかりません: {$filePath}");
return;
}
// PHPの組み込み関数でCSVを読み込む
$handle = fopen($filePath, 'r');
$headers = fgetcsv($handle); // 1行目をヘッダーとして取得
$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} 件が対象です(ドライラン: 保存はスキップしました)");
} else {
$this->info("{$count} 件のインポートが完了しました。");
}
}
}
コマンドを実行する
# 通常のインポート
php artisan import:products storage/products.csv
# 件数を制限する
php artisan import:products storage/products.csv --limit=100
# ドライランで確認
php artisan import:products storage/products.csv --dry-run
定期メンテナンスコマンド
古いデータの削除など、定期的に実行するメンテナンスコマンドの例です。
<?php
namespace App\Console\Commands;
use App\Models\Order;
use Illuminate\Console\Command;
class PruneOldOrders extends Command
{
protected $signature = 'orders:prune {--days=90 : 何日前より古いデータを削除するか}';
protected $description = '指定日数より古い完了済み注文を削除する';
public function handle(): void
{
$days = (int) $this->option('days');
if (! $this->confirm("{$days}日以上前の完了済み注文を削除しますか?")) {
$this->info('キャンセルしました。');
return;
}
$deleted = Order::where('status', 'completed')
->where('created_at', '<', now()->subDays($days))
->delete();
$this->info("{$deleted} 件の注文データを削除しました。");
}
}
スケジュール実行との組み合わせ
作成したコマンドは routes/console.php でスケジュール実行できます。
詳細はタスクスケジューリングを参照してください。
use Illuminate\Support\Facades\Schedule;
// 毎日深夜2時に実行
Schedule::command('orders:prune --days=90')->dailyAt('2:00');
// 毎週月曜9時に実行
Schedule::command('import:products storage/weekly.csv')->weeklyOn(1, '9:00');
コマンドのテスト
Laravelのテスト機能を使って、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
{
// 90日以上前の完了済み注文を作成
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(100),
]);
// 直近の完了済み注文(削除されないはず)
Order::factory()->create([
'status' => 'completed',
'created_at' => now()->subDays(10),
]);
$this->artisan('orders:prune', ['--days' => 90])
->expectsConfirmation('90日以上前の完了済み注文を削除しますか?', 'yes')
->expectsOutput('1 件の注文データを削除しました。')
->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('90日以上前の完了済み注文を削除しますか?', 'no')
->expectsOutput('キャンセルしました。')
->assertExitCode(0);
$this->assertDatabaseCount('orders', 1);
}
}
artisan() メソッドで使えるアサーションメソッドの例:| メソッド | 説明 |
|---|
expectsOutput('...') | 指定したテキストが出力されることを検証 |
expectsQuestion('?', '回答') | ask() の入力をシミュレート |
expectsConfirmation('?', 'yes') | confirm() の応答をシミュレート |
expectsChoice('?', '選択肢') | choice() の選択をシミュレート |
assertExitCode(0) | 終了コードを検証(0 = 成功) |
assertFailed() | 終了コードが 0 以外であることを検証 |
よく使うコマンドまとめ
# コマンドを新規作成
php artisan make:command CommandName
# 利用可能なコマンド一覧
php artisan list
# コマンドの使い方を確認
php artisan help command:name
# Tinkerを起動
php artisan tinker