ポリモーフィック関連とは
あるエンティティが複数のテーブルを参照しているような状態のこと。
アンチパターンにもあるとおり基本的に使用しない最後の手段的なイメージだが使った方が便利なケースもある。今回は使っても良さそうなケースに当てはまって触ってみたのでその備忘録。
要件
コンテンツ→設定一覧→記録一覧(ポリモーフィック )→記録詳細のよう繋げ方をしたい。
ポリモーフィック関連にしない場合には例えばあんまり好ましくないけれど絶対に上限が決まっている場合には、それぞれのテーブルの外部キー用のカラムを作成してsettingテーブルに持たせるとか、テーブルを増やして対応するとかになると思う。
登場テーブル一覧
- contents
- settings
- setting_measurables
- measure_a_recordings
- measure_a_records
- measure_b_recordings
- measure_b_records
- measure_c_recordings
- measure_c_records
#マイグレーション
ポリモーフィック関連に使用するテーブル(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で無い場合にも避けるべきだとは思った。