3.

Laravel Eloquent モデルとテーブルの紐づけ|$table / 命名規則 / Primary Key

編集
この記事の要点
  • Laravel Eloquent モデルにテーブル名を明示的に紐付ける方法
  • Model 内で protected $table = "テーブル名"; を宣言
  • デフォルトはクラス名の複数形 snake_case(例: Userusers, OrderItemorder_items
  • カスタムテーブル名や、複数形でないテーブル (master_data 等) で必須
  • 主キーカラム名 / インクリメント / タイムスタンプも個別にオーバーライド可能

基本: $table プロパティ

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model {
    // テーブル名を明示
    protected $table = 'product_master';
}

// SELECT * FROM product_master が実行される
$products = Product::all();

命名規則: なぜ自動で紐づくのか

Laravel は規約優先 (Convention over Configuration)の設計です。$table を指定しない場合、クラス名から自動推測されます:

クラス名自動推測されるテーブル名
Userusers
Productproducts
OrderItemorder_items
Categorycategories (es 複数形)
Personpeople (不規則複数形)
Datumdata (ラテン語複数)

複数形変換は内部で Str::plural() を使い、英語の不規則変化にも対応しています。日本語ローマ字テーブル名や略語の場合は $table 明示が必要です。

$table が必要なケース

  • テーブル名がクラス名と異なる(既存 DB の命名規約に合わせる場合)
  • 単数形のテーブル名product / category 等)
  • スキーマ付き(schema.table_name
  • プレフィックス付き(cms_users 等)
  • テーブル名が動詞や略語(tx_log / m_user

主キーのカスタマイズ

主キー名が id 以外、または auto-increment でない場合:

class Product extends Model {
    protected $table = 'product_master';

    // 主キーカラム名(デフォルト: 'id')
    protected $primaryKey = 'product_id';

    // 自動インクリメントか(デフォルト: true)
    public $incrementing = false;  // UUID や手動 ID の場合

    // 主キーの型(デフォルト: 'int')
    protected $keyType = 'string';  // UUID なら string
}

タイムスタンプ / 接続のカスタマイズ

class LegacyProduct extends Model {
    protected $table = 'tbl_product';

    // created_at / updated_at カラムが無いテーブル
    public $timestamps = false;

    // カラム名が違う場合
    const CREATED_AT = 'create_datetime';
    const UPDATED_AT = 'update_datetime';

    // 別の DB 接続を使う場合(config/database.php で定義)
    protected $connection = 'legacy_mysql';
}

fillable / guarded

テーブル紐づけと一緒に、create() / update() で受け付けるカラムを定義:

class Product extends Model {
    protected $table = 'products';

    // ホワイトリスト方式(推奨)
    protected $fillable = ['name', 'price', 'description'];

    // ブラックリスト方式(fillable と排他)
    // protected $guarded = ['id', 'created_at'];

    // JSON にしない / させたいカラム
    protected $hidden = ['secret_token'];  // toArray 時に除外
    protected $visible = ['id', 'name'];   // 表示するカラムを限定

    // 型変換
    protected $casts = [
        'price' => 'decimal:2',
        'options' => 'array',  // JSON 列を配列に
        'published_at' => 'datetime',
    ];
}

スキーマ付きテーブル (PostgreSQL 等)

class Product extends Model {
    // schema.table 形式
    protected $table = 'inventory.products';
}

// または接続ごとに schema を指定
// config/database.php
// 'pgsql' => [
//     'driver' => 'pgsql',
//     'schema' => 'inventory',
//     ...
// ]

複数テーブル ⇄ 1 モデル(テーブル動的切替)

シャーディングや月別テーブル分割でテーブル名を動的に変えたい場合:

class Log extends Model {
    public $timestamps = false;

    public static function forMonth($yearMonth) {
        $instance = new static();
        $instance->setTable("logs_{$yearMonth}");  // 動的に変更
        return $instance;
    }
}

// 使い方
$logs = Log::forMonth('202401')->where('user_id', 1)->get();
// SELECT * FROM logs_202401 WHERE user_id = 1

動作確認

php artisan tinker

>>> \App\Models\Product::query()->toSql()
=> "select * from \"product_master\""

>>> $p = new \App\Models\Product();
>>> $p->getTable()
=> "product_master"

>>> $p->getKeyName()
=> "product_id"

関連

  • マイグレーション: Schema::create('product_master', ...) でテーブル作成時の名前を合わせる
  • Factory / Seeder: モデル経由なので $table の指定が自動的に効く
  • リレーション: hasMany('App\Models\Order', 'product_id') のように外部キー指定も忘れず
  • $with でリレーション eager load: protected $with = ['category'];
編集
Post Share
子ページ

子ページはありません

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