Laravel

Laravelで1対多のリレーションをして保存、表示する方法【hasMany】

いつもご利用ありがとうございます。このブログは、広告費によって運営されています。

オススメ本
Web技術を勉強するなら、かなりオススメの雑誌です。毎月新しい発見があります。ついに最終号・・・、みなさん買いましょう!!
読んで損することはない名著。命名で悩むことが多い人はこの本がオススメです。

⇨ Laravel 記事の目次はこちら

Laravel で1対多のリレーションをして保存、表示する方法について書いていきます。

リレーションとは?

データベースのテーブル間で関係性のあるデータのことを指します。

今回の例で言えば、user_id を保存しておけば、users テーブルから user データを参照することができるということです。

Laravel では、少しの定義でこれを簡単に実装することができます。

この記事の内容は公式ドキュメントの要約となります

検証環境

Laravel 6

テーブル設計

リレーション設計

users テーブル側が 1

posts テーブルが多

という関係の時、多の方に user_id を保存します。

この時注意しなければならないのが、

単数系_id で保存する」

ということです。

users テーブルの id でリレーションするのであれば、user_id で保存するのが命名規則になっています。

(命名規則になっているだけで、これ以外でもリレーションを設定する方法自体はあります。が、特例なので別の方法があるということを知っていれば良いと思います。)

Post に user_id を保存する

下記は Controller の記述です。

    use App\Post;
    use Auth;

    ~~~~~~~~~~~~~~

    public function store(PostRequest $request)
    {
        $post = new Post;
        //投稿する際に、ログインしている人のIDが保存されるようにします。
        $post->user_id = Auth::id();
        $post->title = $request->title;
        $post->content = $request->content;
        $post->save();
        return redirect()->route('post.create');
    }

投稿機能に関してよくわからない場合は、こちらの記事を参照してください。

【初心者向け】Laravel で投稿機能を作ってみる(掲示板的なやつ)

【初心者向け】Laravel のフォームリクエストでバリデーションする

リレーションしたデータを取り出す

リレーションは、user から見ると post は複数の可能性があります。

モデルの User.php を編集してください。

public function posts()
{
    return $this->hasMany('App\Post');
}

これで下準備は OK です。

App\Post はリレーションする、Post モデルがある場所を指定してください。

ユーザー一覧を取得するのを想定します。

コントローラー

use App\User;

~~~~~~~~

public function index()
{
  $users = User::all();
  return view('users/index',compact('users'));
}

views

@foreach($users as $user)
  {{ $user->posts }}
@endforeach

データが入っていたら配列にめちゃくちゃなデータが入っているはずです。

なぜなら1対多なので、多の方は複数を前提としているので、配列で出てきます。

これを全て表示するなら、

@foreach($users as $user)
  @foreach($user->posts as $post)
    <h3>{{$post->title}}</h3>
    <p>{{$post->content}}</p>
  @endforeach
@endforeach

このように foreach でまた回す必要があります。

Eager ロード(データベース接続の回数を減らす)

実は、先程の foreach の記述はあんまり良い書き方ではありません。

というのも、users の数だけ、posts テーブルに接続してデータを取得しているからです。

これを N +1問題などと言われたりします。

なので、users のデータを取得する段階で、posts データも一緒に取得するのがベターなやり方となっています。

なので、Laravel ではこの問題を解決する方法が用意されています。

コントローラー

public function index()
{
  $users = User::with('posts')->get();
  return view('users/index',compact('users'));
}

このように、with(‘モデルで定義した関数名’)と書くだけで OK です。

なので、リレーションには with がハッピーセットであると覚えて良いと思います。

Join だとどうなるか

join は、今回紹介したモデルにリレーションを定義するやり方とは別の方法でデータを取得する方法です。

public function index()
{
              //joinするテーブル名、どこのカラムと、どこのカラムが=なのか
  $users = User::join('posts','posts.user_id','=','users.id')
      ->get();
  return view('users/index',compact('users'));
}

このようになります。

第一引数で join するテーブル名でどのテーブルのどのカラムと、どのテーブルのどのカラムがイコールなのかを記述すれば OK です。

まとめ

いかがだったでしょうか?

以上がリレーションについて、僕なりにわかりやすくまとめた記事となります。

感想や誤字などありましたら、TwitterDM からご連絡お願いします。

人気記事

PHP7.4 + Laravel6 のプロジェクトを AWS EC2 にデプロイする

関連記事

Laravel で1対1のリレーションをする方法。【hasOne】

Laravel で多対1のリレーションをして保存、表示する方法。1対多のときの逆【belongsTo】

Laravel で多対多のリレーションをして保存、表示する方法【belongsToMany】