ホーム
Sponserd by↑転職したい人向け、ベンチャー企業の採用動画があります

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

⇨ Laravel 記事の目次はこちら

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

Laravel のオススメの本 ⇨「動かして学ぶ!Laravel 開発入門」

目次

  1. リレーションとは?
  2. テーブル設計
  3. 保存する
  4. リレーションしたデータを取り出す
  5. Eager ロード(データベース接続の回数を減らす)
  6. Join だとどうなるか

リレーションとは? とは

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

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

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

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

検証環境

Laravel 6

テーブル設計

リレーション設計

posts テーブルと、tags テーブルがあって、posts に紐づく tags が複数あるケースの話になります。

簡単にいうと、「ハッシュタグを複数つけられるようにしたい」ってことです。

そういう時には、多対多のリレーションを使う必要があります。

多対多には中間テーブルが必要

中間テーブルというのは、今回の画像でいうところの、

post_tag テーブルに当たります。

中間テーブル名は、単数系_単数系じゃないとダメ

まず、中間テーブルとして紐づけたいテーブルとテーブルの単数系をアンダーバーでつなぐ必要があります。

posts と tags テーブルの中間テーブルなので、post_tag となります。

中間テーブル名は、a-z 順で早い方が左側にこないとダメ

a-z 順という書き方をしてしまいましたが、abcd 順という意味です。

今回は、posts の p が、tags の t より abcd 順で先に来るので、post_tag というテーブル名になります。

users と tags の中間テーブルなら、t の方が u より先に来るので、tag_user になります。

モデルに定義する

中間テーブル用のモデルは不要です。

その代わり、Posts テーブルのモデルと、Tags テーブルのモデルの2つに記述する必要があります。

モデル Post.php

    public function tags()
    {
        return $this->belongsToMany('App\Tag');
    }

モデル Tag.php

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

App\Post のところはモデルがあるところを定義してあげてください(App\Models\Post の人もいると思います。)

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

Post の一覧に複数タグをリレーションさせるためには、with を使うと良いです。

Controller

use App\Post;

~~~~~~~~
    public function index()
    {
        $posts = Post::with('tags')->get();
        //dd($posts);
        return view('home');
    }

次は、表示です。

タグは複数あるはずなので foreach で回してあげます。

views

@foreach($posts as $post)
  {{ $post->title }}
  @foreach($post->tags as $tag)
    {{ $tag->name }}
  @endforeach
@endforeach

保存する方法

$post に対して、タグを紐づけるときの書き方です。

注意して欲しいのは、新しいタグを生成するのと、タグを紐づけるのは別であることです。

新しいタグを作るときは、普通に new して save すれば作ることができます。その、作った ID を attach すればタグを紐づけることができます。

    public function tag(Request $request)
    {
        //新しいタグを生成する場合
        $tag = new Tag;
        $tag->name = $request->name;
        $tag->save();
        //または、新しいタグを生成しない場合、tagのidだけrequestして送っても良いです。
        $tag_id = $request->tag_id;


        //新しいポストの作成(findして既存のpostに紐づけるでもOK)
        $post = new Post;
        $post->user_id = 1;
        $post->title = 'title';
        $post->content = 'content';
        $post->save();
        // または、既存のPostに対してタグを紐づける
        $post = Post::find($request->post_id);


        //タグを紐づける(引数にタグのIDさえ渡れば良い)
        //tags()はPostモデルで作ったfunctionの名前
        //新しくタグを生成していたら、こんな感じ。
        $post->tags()->attach($tag->id);
        //または、既存のタグのIDだけ送ったパターン。
        $post->tags()->attach($tag_id);
    }

↑ コピペだと動かないのでコメントアウトを読んで、実装してみてください。

タグを新規で生成するか既存のものか、ポストを新規で生成するか既存のものか、みたいなのを、両方書いてます。

大事なのは、

  //新しくタグを生成していたら、こんな感じ。
  $post->attach($tag->id);

この部分です。

すでにモデルでリレーションを定義していれば、これだけの記述で中間テーブルにデータが作成されます。

中間テーブルの削除

attach と同様に、detach という記述で簡単に済みます。

//狙った1つのタグだけを外したい
$post->detach($tag_id);
//postに紐づく全ての中間テーブルを削除したい
$post->detach();

となります。

まとめ

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

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

中間テーブルの設計など、ちょっとややこしいところだと思いますが、できるだけ簡潔に書いてみました。

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

オススメの Vue の本

人気記事

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

関連記事

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

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

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