◀ 4.

Laravel Eloquent モデルのデフォルト値設定

この記事の要点
  • Laravel のデフォルト値は「DB のカラム(マイグレーション)」と「Eloquent モデル」の 2 か所で設定できる
  • DB 側: マイグレーションで $table->integer('x')->default(0);
  • 現在時刻は ->useCurrent()、更新時刻の自動更新は ->useCurrentOnUpdate()
  • モデル側: protected $attributes = [...] で new した時点から値が入る
  • DB のデフォルト値は保存直後のモデルには入らない。必要なら refresh() するかモデル側にも書く
  • 既存カラムの変更は ->change()。Laravel 11 以降は残したい修飾子をすべて書き直す必要がある

デフォルト値を設定する 2 つの場所

Laravel で「値を指定しなかったときに入る初期値」を決める方法は 2 つあります。目的に応じて使い分け、必要なら両方に書きます。

方法書く場所効く場面向いている用途
カラムのデフォルト値マイグレーションINSERT 時にそのカラムを省略したとき(SQL を直接実行した場合も含む)データの整合性を DB で保証したい値
モデルの $attributesEloquent モデルnew / create でモデルを作った瞬間保存前の画面表示や処理で初期値を使いたい場合

マイグレーションでカラムにデフォルト値を設定する

カラム定義の後ろに ->default(値) を付けます。以下は既存の test テーブルに colA カラムを追加し、初期値を 0 にする例です。

public function up()
{
    Schema::table('test', function (Blueprint $table) {
        $table->tinyInteger('colA')->default(0);
    });
}

新規テーブルを作る場合も書き方は同じです。型ごとの代表的な書き方をまとめます。

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->string('status', 20)->default('draft');      // 文字列
    $table->unsignedInteger('view_count')->default(0);   // 数値
    $table->boolean('is_published')->default(false);     // 真偽値
    $table->decimal('price', 10, 2)->default(0);         // 小数
    $table->text('memo')->nullable();                    // 初期値 NULL
    $table->timestamp('published_at')->useCurrent();     // 現在時刻
    $table->timestamp('synced_at')->useCurrent()->useCurrentOnUpdate();
    $table->timestamps();
});
  • nullable() は「NULL を許可する」指定で、値を省略すると NULL が入ります。default(null) と書くより意図が明確です
  • useCurrent() は DEFAULT CURRENT_TIMESTAMP を、useCurrentOnUpdate() は MySQL の ON UPDATE CURRENT_TIMESTAMP を付けます
  • 式をデフォルト値にしたい場合は new Expression(...)(Illuminate\Database\Query\Expression)を渡します。MySQL で JSON カラムに式のデフォルトを付けるには 8.0.13 以降が必要です
use Illuminate\Database\Query\Expression;

$table->json('options')->default(new Expression('(JSON_ARRAY())'));

Eloquent モデルでデフォルト値を設定する

モデルに $attributes プロパティを書くと、new Post() や Post::create([...]) でインスタンスを作った時点で、その値が属性に入ります。

class Post extends Model
{
    protected $fillable = ['title', 'status'];

    protected $attributes = [
        'status'     => 'draft',
        'view_count' => 0,
        'options'    => '[]',   // キャストする属性も「保存される形」で書く
    ];

    // Laravel 11 以降の書き方(10 以前は protected $casts プロパティ)
    protected function casts(): array
    {
        return ['options' => 'array'];
    }
}

$post = new Post(['title' => 'Hello']);
echo $post->status;   // draft(まだ保存していなくても入っている)

$attributes の値は DB に保存される生の値として扱われるため、array キャストの属性は配列ではなく JSON 文字列で書きます。現在時刻のように毎回変わる値は $attributes には書けないので、モデルの creating イベント(booted() 内で登録)で設定します。

既存カラムのデフォルト値を変更する

すでにあるカラムのデフォルト値を変えるには、新しいマイグレーションを作り ->change() を使います。

Schema::table('posts', function (Blueprint $table) {
    $table->string('status', 20)->default('published')->change();
});
  • Laravel 10 以前: change() には doctrine/dbal パッケージが必要です(composer require doctrine/dbal)
  • Laravel 11 以降: doctrine/dbal は不要になりました。その代わり、change() では残したい修飾子(nullable、unsigned、comment など)をすべて書き直す必要があり、書かなかった修飾子は外れます

変更後は、意図しない修飾子が外れていないかも含めて必ずテーブル定義を確認しましょう。

落とし穴

  • 保存直後のモデルに DB のデフォルト値が入っていない: $post = Post::create(['title' => 'A']); の直後、DB 側のデフォルト値だけで埋まったカラムは $post->status が null のままです。Eloquent は INSERT した値しか持っていないためです。$post->refresh() で読み直すか、モデルの $attributes にも同じ値を書きます
  • 明示的に null を渡すとデフォルト値は使われない: フォームの空欄がそのまま null で渡ると、NOT NULL カラムではエラーになります。リクエストから値を取り出す段階で空欄を除外するか、既定値を補います
  • TEXT / BLOB 系のデフォルト値: MySQL では TEXT 系のカラムに通常のリテラルのデフォルト値は付けられません(8.0.13 以降は式のデフォルトのみ可)。初期値が必要なら VARCHAR にするか、モデル側で設定します
  • default(false) と boolean: MySQL の boolean は TINYINT(1) なので、DB には 0 が入ります。取り出し時に true / false で扱いたい場合はモデルで boolean キャストを指定します

確認方法

マイグレーション実行後、カラムのデフォルト値が設定されたかは次の方法で確認できます。

# Laravel 9 系の途中以降で使えるコマンド
php artisan db:table posts

# MySQL で直接確認
mysql> SHOW CREATE TABLE posts\G
mysql> SELECT column_name, column_default FROM information_schema.columns
       WHERE table_schema = DATABASE() AND table_name = 'posts';

モデル側の設定は php artisan tinker で (new App\Models\Post)->status を表示すれば確認できます。

関連

Post Share
子ページ

子ページはありません

同階層のページ
  1. テーブルの作成と定義の変更
  2. カラムの追加、変更、削除方法
  3. データ型とカラム修飾子
  4. デフォルト値の設定