LoginSignup
62
32

More than 1 year has passed since last update.

Laravelリレーション初心者向け!外部キーがデフォルトでないパターン!!!

Last updated at Posted at 2019-12-20

foreign_key が <テーブル名>_id でない場合のリレーション

日本語ドキュメントはこちらです!
https://readouble.com/laravel/6.x/ja/eloquent-relationships.html

やりたいこと

image.png

まずは結論

Status.php
class Status extends Model
{
    public function history()
    {
        return $this->belongsTo(History::class, 'post_number');
    }
}
History.php
class History extends Model
{
    public function status()
    {
        return $this->hasOne(Status::class, 'post_number');
    }
}
StatusController.php
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'));
    }
}
index.blade.php
@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」
image.png

とのことなので、 第2引数が id などの Local Key になっていたら belongsTohasOne が逆 です。
あと公式ドキュメントにも

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

と載ってるのですがここが大事なようです。
わたしはデータをとりにいくテーブル側が hasOne になる!と思い込んでたので最初は下記のようにしており、実際にデータも取得はできていたのですが、これだと、 Local Key が第2引数になってしまい正しい形ではないと!

Status.php ❌
class Status extends Model
{
    public function history()
    {
        return $this->hasOne(History::class, 'id', 'post_number');
    }
}

ドキュメントに沿うと下記が正解なのではと思ったけど何故かデータ取得できず…。

Status.php ❓
class Status extends Model
{
    public function history()
    {
        return $this->hasOne(History::class, 'post_number', 'id');
    }
}

そこで belongsTohasOne を反対にするとちゃんとデータも取得でき正しい書き方になったという結論です。(※まっぴーさんに教えてもらった)
ちなみにもし外部キーがデフォルトの、<テーブル名>_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());

取得結果
image.png
bindings0 => 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 などにコピペして求めてるレコードが取れているか確認します。

62
32
1

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
62
32