Eloquent:リレーションイントロダクションデータベーステーブルは大抵の場合他のものと関連しています。ブログポストは多くのコメントを持つか、それを投稿したユーザーと関連しています。Eloquentはそうしたリレーションを簡単に管理し操作できるようにするとともに、様々なタイプのリレーションをサポートしています。Throughポリモーフィックリレーションポリモーフィック関係の多対多リレーションの定義EloquentのリレーションとはEloquentモデルクラスの関数として定義します。Eloquentモデル自身と同様にリレーションはパワフルなクエリービルダーとして動作しますので、関数として定義しているリレーションはパワフルなメソッドのチェーンとクエリー能力を提供できるのです。1)->get();リレーションの使い方へ進む前に、リレーションの各タイプをどのように定義するかを学びましょう。1対11対1関係が基本です。UserモデルはPhoneモデル一つと関係しているとしましょう。このリレーションを定義するには、phoneメソッドをUserモデルに世知します。phoneメソッドはベースのEloquentモデルクラスのhasOneメソッドを結果として返す必要があります。}}hasOneメソッドの最初の引数は関係するモデルの名前です。リレーションが定義できたらEloquentの動的プロパティを使って、関係したモデルを取得できます。動的プロパティによりモデル上のプロパティのようにリレーション関数にアクセスできます。User::find(1)->phone;Eloquentはリレーションの外部キーがモデル名に基づいていると仮定します。この場合自動的にPhoneモデルはuser_id外部キーを持っていると仮定します。この規約をオーバーライドしたければ、hasOneメソッドの第2引数を指定してください。'foreign_key');Eloquentは親のidカラムと一致する外部キーの値を持っていると仮定します。言い換えればEloquentはユーザーのidカラムの値をPhoneレコードのuser_idカラムに存在しないか探します。リレーションで他のidを使いたければ、hadOneメソッドの第3引数でカスタムキーを指定してください。'local_key');逆の関係の定義これでUserからPhoneモデルへアクセスできるようになりました。今度はPhoneモデルからそれを所有しているUserへアクセスするリレーションを定義しましょう。hasOneの逆のリレーションを定義するには、belongsToメソッドを使います。}}上の例でEloquentはPhoneモデルのuser_idに一致するidを持つUserモデルを見つけようとします。Eloquentはリレーションメソッド名に_idのサフィックスを付けた名前をデフォルトの外部キー名とします。Phoneモデルの外部キーがuser_idでなければ、belongsToメソッドの第2引数にカスタムキー名を渡してください。'foreign_key');}親のモデルの主キーがidでないか子のモデルと違ったカラムで紐付けたい場合は、親テーブルのカスタムキー名をbelongsToメソッドの第3引数に渡してください。「1対多」リレーションは一つのモデルが他の多くのモデルを所有する関係を定義するために使います。ブログポストが多くのコメントを持つのが一例です。他のEloquentリレーションと同様に1対多リレーションはEloquentモデルの関数として定義します。}}EloquentはCommentモデルに対する外部キーを自動的に決めることを心に留めてください。規約によりEloquentは自分自身のモデル名の「スネークケース」に_idのサフィックスをつけた名前と想定します。今回の例でEloquentはCommentモデルの外部キーをpost_idであると想定します。リレーションを定義したらcommentsプロパティによりコメントのコレクションへアクセスできます。Eloquentは「動的プロパティ」を提供しているのでモデルのプロパティとして定義したリレーション関数へアクセスできることを覚えておきましょう。//}もちろん全リレーションはクエリービルダーとしても働きますから、commentsメソッドを呼び出すときにどのコメントを取得するのかという制約を追加でき、クエリーに条件を続けてチェーンでつなげます。'foo')->first();hasOneメソッドと同様に、外部キーとローカルキーをhasManyメソッドに追加の引数として渡すことでオーバーライドできます。'local_key');逆のリレーションを定義これでポストの全コメントにアクセスできます。今度はコメントから親のポストへアクセスできるようにしましょう。hasManyリレーションの逆を定義するには子のモデルでbelongsToメソッドによりリレーション関数を定義します。}}リレーションが定義できたらCommentのPostモデルをpost動的プロパティにより取得しましょう。$comment->post->title;前例でEloquentはCommentモデルのpost_idと一致するidのPostモデルを見つけようとします。Eloquentはリレーションメソッドの名前に_idのサフィックスをつけた名前をデフォルトの外部キーとします。Commentモデルの外部キーがpost_idでなければ、belongsToメソッドの第2引数にカスタムキー名を指定してください。'foreign_key');}親モデルが主キーにidを使っていない場合、もしくは子供のモデルに異なったカラムを紐つけたい場合は、belongsToメソッドの第3引数にテーブルのカラム名を指定してください。多対多の関係はhasOneとhasManyリレーションよりも多少複雑な関係です。このような関係として、ユーザ(user)が多くの役目(roles)を持ち、役目(role)も大勢のユーザー(users)に共有されるという例が挙げられます。多くのユーザーは"管理者"の役目を持っています。users、roles、role_userの3テーブルがこの関係には必要です。role_userテーブルは関係するモデル名をアルファベット順に並べたもので、user_idとrole_idを持つ必要があります。多対多リレーションはベースのEloqunetクラスのbelongsToManyメソッド呼び出しを記述することで定義します。例としてUserモデルにrolesメソッドを定義してみましょう。}}リレーションが定義できたら、roles動的プロパティを使いユーザーの役割にアクセスできます。//}もちろん他のリレーションタイプと同様にリレーションを制約するクエリーをrolesに続けてチェーンすることができます。App\User::find(1)->roles()->orderBy('name')->get();前に述べたようにリレーションの結合テーブルの名前を決めるため、Eloquentは2つのモデル名をアルファベット順に結合します。この規約は自由にオーバーライドできます。belongsToManyメソッドの第2引数に渡してください。'user_roles');結合テーブル名のカスタマイズに加えテーブルのキーカラム名をカスタマイズするには、belongsToManyメソッドに追加の引数を渡してください。第3引数はリレーションを定義しているモデルの外部キー名で、一方の第4引数には結合するモデルの外部キー名を渡します。多対多のリレーションの逆リレーションを定義するには、関連するモデルでもbelongsToManyを呼び出してください。引き続きユーザーと役割の例を続けますがRoleモデルでusersメソッドを定義してみましょう。}}ご覧の通り一方のUserと全く同じ定義のリレーションです。違いはApp\Userモデルを参照していことです。同じbelongsToManyメソッドを使っているのですから、通常のテーブル名、キーカスタマイズのオプションは逆の多対多リレーションを定義するときでも全て使用できます。学んだように、多対多リレーションの操作には中間テーブルが必要です。Eloquentこのテーブルを操作する便利な手段を用意しています。例としてUserオブジェクトが関連するRoleオブジェクトを持っているとしましょう。このリレーションへアクセスした後、モデルのpivot属性を使い中間テーブルにアクセスできます。$role->pivot->created_at;}取得したそれぞれのRoleモデルは自動的にpivot属性と自動的に結合されます。この属性は中間テーブルを表すモデルを含んでおり、他のElouquentモデルと同様に使用できます。デフォルトでモデルキーはpivotオブジェクト上のものを表しています。中間テーブルがその他の属性を持っている場合、リレーションを定義するときに指定できます。'column2');もし中間テーブルのcreated_at、updated_atタイムスタンプを自動的に保守したい場合は、withTimestampsメソッドをリレーション定義に付けてください。through(〜経由の多対多)リレーションは、仲介するテーブルを通して直接関連付けしていないテーブルへアクセスするための、便利な近道を提供します。CountryモデルはUsersモデルを経由して、多くのPostsを所有することでしょう。テーブルは以下のような構成になります。stringたとえpostsテーブルにcountry_idが存在しなくても、hasManyThroughリレーションではCountryのPostへ$country->postsによりアクセスできます。このクエリーを行うためにEloquentは仲介するusersテーブルのcountry_idを調べます。一致するユーザーIDが存在していたらpostsテーブルのクエリーに利用します。リレーションのテーブル構造を理解したところで、Countryモデルを定義しましょう。}}hasManyThroughメソッドの第一引数は最終的にアクセスしたいモデル名で、第2引数は仲介するモデル名です。リレーションのクエリー実行時では典型的なEloquentの外部キー規約が使用されます。リレーションのキーをカスタマイズしたい場合はhasManyThroughメソッドの第3引数と、第4引数を指定してください。第3引数は仲介モデルの外部キー名、第4引数は最終的なモデルの外部キー名です。}}ポリモーフィック関係テーブル構造ポリモーフィックリレーションはあるモデルを一つの関係だけで、複数のモデルに所属させるものです。スタッフメンバーと商品の写真を保存するとしましょう。ポリモーフィックリレーションによりphotosテーブル一つを両方のシナリオで使用できます。最初にこのリレーションを構築するために必要な構造を確認してください。stringphotosテーブル上の2つの重要なカラム、imageable_idとimageable_typeに注目してください。imageable_idカラムは所有しているスタッフか製品のIDを持っています。一方のimageable_typeカラムは所収されているモデルのクラス名を持っています。imageable_typeはimageableリレーションにアクセスされた時に返す、所有しているモデルの「タイプ」をORMが決定するためのカラムです。次にこのリレーションを構築するために必要なモデル定義を見てみましょう。}}ポリモーフィックリレーションの取得データベーステーブルとモデルが定義できたらモデルを使いリレーションにアクセスできます。スタッフメンバーの全写真にアクセスするにはphotos動的プロパティーを使用するだけです。//}ポリモーフィックモデルからポリモーフィックリレーションの所有者をmorphToを呼び出すメソッド名にアクセスすることで取得できます。今回の例の場合Photoモデルのimageableメソッドです。動的プロパティーとしてメソッドにアクセスしてみましょう。$photo->imageable;Photoモデルのimageableリレーションは写真を所有しているモデルのタイプにより、StaffかProductインスタンスを返します。カスタムポリモーフィックリレーション関連付けられたモデルのタイプを保存するため、デフォルトでLaravelははっきりと区別できるクラス名を使います。上記の例で、LikeがPostかCommentに所属しているとすると、likable_typeはデフォルトでApp\PostかApp\Commentのどちらかになるでしょう。データーベースはアプリケーションの内部構造と分離したいかと思います。map"を定義し、クラス名の代わりに使用する、各モデルに関連づいたテーブル名をEloquentへ指示することができます。App\Comment::class,]);もしくは、各モデルに関連づいた、カスタム文字列を指定することもできます。App\Like::class,]);morphMapはAppServiceProviderの中で登録できます。要望に合わせて、独立したサービスプロバイダを作成することもできるでしょう。伝統的なポリモーフィックリレーションに加え、「多対多」ポリモーフィックリレーションも指定することができます。ブログのPostとVideoモデルはTagモデルに対するポリモーフィックリレーションを共有できます。多対多ポリモーフィックリレーションを使うことで、ブログポストとビデオの両者に所有されている一意のタグのリストを取得できます。最初にテーブル構造を確認しましょう。次にモデルにその関係を用意しましょう。PostとVideoモデルは両方ともベースのEloquentクラスのmorphToManyメソッドを呼び出すtagsメソッドを持っています。次にTagモデルで関係する各モデルに対するメソッドを定義する必要があります。この例の場合、postsメソッドとvideosメソッドを用意します。}}リレーションの取得データベーステーブルとモデルが定義できたら、モデルを使いリレーションにアクセスできます。ポストに対する全タグへアクセスするには、単にtags動的プロパティーを使用するだけです。//}さらにmorphedByManyを呼び出すメソッドの名前にアクセスし、ポリモーフィックモデルからポリモーフィックリレーションの所有者を取得することも可能です。この例の場合Tagモデルのpostsとvideosメソッドです。動的プロパティーとしてメソッドを呼び出しましょう。//}リレーションのクエリーEloquentリレーションは全てメソッドとして定義され、リレーションのクエリーを実際に記述しなくてもメソッドを呼び出すことでそのリレーションのインスタンスを取得できます。付け加えるなら、全タイプのEloquentリレーションもクエリービルダーとしても動作し、データベースに対してSQLが最終的に実行される前にそのリレーションのクエリーをチェーンで続けて記述できます。ブログシステムで関連した多くのPostモデルを持つUserモデルを想像してください。}}次のようにpostsリレーションのクエリーに追加の制約を付け加えられます。動的プロパティーEloquentリレーションクエリーに追加の制約を加える必要がなければ、シンプルにそのリレーションへプロパティーとしてアクセスできます。UserとPostの例を続けるとして、ユーザーの全ポストには次のようにアクセスできます。//}動的プロパティーは「遅延ロード」されます。実際にアクセスされた時にだけそのリレーションのデータはロードされます。そのため開発者は多くの場合にEagerローディングを使い、モデルをロードした後にアクセスするリレーションを前もってロードしておきます。Eagerロードはモデルのリレーションをロードするため実行されるSQLクエリーを大幅に減らしてくれます。関連付けたモデルのレコードに基づいて、モデルのレコードに対するマッチングを絞り込みたい場合もあるでしょう。最低でも一つのコメントを持つ、全ブログポストを取得したい場合を考えてください。これを行うためにはhasメソッドを使用します。App\Post::has('comments')->get();演算子と数を指定しクエリーをカスタマイズすることもできます。3)->get();ネストしたhas文は「ドット」記法で組立てられます。最低一つのコメントと評価を持つ全ポストを取得する場合です。Post::has('comments.votes')->get();もっと強力な機能がお望みならばhasの問い合わせに"where"で条件をつけるために、whereHasやorWhereHasを利用して下さい。これらのメソッドによりリレーションの制約にカスタマイズした制約を追加できます。コメントの内容を調べることです。'foo%');})->get();EagerローディングEloquentリレーションをプロパティーとしてアクセする場合、リレーションのデータは「遅延ロード」されます。プロパティーにアクセスされるまで実際にリレーションのデータはロードされることはありません。Eloquentでは親モデルにクエリーする時点で「Eagerロード」できます。EagerローディングはN+1クエリー問題を軽減するために用意しています。BookモデルがAuthorモデルと関連していると考えてください。関係はこのように定義されます。}}では全書籍とその著者を取得しましょう。$book->author->name;}このループではまず全ての本をテーブルから取得するために1クエリー実行され、それから著者をそれぞれの本について取得します。25冊あるならば、このループで26クエリーが発生します。ありがたいことにクエリーの数を徹底的に減らすためにEagerローディングを使うことができます。withメソッドを使い指定してください。$book->author->name;}この操作では2つだけしかクエリーが実行されません。...)複数のリレーションに対するEagerローディング一回の操作で異なった複数のリレーションをEagerローディングする必要がある場合もあります。その場合でも、ただwithメソッドに引数を追加で渡すだけです。'publisher')->get();ネストしたEagerローディングネストしたリレーションをEagerロードする場合は「ドット」記法が使用できます。例としてEloquent文で全著者と著者個人のコンタクトも全部Eagerロードしてみましょう。場合によりリレーションをEagerロードしたいが、Eagerロードクエリーに制約を追加したい場合があります。'%first%');}])->get();この例でEloquentはtitleカラムの内容にfirstという言葉を含むポストのみをEagerロードしています。Eagerローディング操作をもっとカスタマイズするために他のクエリービルダーを呼び出すこともできます。'desc');}])->get();遅延Eagerローディング既に親のモデルを取得した後にリレーションをEagerロードする必要がある場合もあるでしょう。これはどの関連しているモデルをロードするかを動的に決める場合に便利です。'publisher');}Eagerロードに追加の制約を付ける必要があるなら、loadメソッドへ「クロージャー」を渡してください。'asc');}]);関係したモデルの挿入saveメソッドEloquentは新しいモデルをリレーションに追加するために便利なメソッドを用意しています。Postモデルに新しいCommentを挿入する必要がある場合です。Commentのpost_id属性を自分で設定する代わりに、リレーションのsaveメソッドで直接Commentを挿入できます。App\Post::find(1);$post->comments()->save($comment);動的プロパティーとしてcommentsリレーションにアクセスできない点には注意してください。代わりにリレーションの取得でcommentsメソッドを呼び出しています。saveメソッドは自動的に新しいCommentモデルのpost_idへ適した値を代入します。複数の関連したモデルを保存する必要があるなら、saveManyメソッドを使用できます。多対多リレーションを操作する場合、saveメソッドの第2引数へ追加の中間テーブルの属性を指定できます。$expires]);createメソッドsaveとsaveManyメソッドに加え、createメソッドも使用できます。属性の配列を引数に受け付け、モデルを作成しデータベースへ挿入します。saveとcreateの違いはsaveが完全なEloquentモデルを受け付けるのに対し、createは普通のPHPの「配列」を受け付ける点です。',]);createメソッドを使用する前に属性の複数代入に関するドキュメントを読んでおいてください。To"リレーションの更新belongsToリレーションを更新する場合はassociateメソッドを使います。このメソッドは子モデルへ外部キーをセットします。App\Account::find(10);$user->account()->associate($account);$user->save();belongsToリレーションを削除する場合はdissociateメソッドを使用します。このメソッドはリレーションの子モデルの外部キーをリセットします。$user->account()->dissociate();$user->save();多対多関係の挿入attach/detach多対多リレーションを操作時により便利なように、Eloquentはヘルパメソッドをいくつか用意しています。例としてユーザーが多くの役割りを持ち、役割も多くのユーザーを持てる場合を考えてみましょう。モデルを結びつけている中間テーブルにレコードを挿入することにより、ユーザーに役割を持たせるにはattachメソッドを使います。App\User::find(1);$user->roles()->attach($roleId);モデルにリレーションを割りつけるときに中間テーブルに挿入したい追加のデータを配列で渡すこともできます。$expires]);もちろんユーザーから役割を削除する必要がある場合もあるでしょう。多対多リレーションのレコードを削除するにはdetachメソッドを使います。detachメソッドは中間テーブルから対応するレコードを削除します。両方のモデルはデータベースに残ります。ユーザーから役割を全部切り離す...$user->roles()->detach();便利なようにattachとdetachの両方共にIDの配列を指定することができます。3]);便利なsync多対多の関連を構築するためにsyncメソッドも使用できます。syncメソッドへは中間テーブルに設置しておくIDの配列を渡します。その配列に指定されなかったIDは中間テーブルから削除されます。この操作が完了すると、中間テーブルには配列中のIDだけが存在することになります。3]);IDと一緒に中間テーブルの追加の値を渡すことができます。3]);親のタイムスタンプの更新CommentがPostに所属しているように、あるモデルが他のモデルに所属(belongsToもしくはbelongsToMany)しており、子のモデルが更新される時に親のタイムスタンプを更新できると便利なことがあります。Commentモデルが更新されたら、所有者のPostのupdated_atタイムスタンプを自動的に"touch"したい場合です。Eloquentなら簡単です。子のモデルにtouchesプロパティを追加しリレーション名を指定してください。}}これでCommentが更新されると、所有しているPostのupdated_atカラムも同時に更新されます。kawase(Translation).ドキュメントメンテナンス期間は終了しました。注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。閉じる移動クリックで即時移動します。適用ボタンクリック後に、全項目まとめて適用されます。Scaffoldスカフォールド型枠生成スカフィールドLargeスクリーン表示幅640px80%90%100%インデントなし1rem2rem3rem本文フォントコードフォントフォント適用確認フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。バックスラッシュを含むインライン\Code\Blockの例です。以下はコードブロックの例です。}}設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。