◀ 10.

【Laravel】モデルのcreated_at/updated_atの別名指定

この記事の要点
  • Eloquent が自動で埋める created_at / updated_at の列名は、モデルの定数 CREATED_AT / UPDATED_AT で変更できる
  • 例: const CREATED_AT = 'creation_date'; const UPDATED_AT = 'last_update';
  • 片方だけ使わないなら、その定数に null を入れる(例: 更新日時の列がないテーブル)
  • 自動更新を完全に止めたいなら public $timestamps = false;
  • latest() や日付キャストも新しい列名に追従する。ただし DB::table() のクエリビルダは自動設定しない

結論: モデルに定数を書く

次のように、モデル内の CREATED_AT / UPDATED_AT 定数に、created_at / updated_at に相当するカラム名を指定することで、Laravel 側は指定したカラムを作成日時・更新日時として認識するようになります。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    const CREATED_AT = 'creation_date';
    const UPDATED_AT = 'last_update';
}

これだけで、Flight::create() や $flight->save() のときに、creation_date と last_update に現在日時が自動で入るようになります。

なぜ別名指定が必要になるのか

Eloquent モデルは、既定でテーブルに created_at と updated_at という列があることを前提にしています。新規作成時には両方に、更新時には updated_at に、現在日時を自動で設定します。

しかし、既存のシステムのテーブルを Laravel から使う場合などは、列名が created_date や insert_datetime のように違うことがよくあります。この状態で何も設定しないと、Laravel は存在しない created_at 列に書き込もうとして、次のようなエラーになります。

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list'

テーブル定義を変えずに Laravel 側を既存の列名に合わせるのが、CREATED_AT / UPDATED_AT 定数の役割です。

パターン別の書き方

テーブルの状態モデルの設定
列名が違うconst CREATED_AT = '列名'; const UPDATED_AT = '列名';
作成日時の列だけあるconst UPDATED_AT = null;
更新日時の列だけあるconst CREATED_AT = null;
日時の列がない・自動設定したくないpublic $timestamps = false;
日時を UNIX 時刻などで保存しているprotected $dateFormat = 'U'; を併用
// 作成日時だけを持つログテーブルの例
class AccessLog extends Model
{
    const CREATED_AT = 'logged_at';
    const UPDATED_AT = null;
}

// タイムスタンプを一切使わないテーブル
class Prefecture extends Model
{
    public $timestamps = false;
}

ソフトデリート(SoftDeletes トレイト)の削除日時列も、同じように const DELETED_AT = 'removed_at'; で変更できます。

マイグレーションで列を作る場合

マイグレーションの $table->timestamps() は、常に created_at と updated_at という名前で列を作ります。別名にしたい場合は、列を個別に定義します。

Schema::create('flights', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamp('creation_date')->nullable();
    $table->timestamp('last_update')->nullable();
});

特別な理由がない新規テーブルなら、Laravel の規約どおり created_at / updated_at にしておく方が、パッケージやチームの慣習と合わせやすくおすすめです。

別名にしても自動で追従するもの

  • 日付キャスト: 指定した列は Carbon(日時オブジェクト)として取得され、$flight->creation_date->format('Y-m-d') のように扱える
  • latest() / oldest(): 列名を省略すると、モデルの CREATED_AT で指定した列で並べ替える
  • touch(): UPDATED_AT で指定した列を現在日時に更新する
  • リレーションの $touches: 親モデルの更新日時列にも、親側の定義に従って書き込まれる

コードの中で列名が必要なときは、文字列を直書きせず $model->getCreatedAtColumn() / $model->getUpdatedAtColumn() で取得すると、定数の変更に強くなります。

よくある落とし穴

  • DB ファサードでは自動設定されない: DB::table('flights')->insert([...]) や Flight::insert([...])(複数行の一括 insert)はクエリビルダの機能なので、日時は自分で指定する必要がある
  • 中間テーブル(pivot): belongsToMany の withTimestamps() は、既定で created_at / updated_at を使う。別名の場合は withTimestamps('creation_date', 'last_update') のように列名を渡す
  • 定数のスペルミス: CREATE_AT のように綴りを間違えるとエラーにならず無視され、既定の created_at が使われる
  • 一時的に更新日時を変えたくない: そのときだけ $model->timestamps = false; を設定してから save() する

確認方法

  1. php artisan tinker で (new App\Models\Flight)->getCreatedAtColumn() を実行し、指定した列名が返るか確認する
  2. Flight::create(['name' => 'test']) でレコードを作り、指定した列に日時が入っているか確認する
  3. 発行された SQL を確認したい場合は、DB::enableQueryLog() でクエリログを取り、insert 文の列名を見る

関連

Post Share
子ページ

子ページはありません

同階層のページ
  1. モデルの作成
  2. $fillable $guarded $hiddenの説明
  3. テーブルの紐づけ
  4. 主キーの指定とインクリメント
  5. タイムスタンプ
  6. モデルでselect
  7. モデルでinsert
  8. モデルでupdate
  9. 現在値に加算する方法
  10. created_at/updated_atの別名指定