foreign_key が <テーブル名>_id
でない場合のリレーション
日本語ドキュメントはこちらです!
https://readouble.com/laravel/6.x/ja/eloquent-relationships.html
やりたいこと
まずは結論
class Status extends Model
{
public function history()
{
return $this->belongsTo(History::class, 'post_number');
}
}
class History extends Model
{
public function status()
{
return $this->hasOne(Status::class, 'post_number');
}
}
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Status;
class StatusController extends Controller
{
public function index()
{
$statuses = Status::orderBy('created_at', 'asc')->paginate(10);
return view('status.index', compact('statuses'));
}
}
@foreach ($statuses as $status)
<tr>
<td>{{ optional($status->history)->post_id }}</td>
</tr>
@endforeach
どっちが belongsTo
? とわかりづらい場合は、
まっぴーさんのツイートを参考に!!!!!!!!!!!!!!!!!!!!!!!
「常に第2引数が Foreign Key で,第3引数が Local Key です。基本的に Local Key はいじらない限りは "id" となるもので,何かしらテーブル名入ってる方は Foreign Key という覚え方でOK」
とのことなので、 第2引数が id
などの Local Key になっていたら belongsTo
と hasOne
が逆 です。
あと公式ドキュメントにも
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
と載ってるのですがここが大事なようです。
わたしはデータをとりにいくテーブル側が hasOne
になる!と思い込んでたので最初は下記のようにしており、実際にデータも取得はできていたのですが、これだと、 Local Key が第2引数になってしまい正しい形ではないと!
class Status extends Model
{
public function history()
{
return $this->hasOne(History::class, 'id', 'post_number');
}
}
ドキュメントに沿うと下記が正解なのではと思ったけど何故かデータ取得できず…。
class Status extends Model
{
public function history()
{
return $this->hasOne(History::class, 'post_number', 'id');
}
}
そこで belongsTo
と hasOne
を反対にするとちゃんとデータも取得でき正しい書き方になったという結論です。(※まっぴーさんに教えてもらった)
ちなみにもし外部キーがデフォルトの、<テーブル名>_id
であれば引き数は必要ないけれど、
( histories
テーブルに status_id
があり、それを外部キーとしてデータを取得したい場合)
今回は違うので引数を割り当てます。
基本的には第3引数が id
の形になると思われますが、
return $this->belongsTo(History::class, 'post_number', 'id');
命名規則にのっていれば第3引数の id
はデフォルトなので省略可能。
return $this->belongsTo(History::class, 'post_number');
無事データが取得できたか確認
\DB::enableQueryLog();
Status::find(1)->history;
dd(\DB::getQueryLog());
取得結果
bindings
の 0 => 1
の意味は、「1つ目の ?
に 1
があてられる」
当てはめると下記になる↓
select * from `statuses` where `statuses`.`id` = 1 limit 1;
select * from `histories` where `histories`.`id` = 18 and `histories`.`deleted_at` is null limit 1;
上記を heidiSQL や A5SQL などにコピペして求めてるレコードが取れているか確認します。