例えば、こんなパターン。
この画像のように、投稿を表示する場合、その投稿をしたユーザー名も表示したいとしましょう。でも、投稿はpostsテーブルに、ユーザー名はusersテーブルに保存されています。
2つの情報はバラバラ。これでは普通にコントローラーからクエリを書いても、バラバラにしか情報を出せず、誰がどの記事を書いたかという情報がないので、上のような表示ができません。
なので、postsテーブルとusersテーブルをリレーション(relation)という機能を使って連結して、誰がどの投稿を書いたのかも保存する必要があります。
下の図を見てください。投稿を保存してるpostsテーブルと、ユーザーを保存してるusersテーブルがあります。
ただ、どのユーザーが投稿したのかが分かるように、user_idというリレーションカラム(foreign key)を作る事で、「id1の投稿は、Hana(id3)がしたもの」というのが分かるようになり、先程の例のように、投稿に投稿者名を表示するといった事ができるようになるわけです。
というわけで、今回は、このリレーションをデータベースに作る方法を解説していきます。
laravelで関連テーブル情報を表示するリレーションのやり方。
では、以下の流れで関連テーブル情報をサイトに表示する事ができるようになります。
- foreign_key をデータベースに作成する(マイグレーション)
- モデルを書く(1対多、多対多)
- コントローラーからuser_idを保存する
- クエリでDBから関連テーブルのデータを取り出す
- ブレードに表示する
foreign_key をデータベースに作成する(マイグレーション)
では、冒頭の例のように、postsテーブルにuser_idというリレーションカラム(foreign_key)を作っていくという前提で話していきます。
そして、すでにposts、users、2つのテーブルがデータベースに作成済みで、user_idカラムとforeign_keyだけ追加したいという状況だとしましょう。
foreign_key(外部キー)とは
いきなり新ワードがまた出てきてご乱心されていると思いますが、
foreign_key(外部キー)は、鍵をかけるという事です。
これは、phpMyAdminの構造タブで見れる画面なんですが、金の鍵マーク、銀の鍵マークがあります。
なんで鍵マークが付いてるかというと、鍵がかかってるので、勝手に値を変更できないようになってるって意味です。
idなら、投稿するたびに自動的に、1,2,3,4・・と数字が振られていきます。独自に任意の数字を設定できないように、Primary Key(主キー)がかかってます。
そして、user_idも、usersテーブルのidと連動してますから、usersに存在しないidなどを勝手に入力できないように、foreign_key(外部キー)をかけるわけです。
というわけで、user_idを設置するマイグレーションをやっていきます。
user_idカラムをマイグレーションをする
まず、新しいマイグレーションファイルを作成します。
コマンドプロンプト(shell/ターミナル)を開いて、cdでLaravelプロジェクトフォルダに移動後、
php artisan make:migration add_foreign_to_posts_table --table=posts
と入力、Enterします。
database\migrationsフォルダを開き、できたファイルを開いてください。
public function up(){ }の中に以下の黄色部分を追記します。
コピーしました
コピー
$table->bigInteger('user_id')->nullable()->unsigned();
$table->foreign('user_id')->references('id')->on('users');
1行目はuser_idカラムを追加するコマンドで、2行目がforeign_keyを作成するコマンドです。
2行目を説明すると、
作ったuser_idカラムをforeign_keyとして設定し、usersテーブルのidを参照するんだよという事が書かれています。
→LaravelのMigrationとは?初心者でも図解で面白いほどよく分かる!
→LaravelのMigrationでカラムを追加、編集、削除のやり方。初心者でもよく分かるように解説!
上書き保存したら、先程のコマンドプロンプトを開いて
php artisan migrate
と入力すれば、postsテーブルに、foreign_key付きのuser_idカラムが追加されます。
エラーが出てできない場合は↓
phpMyAdminの構造タブを見ると、銀の鍵マークが付いてます。これが外部キーができたという印です。
モデルを書く(1対多、多対多)
さて、今作成した外部キーを操るには、Modelが必要です。
appフォルダ内に、User.php, Post.phpのようなファイルがある事を確認してください。
モデルがない場合は、コマンドプロンプトに打って作成してください。
- コマンドプロンプトを開き
- cdでLaravelプロジェクトフォルダに移動し
- php artisan make:model Postのように入力、Enter
する事で作成できます。
→LaravelのModel(Eloquent)とは?初心者でも図とチュートリアルでちゃんと分かる!
主テーブルと従テーブルを決める
さて、このリレーションを使って、データベースのデータを出し入れするには、主テーブル、従テーブルを理解する必要があります。
今回は、user_idという外部キー付きカラムを作りましたが、外部キーがある側は従テーブル、逆に参照される側は主テーブルとなります。
これを理解してないと、モデルにリレーションを書けないんです。
モデルにリレーションを設定する
では、appフォルダ内のPost.php と User.php の2つのモデルのファイルを開きます。
まず、Postモデル。
class Post extends Model { }内に黄枠部分を追記します。
コピーしました
コピー
public function user(){
return $this->belongsTo('App\User');
}
このように、書く事により、コントローラーからクエリを書く際、postsテーブルと関連するusersテーブルのデータを呼び出せるようになります。
先程、postsテーブルは従テーブルだと言いました。従テーブルの場合は、belongsToと書く必要があります。
これで完成と言えば完成なんですが、
逆にusersテーブルのデータをクエリで引き出す際に、関連する投稿も出せるようにしたいのであれば、Userモデルにも追記が必要です。
今度は、User.phpを開いて、
class User extends Authenticatable{ }内に以下を追記します。
コピーしました
コピー
public function posts(){
return $this->hasMany('App\Post');
}
主テーブルの場合は、hasMany、もしくはhasOneと書く事で、従テーブルの情報を一緒に引き出せるようになります。
hasMany と hasOneの違い
hasは2種類あります。
例えば、口コミサイトにせよ、ブログにせよ、
1userは、複数のposts(投稿)を行う可能性が高いですよね。
こういう場合は、
public function posts(){
return $this->hasMany('App\Post');
}
のように、書きます。
じゃあ今度は、仮にprofilesテーブルをデータベースに作ったとします。その場合、1userには1プロフィールしかないわけです。プロフィールは更新は可能ですが、上の投稿画像のように1人が複数行持つ事はありません。
この場合は、
public function profile(){
return $this->hasOne('App\Profile');
}
のように書きます。
user_idを保存してみよう
では、Modelの設定まで完了したので、今度は、あなたのサイトの投稿フォームから投稿した際、user_idも一緒にデータベースに登録されるようにする必要があります。
といっても、ログイン機能設置済みならブレード側に何か書き加える必要はありません (ログイン機能を使わない場合は、inputフィールドなどでuser_idを一緒に送信する必要がありますが)
実際にフォームから投稿が送信された際、コントローラー側で、現在のログインユーザーが誰かをチェックできます。
コントローラーで投稿を保存する際、
$post->user_id = auth()->id();
のように、auth()->id();と書く事で、自動的に現在ログインしているユーザーのid番号を取得できます。それをpostsテーブルのuser_idカラムに保存すれば、誰が投稿したかまで保存できるというわけです。
データベースから関連テーブルの情報を取り出す(クエリ)
では、リレーションを使って、コントローラーにクエリを書いて、データベースから投稿+投稿ユーザーの両方を取り出してみましょう。
<クエリ例>
$val = Post::with('user')->where('id', $id)->first();
上の例は、個別の投稿表示ページに1件だけ投稿を表示する際のクエリです。
例えば、show/7 というURLにアクセスしたら、データベースからid7の投稿を取り出すと同時に、投稿者情報もusersテーブルから取り出すようになっています。
先程、Post.phpには、userメソッドを作りました。
コントローラーに書くPost::where()のようなクエリに、with('user')と、モデルに作ったメソッド名を書き足せば、
投稿に関連したユーザー情報、つまり投稿者名、投稿者メールアドレスなどのusersテーブルの情報を一緒に出す事ができるようになるんです。
ブレード側で表示する際の書き方
では、コントローラーで取り出したこのクエリ、どうやってブレード側で表示すればいいのかなんですが、
{{ $val->user->name }}
のように、書く事で、投稿者名を表示する事ができます。
通常、例えば、投稿タイトルを表示するなら、{{ $val->title }}のように書くわけですが、
usersテーブルの中身を取り出すなら、$val->user->カラム名 のように書くという事です。
先程のwith('')の所に書いたuserを一緒に書く事で、中身を取り出せるわけです。
phpMyAdminから、リレーションカラムの値を変更も可能
例えば、すでに投稿がある場合は、phpMyAdmin側から、user_idを投稿にセットする事もできます。
user_idを設定もしくは変更したい行の編集ボタンを押します。
そして、user_idの値のプルダウンメニューを押せば、ユーザー一覧が出てくるので、ユーザーを選んで保存すれば良いわけです。
というわけで、Modelのリレーションを使えば、関連テーブルのデータが取り出せます。