LoginSignup
3
4

More than 3 years have passed since last update.

LaravelのEloquentでポリモーフィック関連

Posted at

ポリモーフィック関連とは

あるエンティティが複数のテーブルを参照しているような状態のこと。
アンチパターンにもあるとおり基本的に使用しない最後の手段的なイメージだが使った方が便利なケースもある。今回は使っても良さそうなケースに当てはまって触ってみたのでその備忘録。

要件

コンテンツ→設定一覧→記録一覧(ポリモーフィック )→記録詳細のよう繋げ方をしたい。
ポリモーフィック関連にしない場合には例えばあんまり好ましくないけれど絶対に上限が決まっている場合には、それぞれのテーブルの外部キー用のカラムを作成してsettingテーブルに持たせるとか、テーブルを増やして対応するとかになると思う。

登場テーブル一覧

  • contents
  • settings
  • setting_measurables
  • measure_a_recordings
  • measure_a_records
  • measure_b_recordings
  • measure_b_records
  • measure_c_recordings
  • measure_c_records

リレーションのイメージ
ポリモーフィック .png

マイグレーション

ポリモーフィック関連に使用するテーブル(setting_measurables)のマイグレーションに関してだけ書く。ポリモーフィック関連を使用する場合マイグレーションの段階でmorphを使うど便利、リレーションに必要なカラムを指定したキーワードから作成してくれる。マイグレーションファイルを見たときにポリモーフィック関連を使用することが明示的にわかるので便利。

create_setting_measurables_table.php
public function up()
    {
        Schema::create('setting_measurables', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('setting_id');
            $table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
            $table->morphs('measurable'); // measurable_id, measurable_typeを作成
            $table->timestamps();
        });
    }

モデル

class Setting extends Model
{
    protected $fillable = ['content_id'];

    public function measureARecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureARecording',
            'measurable', //morphsに指定したカラム名
            'setting_measurables' //テーブル名
        );
    }

    public function measureBRecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureBRecording',
            'measurable',
            'setting_measurables'
        );
    }

    public function measureCRecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureCRecordings',
            'measurable',
            'setting_measurables'
        );
    }
}

呼び出し

withでEagerLoadingももちろんできる。


public function getMeasureArecording($content_id)
{
    return Content::with([
        'settings',
        'settings.measureARecordings',
        'settings.measureBRecordings',
        'settings.measureCRecordings',
    ])->find($content_id);
}

保存


public function storeSettingMeasurable(Request $request)
{
    SettingMeasurable::create([
        'setting_id' => $request->input('setting_id'),
        'measurable_id' => $request->input('recording_id'), //それぞれのレコーディングテーブルの外部キー
        'measurable_type' => 'App\Models\MeasureARecording' //namespace含む対象モデル名
    ]);
}

# まとめ
ORMだと随所でポリモーフィックであることを明示できるのと呼び出しがより簡潔になるので利用してみたが慎重にCURDしないと不整合が起きるので頻繁には使わない方がいいORMを使用しないならより複雑な処理が必要になるはずなのでORMで無い場合にも避けるべきだとは思った
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4