モデルの関連付け
- 1 対 1
- 逆関連付けの定義
- 1 対多
- 1 対多 (逆)
- 逆関連付けの定義
- 中間テーブル フィールドの取得
- #From ピボット属性名を定義します
- 中間テーブル モデルを定義する
- #ID が増加するカスタム リレー モデル
- ##リモート 1 対 1 リレーションシップ #リモート 1 対 1 関係マルチアソシエーション
- ポリモーフィック アソシエーション
- テーブル構造
- #モデル構造
- #関連付けの取得
- クエリの関連付け
- プリロード ##関連モデルの挿入と更新
- #保存メソッド
- モデルと関連データを再帰的に保存
- ##更新は関連付けに属します
- デフォルト モデル
- アタッチ/デタッチ
- 関連付けの切り替え
- 中間テーブル データの追加の保存
- 中間テーブルのレコードの更新
- 親タイムスタンプの更新
- はじめに
- アソシエーションの定義
- ポリモーフィック関連付け #クエリの関連付け
- は、制約を追加するためのプリロードです。
- 遅延プリロード
- ##挿入と更新です。関連モデル
- save メソッド
create メソッド
- #Update
所属
関連付け - 多対多の関連付け
- ##Update親セットのタイムスタンプ
- #多対多
- #リモート 1 対 1 #リモート 1 対多
- 1 対 1 (ポリモーフィック関連付け)
- 1 対多 (ポリモーフィック関連付け)
- 多対多 (ポリモーフィック関連付け)
- #
Define Association
Eloquent Association は、Eloquent モデル クラスのメソッドとして提供されます。 Eloquent モデル自体と同様に、アソシエーションも強力なクエリ ステートメント ビルダーとして使用でき、強力なチェーン コールとクエリ関数を提供します。たとえば、
posts
アソシエーションの連鎖呼び出しに制約を付けることができます:$user->posts()->where('active', 1)->get();
ただし、アソシエーションの使用に入る前に、各アソシエーション タイプを定義する方法を学びましょう。
#1 対 11 対 1 は最も基本的な関係です。たとえば、User
モデルは
Phoneモデルに関連付けられている場合があります。この関連付けを定義するには、
Userモデルに
phoneメソッドを記述する必要があります。
phoneメソッド内で
hasOneメソッドを呼び出し、その結果を返します。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model{ /** * Get the phone record associated with the user. */ public function phone() { return $this->hasOne('App\Phone'); } }
hasOne
メソッドの最初のパラメータは、次のクラス名です。関連するモデル。モデルの関連付けが定義されたら、Eloquent の動的プロパティを使用して関連レコードを取得できます。動的プロパティを使用すると、モデルで定義されたプロパティと同じようにリレーショナル メソッドにアクセスできます。
$phone = User::find(1)->phone;
Eloquent は、モデル名に基づいて外部キー名を決定します。この場合、Phone
モデルには
user_id外部キーがあると自動的に想定されます。この規則をオーバーライドしたい場合は、
hasOneメソッドに 2 番目の引数を渡すことができます:
return $this->hasOne('App\Phone', 'foreign_key');
さらに、Eloquent は外部キーの値が親 ID と同じであると想定します。 (またはカスタム $primaryKey) 列の値が一致します。つまり、Eloquent は、Users テーブルの id 列と一致する Phone レコードの user_id 列の値を探します。関連付けで id 以外のカスタム キー名を使用する場合は、3 番目のパラメーターを hasOne メソッドに渡すことができます。return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
逆の関連付けを定義しますWePhone
モデルには、
Userモデルからアクセスできます。次に、電話を所有する
Userモデルへのアクセスを許可する、
Phoneモデルに別の関連付けを定義しましょう。
hasOneメソッドに対応する
belongsToメソッドを使用して逆関連付けを定義できます:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Phone extends Model{ /** * 获得拥有此电话的用户 */ public function user() { return $this->belongsTo('App\User'); } }
上記の例では、Eloquent はPhone# との一致を試みます。モデルの
##user_id
をUser
モデルのid
に変更します。リレーションシップ メソッドの名前を調べ、サフィックスとして_id
を使用することで、デフォルトの外部キー名が決定されます。ただし、Phone
モデルの外部キーがuser_id
でない場合は、カスタム キー名を 2 番目のパラメーターとしてbelongsTo
メソッドに渡すことができます。/** * 获得拥有此电话的用户 */ public function user(){ return $this->belongsTo('App\User', 'foreign_key'); }
親モデルが
id を主キーとして使用しない場合、または別のフィールドを使用して子モデルを接続する場合は、3 番目のパラメーターをbelongsTo# に渡すことができます。 ## メソッド。親データ テーブルのカスタム キーを次の形式で指定します:
もちろん、すべてのリレーションシップはクエリ ステートメント ビルダーとしても使用できるため、連鎖呼び出しを使用できます。/** * 获得拥有此电话的用户 */ public function user(){ return $this->belongsTo('App\User', 'foreign_key', 'other_key'); }
comments
メソッドに追加の制約を追加するには:
$comment = App\Post::find(1)->comments()->where('title', 'foo')->first();
hasOne
メソッドと同様に、
hasManyメソッドを使用して追加のパラメーターを渡すこともできます。使用されるデフォルトの外部キーとローカル キーをオーバーライドするには:
return $this->hasMany('App\Comment', 'foreign_key'); return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
1 対多 (逆) これで、記事のすべてのコメントを取得し、コメントを通じて記事を取得するための関連付けを定義できました。この関連付けは、hasMany
関連付けの逆の関連付けです。
belongsToメソッドを使用して子モデルで定義する必要があります:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model{ /** * 获取此评论所属文章 */ public function post() { return $this->belongsTo('App\Post'); } }
この関係を定義した後、Comment
モデルの
post「動的属性」にアクセスすることで、関連する
Postモデルを取得できます。
$comment = App\Comment::find(1); echo $comment->post->title;
上記の例では、 Eloquent は、Comment
モデルの
post_idを
Postモデルの
idと照合しようとします。デフォルトの外部キー名は、アソシエーション名に基づいて Eloquent によって決定され、その後に _ が続き、サフィックスとして主キー フィールド名が続きます。もちろん、
Commentモデルの外部キーが
post_idでない場合は、カスタム キー名を 2 番目のパラメーターとして
belongsToメソッドに渡すことができます。
/** * 获取此评论所属文章 */ public function post(){ return $this->belongsTo('App\Post', 'foreign_key'); }
親モデルがid
を主キーとして使用しない場合、または別のフィールドを使用して子モデルを接続する場合は、3 番目のパラメーターを ## に渡すことができます。 #belongsTo
メソッド。親データ テーブルのカスタム キーを次の形式で指定します:/** * 获取此评论所属文章 */ public function post(){ return $this->belongsTo('App\Post', 'foreign_key', 'other_key'); }
多対多
多対多の関係は、
hasOne
およびhasMany
の関係よりも少し複雑です。たとえば、ユーザーは多くのロールを持つことができ、これらのロールは他のユーザーによって共有されます。たとえば、多くのユーザーが「管理者」の役割を持っている可能性があります。この関連付けを定義するには、users
、roles
、およびrole_user
の 3 つのデータベース テーブルが必要です。role_user
テーブルには、関連付けられた 2 つのモデルからアルファベット順に名前が付けられ、user_id
フィールドとrole_id
フィールドが含まれます。多対多の関係は、この内部メソッド
belongsToMany
によって返された結果を呼び出すことで定義されます。たとえば、で
rolesメソッドを定義します。 User
モデル。:<?php namespace App; use Illuminate\Database\Eloquent\Model;class User extends Model{ /** * 用户拥有的角色 */ public function roles() { return $this->belongsToMany('App\Role'); } }
関連付けが定義されたら、
roles
動的属性を通じてユーザー ロールを取得できます:$user = App\User::find(1); foreach ($user->roles as $role) { // }
もちろん、すべてと同様に、他の関連付けモデルでは、連鎖呼び出しを使用して
roles
メソッドを使用してクエリ ステートメントに制約を追加できます:$roles = App\User::find(1)->roles()->orderBy('name')->get();
前述したように、関連付けられた接続テーブルのテーブル名を決定するために, Eloquent は 2 つをアルファベット順に接続します。 関連するモデルの名前。もちろん、この規則を使用せずに、2 番目のパラメータを
belongsToMany
メソッドに渡すこともできます。return $this->belongsToMany('App\Role', 'role_user');
接続テーブルのテーブル名をカスタマイズすることに加えて、追加のパラメータを渡すこともできます。テーブル内のフィールドのキー名を定義するための
belongsToMany
メソッドへのパラメーター。 3 番目のパラメーターは、接続テーブル内のこの関連付けを定義するモデルの外部キー名で、4 番目のパラメーターは、接続テーブル内の別のモデルの外部キー名です:return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
定義 逆関連付け
多対多逆関連付けを定義するには、関連付けモデルで
belongsToMany
メソッドを呼び出すだけです。Role
モデルでusers
メソッドを定義します。<?php namespace App; use Illuminate\Database\Eloquent\Model; class Role extends Model{ /** * 拥有此角色的用户。 */ public function users() { return $this->belongsToMany('App\User'); } }
ご覧のとおり、モデル
App\User
の導入を除きます。 、その他User
モデルで定義されているものとまったく同じです。belongsToMany
メソッドを再利用するため、カスタム結合テーブルのテーブル名とカスタム結合テーブルのキーのフィールド名もここに適用されます。中間テーブルのフィールドを取得する
先ほど学習したように、多対多のリレーションシップにはサポートを提供する中間テーブルが必要です。Eloquent には、このテーブルを操作するための便利なメソッドがいくつか用意されています。たとえば、
User
オブジェクトが複数のRole
オブジェクトに関連付けられているとします。これらの関連オブジェクトを取得した後、モデルのpivot
属性を使用して中間テーブルのデータにアクセスできます。$user = App\User::find(1); foreach ($user->roles as $role) { echo $role->pivot->created_at; }
各
Role
取得したモデル オブジェクトには、pivot
属性が自動的に割り当てられます。これは、中間テーブルのモデル オブジェクトを表し、他の Eloquent モデルと同様に使用できます。デフォルトでは、
pivot
オブジェクトには 2 つの関連モデルの主キーのみが含まれています。中間テーブルに他の追加フィールドがある場合は、リレーションシップを定義するときにそれを明示的に指定する必要があります。return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
中間テーブルで
created_at
およびupdated_at
タイムスタンプを自動的に維持する場合は、関連付けを定義するときにwithTimestamps
メソッドを追加します。 ##return $this->belongsToMany('App\Role')->withTimestamps();
Custompivot
前述したように、中間テーブルの属性には、属性名
pivot
たとえば、アプリに購読する可能性のあるユーザーが含まれている場合、ユーザーとブログの間に多対多の関係が存在する可能性があります。この場合、中間テーブル アクセサーに属性を使用してアクセスできます。 。ただし、アプリケーションでの使用をより適切に反映するために、このプロパティの名前を自由にカスタマイズできます。
pivot
ではなく
subscriptionという名前を付けることをお勧めします。これは、リレーションシップを定義するときに
asメソッドを使用して行うことができます:
return $this->belongsToMany('App\Podcast') ->as('subscription') ->withTimestamps();
定義が完了すると、カスタム名:$users = User::with('podcasts')->get(); foreach ($users->flatMap->podcasts as $podcast) { echo $podcast->subscription->created_at; }
## を使用して中間テーブル データにアクセスできます。#中間テーブルによるリレーションシップのフィルタリング##リレーションシップを定義する場合、wherePivot
メソッドとwherePivotIn
メソッドを使用して、 # によって返された結果をフィルタリングすることもできます。 ##belongsToMany
:return $this->belongsToMany('App\Role')->wherePivot('approved', 1); return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]);
##
中間テーブル モデルを定義する
カスタム中間テーブル モデルを定義する
関連関係の中間テーブルを表すカスタム モデルを定義する場合は、次の場合にusing# を呼び出すことができます。アソシエーションを定義する ## メソッド。カスタマイズされた
多対多中間テーブル モデルは Illuminate\Database\Eloquent\Relations\Pivot クラスから拡張する必要があり、カスタム
多対多 (ポリモーフィック)中間テーブル モデルは継承する必要があります\Database\Eloquent\Relations\MorphPivot クラスを照らします。たとえば、
ロール モデルの関連付けを記述するときは、カスタム中間テーブル モデルを使用します。
UserRole<?php namespace App; use Illuminate\Database\Eloquent\Model; class Role extends Model{ /** * 拥有此角色的所有用户 */ public function users() { return $this->belongsToMany('App\User')->using('App\UserRole'); } }
UserRole
モデルを定義するときは、拡張する必要があります
Pivotクラス:
<?php namespace App; use Illuminate\Database\Eloquent\Relations\Pivot; class UserRole extends Pivot{ // }
using
と
withPivotを組み合わせて使用して、中間テーブルから列を取得できます。たとえば、列名を
withPivotメソッドに渡すことによって、
UserRole中間テーブルから
created_by列と
updated_by列を取得できます。 。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Role extends Model{ /** * 拥有此角色的用户。 */ public function users() { return $this->belongsToMany('App\User') ->using('App\UserRole') ->withPivot([ 'created_by', 'updated_by' ]); } }
ID が増加するカスタム リレー モデルカスタム リレー モデルと多対多の関係を定義すると、リレー モデルには自動カスタム リレー モデル クラスで、値true
を持つ
incrementing属性が定義されていることを確認する必要があります:
/** * 标识 ID 是否自增。 * * @var bool */ public $incrementing = true;
リモート 1 対 1 関係リモート 1 対 1 関係は、中間関係モデルを通じて実装されます。たとえば、各プロバイダーにユーザーがあり、各ユーザーがユーザー履歴に関連付けられている場合、プロバイダーはそのユーザーを通じてユーザーの履歴にアクセスできます。この関係を定義するために必要なデータベースを見てみましょう。表:
suppliers id - integer users id - integer supplier_id - integer history id - integer user_id - integer
history
テーブルには
supplier_idが含まれていませんが、
hasOneThrough関係により、サプライヤー モデルにアクセスするためのユーザーの履歴へのアクセスが提供されます。リレーションシップのテーブル構造を調べたので、
Supplierモデルで対応するメソッドを定義しましょう:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Supplier extends Model{ /** * 用户的历史记录。 */ public function userHistory() { return $this->hasOneThrough('App\History', 'App\User'); } }
最初のパラメータはhasOneThrough
関連クエリを実行するときは、通常、Eloquent によって合意された外部キー名が使用されます。関連付けられたキーをカスタマイズしたい場合は、3 番目と 4 番目のパラメーターをメソッドに渡されます。 is はアクセスするモデルの名前で、2 番目のパラメータは中間モデルの名前です。
hasOneThrough
メソッドに渡すことで行うことができます。3 番目のパラメーターは中間モデルの外部キー名を表し、4 番目のパラメーターは中間モデルの外部キー名を表します。 Final モデルの外部キー名。 5 番目のパラメーターはローカル キー名を表し、6 番目のパラメーターは中間モデルのローカル キー名を表します:
class Supplier extends Model{ /** * 用户的历史记录。 */ public function userHistory() { return $this->hasOneThrough( 'App\History', 'App\User', 'supplier_id', // 用户表外键 'user_id', // 历史记录表外键 'id', // 供应商本地键 'id' // 用户本地键 ); } }
リモート 1 対多アソシエーション
リモート 1 対多アソシエーションは、中間アソシエーションを通じてリモート レベルのアソシエーションを取得するための便利で短い方法を提供します。たとえば、
Country
モデルには、介在するUser
モデルを介して複数のPost
モデルを含めることができます。この例では、特定の国からのすべてのブログ投稿を簡単に収集できます。この関連付けを定義するために必要なデータ テーブルを見てみましょう。countries id - integer name - string users id - integer country_id - integer name - string posts id - integer user_id - integer title - string
posts
テーブルにはcountry_id
フィールドが含まれていませんが、hasManyThrough
関連付けにより、$country->posts
を通じて、ある国のすべてのユーザー投稿にアクセスできるようになります。このクエリを完了するために、Eloquent は最初に中間テーブルusers
のcountry_id
フィールドをチェックし、一致するユーザー ID をすべて見つけた後、これらの ID をposts
で使用します。テーブル 検索を完了します。この関連付けを定義するために必要なデータ テーブル構造がわかったので、
Country
モデルで定義しましょう:<?php namespace App; use Illuminate\Database\Eloquent\Model; class Country extends Model{ /** * 当前国家所有文章。 */ public function posts() { return $this->hasManyThrough('App\Post', 'App\User'); } }
hasManyThrough の最初のパラメータ
メソッドは最終的にアクセスしたいモデルの名前であり、2 番目のパラメーターは中間モデルの名前です。関連クエリを実行するときは、通常、Eloquent によって合意された外部キー名が使用されます。関連付けられたキーをカスタマイズしたい場合は、3 番目と 4 番目のパラメーターを
hasManyThrough
メソッドに渡すことによって行うことができます。3 番目のパラメーターは中間モデルの外部キー名を表し、4 番目のパラメーターは中間モデルの外部キー名を表します。 Final モデルの外部キー名。 5 番目のパラメーターはローカル キー名を表し、6 番目のパラメーターは中間モデルのローカル キー名を表します。class Country extends Model{ public function posts() { return $this->hasManyThrough( 'App\Post', 'App\User', 'country_id', // 用户表外键 'user_id', // 文章表外键 'id', // 国家表本地键 'id' // 用户表本地键 ); } }
多態性関連付け
多態性関連付けを使用すると、ターゲット モデルを 1 つの関連付けで複数のモデルに従属させることができます。
#1 対 1 (ポリモーフィック)テーブル構造1 対 1 の多態性関連付けは単純な 1 対 1 関連付けに似ていますが、ターゲット モデルは 1 つの関連付けで複数のモデルに属することができます。たとえば、ブログPost
と
Userは、
Imageモデルとの関係を共有する可能性があります。 1 対 1 のポリモーフィック関連付けを使用すると、ブログ投稿とユーザー アカウントの両方に一意の画像リストを使用できます。まずテーブルの構造を見てみましょう。
posts id - integer name - string users id - integer name - string images id - integer url - string imageable_id - integer imageable_type - string
images
モデル構造次に、関連するモデル定義を見てみましょう:テーブルの
imageable_id列と
imageable_type列に特に注意してください。
imageable_id列には記事またはユーザーの ID 値が含まれ、
imageable_type列には親モデルのクラス名が含まれます。 Eloquent は、
imageableにアクセスするときに
imageable_type列を使用して、親モデルの「タイプ」を決定します。
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Image extends Model{ /** * 获取拥有此图片的模型。 */ public function imageable() { return $this->morphTo(); } } class Post extends Model{ /** * 获取文章图片。 */ public function image() { return $this->morphOne('App\Image', 'imageable'); } } class User extends Model{ /** * 获取用户图片。 */ public function image() { return $this->morphOne('App\Image', 'imageable'); } }
関連付けを取得する
テーブルとモデルを定義すると、モデルを通じてこの関連付けにアクセスできるようになります。たとえば、記事の画像を取得するには、
image
動的属性を使用できます:$post = App\Post::find(1); $image = $post->image;
また、
によって呼び出されるメソッド名にアクセスして、多態性モデルから親を取得することもできます。 morphTo
モデル。この場合、これはImage
モデルのimageable
メソッドです。したがって、動的プロパティのようにこのメソッドにアクセスできます。$image = App\Image::find(1); $imageable = $image->imageable;
#1 対多 (ポリモーフィック)テーブル構造1 対多の多態性関連付けは、単純な 1 対多の関連付けに似ていますが、ターゲット モデルは 1 つの関連付け内の複数のモデルに属することができます。アプリケーション内のユーザーが記事とビデオに同時に「コメント」できると仮定します。ポリモーフィックな関連付けを使用すると、これらの状況は単一のImage
モデルのimageable
関連付けは、Post
またはのいずれかを返します。ユーザー
インスタンス。結果は、画像属性がどのモデルであるかによって異なります。comments
テーブルで同時に満たすことができます。まず、この関連付けを構築するために使用されるテーブル構造を見てみましょう:
posts id - integer title - string body - text videos id - integer title - string url - string comments id - integer body - text commentable_id - integer commentable_type - string
モデル構造次に、この関連付けを構築するためのモデル定義を見てみましょう:<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model{ /** * 获取拥有此评论的模型。 */ public function commentable() { return $this->morphTo(); } } class Post extends Model{ /** * 获取此文章的所有评论。 */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } } class Video extends Model{ /** * 获取此视频的所有评论。 */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } }
関連付けの取得データベース テーブルとモデルが定義されると、モデルを介して関連付けにアクセスできるようになります。たとえば、comments
動的プロパティを使用して、記事のすべてのコメントにアクセスできます。
$post = App\Post::find(1);foreach ($post->comments as $comment) { // }
また、morphTo
モデルを呼び出します。この場合、
Commentモデルの
commentableメソッド:
$comment = App\Comment::find(1); $commentable = $comment->commentable;
Comment
多対多 (ポリモーフィック)モデルの
commentable関連は ## を返します。 #Post
またはVideo
インスタンスの場合、結果はコメントが属するモデルによって異なります。##テーブル構造
多対多の多態性関連付けは、morphOneおよび
morphMany関連付けよりもわずかに複雑です。たとえば、ブログ
Post
モデルとVideo
モデルは、Tag
モデルと多態性の関係を共有できます。多対多のポリモーフィックな関連付けを使用すると、一意のタグを使用してブログ投稿とビデオ間で共有できるようになります。以下は、多対多の多態性関連付けのテーブル構造です。posts id - integer name - string videos id - integer name - string tags id - integer name - string taggables tag_id - integer taggable_id - integer taggable_type - string
モデル構造
次に、モデル上で関連付けを定義します。Postモデルと
Videoモデルには両方とも、Eloquent 基本クラスの
演算子も指定し、Quantity でクエリをさらにカスタマイズします。morphToMany
メソッドを呼び出すtags
メソッドがあります:<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model{ /** * 获取文章的所有标签。 */ public function tags() { return $this->morphToMany('App\Tag', 'taggable'); } }
逆相関関係を定義する
次に、
Tag
モデル上の各相関モデルのメソッドを定義する必要があります。この例では、posts
メソッドとvideos
メソッドを定義します。<?php namespace App; use Illuminate\Database\Eloquent\Model; class Tag extends Model{ /** * 获取被打上此标签的所有文章。 */ public function posts() { return $this->morphedByMany('App\Post', 'taggable'); } /** * 获取被打上此标签的所有视频。 */ public function videos() { return $this->morphedByMany('App\Video', 'taggable'); } }
Get the association
Once定義済みのデータベース テーブルとモデルを作成したら、モデルを通じてリレーションシップにアクセスできます。たとえば、
tags
動的プロパティを使用して、記事のすべてのタグにアクセスできます。$post = App\Post::find(1);foreach ($post->tags as $tag) { // }
また、
morphedByMany
メソッド呼び出しを実行するメソッド名にアクセスすることもできます。多態性モデル Model から所有権を取得します。この例では、Tag
モデルのposts
またはvideos
メソッドです。これらのメソッドには、動的プロパティと同様にアクセスできます:$tag = App\Tag::find(1);foreach ($tag->videos as $video) { // }
Custom Polymorphic Type
デフォルトでは、Laravel ストアに関連付けられたモデル完全修飾クラス名を使用した型。上記の 1 対多の例では、
Comment
はPost
またはVideo
に属する可能性があるため、デフォルトのcommentable_type
は次のようになります。App\Post
またはApp\Video
です。ただし、データベースをアプリケーションの内部構造から切り離したい場合があります。この場合、「モーフ マッピング」を定義して、対応するクラス名の代わりにカスタム名を使用するように Eloquent に指示できます。use Illuminate\Database\Eloquent\Relations\Relation; Relation::morphMap([ 'posts' => 'App\Post', 'videos' => 'App\Video', ]);
AppServiceProvider
ので実行できます。 boot
関数にmorphMap
を登録するか、別のサービス プロバイダーを作成します。クエリ アソシエーション
Eloquent アソシエーションのすべてのタイプはメソッドによって定義されているため、代わりにこれらのメソッドを呼び出すことができます。関連するクエリを実際に実行する必要はありません。さらに、すべての Eloquent リレーション タイプはクエリ ビルダーとして機能するため、データベースで SQL を実行する前に一連の呼び出しを通じて制約を継続的に追加できます。
たとえば、ブログ システムの
User
モデルに関連するPost
モデルが多数あるとします。<?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model{ /** * 获取该用户的所有文章。 */ public function posts() { return $this->hasMany('App\Post'); } }
クエリを実行すると、
posts
関連付けを行い、それに制約を追加します。$user = App\User::find(1); $user->posts()->where('active', 1)->get();
関連付けに対して任意のクエリ ビルダー メソッドを使用できます。クエリ ビルダーのドキュメントを参照して、役立つメソッドを学習してください。
リレーション メソッドと動的プロパティ
Eloquent 相関クエリに追加の制約を追加する必要がない場合は、プロパティのようにリレーションシップにアクセスできます。たとえば、
User
およびPost
サンプル モデルを引き続き使用すると、次のようにユーザーのすべての投稿にアクセスできます。$user = App\User::find(1); foreach ($user->posts as $post) { // }
動的属性は「遅延読み込み」されます。これは、関連するデータに実際にアクセスした場合にのみロードされることを意味します。したがって、開発者は多くの場合、preloading を使用して、モデルのロード後にアクセスすることがわかっている関係をプリロードします。モデルの関連付けを読み込むときに実行する必要がある SQL クエリの場合、即時読み込みによりクエリの実行数が大幅に削減されます。
#既存の関係をクエリするモデル レコードにアクセスするとき、存在に基づいてクエリの結果を制限したい場合があります。関係の。たとえば、少なくとも 1 つのコメントを含むすべての記事を取得したい場合は、has
メソッドと
orHasメソッドに関連付け名を渡すことができます:
// 获取至少存在一条评论的所有文章... $posts = App\Post::has('comments')->get();
// 获取评论超过三条的文章... $posts = App\Post::has('comments', '>=', 3)->get();
「ドット」構文を使用して、ネストされたhas
ステートメントを構築することもできます。たとえば、少なくとも 1 つのコメントが含まれる記事を取得して投票できます。
// 获取拥有至少一条带有投票评论的文章... $posts = App\Post::has('comments.votes')->get();
さらに関数が必要な場合は、whereHas
メソッドと
orWhereHasメソッドを使用して、 「where」条件 Go to
hasクエリ。これらのメソッドを使用すると、コメントの内容をチェックするなど、関連付けにカスタム制約を追加できます。
use Illuminate\Database\Eloquent\Builder; // 获取至少带有一条评论内容包含 foo% 关键词的文章... $posts = App\Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%');})->get(); // 获取至少带有十条评论内容包含 foo% 关键词的文章... $posts = App\Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); }, '>=', 10)->get();
存在しない関連付けのクエリモデル レコードにアクセスするとき、関連付けが存在しないことに基づいてクエリ結果を制限したい場合があります。doesntHave と orDoesntHave
メソッド:にコメントがない記事を取得したいとします。これを行うには、関連名を
doesntHaveと
orDoesntHave に渡します。$posts = App\Post::doesntHave('comments')->get();
if さらに機能を高めるには、
whereDoesntHaveと
orWhereDoesntHave## を使用して、doesntHave
クエリに「where」条件を追加できます。 # 個のメソッド。これらのメソッドを使用すると、コメント コンテンツの検出など、関連付けにカスタム制限を追加できます。use Illuminate\Database\Eloquent\Builder; $posts = App\Post::whereDoesntHave('comments', function (Builder $query) { $query->where('content', 'like', 'foo%'); })->get();
「ドット」構文を使用して、ネストされた関連付けクエリを実行することもできます。たとえば、次のクエリは、禁止されていない著者からのコメントを含む記事を取得します:
use Illuminate\Database\Eloquent\Builder; $posts = App\Post::whereDoesntHave('comments.author', function (Builder $query) { $query->where('banned', 1); })->get();
関連モデル数
実際に結果をロードせずに、関連する結果の統計的な数のみを計算したい場合は、 ## に配置される
withCount
メソッドを使用できます。結果モデルの {relation}_count列の数。例は次のとおりです。
$posts = App\Post::withCount('comments')->get(); foreach ($posts as $post) { echo $post->comments_count; }
クエリに制限を追加するのと同じように、複数のリレーションシップに「カウント」を追加できます。$posts = App\Post::withCount(['votes', 'comments' => function ($query) { $query->where('content', 'like', 'foo%'); }])->get(); echo $posts[0]->votes_count;echo $posts[0]->comments_count;
リレーションシップ カウントの結果にエイリアスを付けることもでき、これにより、同じリレーションシップの「カウント」 複数のカウント:$posts = App\Post::withCount([ 'comments', 'comments as pending_comments_count' => function ($query) { $query->where('approved', false); }])->get(); echo $posts[0]->comments_count; echo $posts[0]->pending_comments_count;
withCount
クエリと
selectクエリを一緒に組み立てる場合は、## の後に
withCount を必ず呼び出してください。 #selectメソッド
:$query = App\Post::select(['title', 'body'])->withCount('comments'); echo $posts[0]->title; echo $posts[0]->body; echo $posts[0]->comments_count;
Preloading属性モードで Eloquent アソシエーションにアクセスする場合、関連するデータは「遅延」ロードです。この方法では、プロパティに初めてアクセスするまで、関連付けられたデータは実際には読み込まれません。ただし、Eloquent は、親モデルをクエリするときに、子関係を「プリロード」できます。積極的な読み込みにより、N 1 クエリの問題を軽減できます。 N 1 クエリの問題を説明するために、
Bookモデルが
Author
:
に関連付けられている状況を考えてみましょう。次に、すべての書籍とその著者を取得しましょう。<?php namespace App; use Illuminate\Database\Eloquent\Model; class Book extends Model{ /** * 获取书籍作者。 */ public function author() { return $this->belongsTo('App\Author'); } }
$books = App\Book::all(); foreach ($books as $book) { echo $book->author->name; }
このループは、すべての書籍を取得するクエリを実行し、次に書籍ごとに著者を取得するクエリを実行します。書籍が 25 冊ある場合、このループは 26 のクエリを実行します。1 つは書籍をクエリし、25 の追加クエリは各書籍の著者をクエリします。
ありがたいことに、熱心な読み込みを使用して操作をわずか 2 つのクエリに凝縮することができました。クエリ時に、
withメソッドを使用して、プリロードする関連付けを指定できます:
この例では、2 つのクエリのみが実行されました:$books = App\Book::with('author')->get(); foreach ($books as $book) { echo $book->author->name; }
select * from books select * from authors where id in (1, 2, 3, 4, 5, ...)
複数の関連付けのプリロード場合によっては、1 回の操作で複数の異なる関連付けをプリロードする必要がある場合があります。これを実現するには、複数の関連する名前で構成される配列パラメーターを
withメソッドに渡すだけです:
$books = App\Book::with(['author', 'publisher'])->get();
ネストされたプリロードを使用できます。 Dot」構文は、ネストされた関連付けをプリロードします。たとえば、Eloquent ステートメントですべての本の著者とその連絡先情報をプリロードします。
$books = App\Book::with('author.contacts')->get();
指定された列をプリロードするリレーションシップのすべての列を取得する必要があるとは限りません。 。この場合、Eloquent では、関連付けのために取得したい列を指定できます:
$users = App\Book::with('author:id,name')->get();
{note} この機能を使用するときは、取得する列のリストに ## を必ず含めてください。 . #id列。
プリロードの制約を追加する
次の例のように、リレーションシップをプリロードし、追加のクエリ条件をプリロード クエリに追加することが必要な場合があります。
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();
この例では、Eloquent は
title
列にfirst
キーワードが含まれる記事のみをプリロードします。他のクエリ ビルダー メソッドを呼び出して、プリロード操作をさらにカスタマイズすることもできます。$users = App\User::with(['posts' => function ($query) { $query->orderBy('created_at', 'desc'); }])->get();
{note} プリロードを制約する場合、
limit
およびtake# は使用できません ##クエリコンストラクターメソッド。
#プリロードモデルがロードされた後に、積極的なロードを実行したい場合もあります。たとえば、関連データを動的にロードしたい場合は、
loadメソッドが非常に役立ちます。
Closure
クエリを一気にロードしたい場合 条件付き制約の場合、配列の形式でロードできます。キーは対応する関連付けで、値は$books = App\Book::all(); if ($someCondition) { $books->load('author', 'publisher'); }
クロージャ関数です。クロージャのパラメータは
loadMissingquery
例:
関連付けが読み込まれていない場合は、$books->load(['author' => function ($query) { $query->orderBy('published_date', 'asc'); }]);
メソッドを使用できます:
public function format(Book $book){ $book->loadMissing('author'); return [ 'name' => $book->name, 'author' => $book->author->name ]; }
Nested LazyLoading&morphTo
morphTo関係と、その関係が返すさまざまなエンティティの入れ子になった関係をすばやくロードする場合は、
morphToloadMorph
メソッドを使用できます。このメソッドは、
リレーションシップの名前を最初のパラメーターとして受け取り、2 番目のパラメーターはモデル配列とリレーションシップ配列を受け取ります。このアプローチを説明するために、次のモデル例を見てください:
Event
この例では、<?php use Illuminate\Database\Eloquent\Model; class ActivityFeed extends Model{ /** * Get the parent of the activity feed record. */ public function parentable() { return $this->morphTo(); } }
、
モデル インスタンスを取得し、すべてのPhoto
、およびPost# を想定します。 # # モデルは
ActivityFeedモデルを作成できます。さらに、
Eventモデルが
Calendarモデルに属し、
Photoモデルが
Tagモデルに関連付けられていると仮定します。
Postモデルは
Authorモデルに属します。
これらのモデル定義と関係を使用すると、
ActivityFeedparentable
モデルとそれぞれのネストされた関係を一度に読み込むことができます:
$activities = ActivityFeed::with('parentable') ->get() ->loadMorph('parentable', [ Event::class => ['calendar'], Photo::class => ['tags'], Post::class => ['author'], ]);
関連モデルの挿入と更新新しいメソッド
save
{tip}と
saveManyに加えてメソッドのほかに、
createメソッドを使用することもできます。プロパティの配列を受け取り、モデルを作成してデータベースに挿入します。また、
saveメソッドと
createメソッドの違いは、
saveメソッドは完全な Eloquent モデル インスタンスを受け入れるのに対し、
create## メソッドは受け入れられることです。 # その後、通常の PHP 配列を受け入れます:$post = App\Post::find(1); $comment = $post->comments()->create([ 'message' => 'A new comment.', ]);
create
createManyメソッドを使用する前に、このドキュメントのバッチ割り当ての章を必ず確認してください。
メソッドを使用して、複数の関連モデルを作成することもできます。
findOrNew
また、$post = App\Post::find(1);$post->comments()->createMany([ [ 'message' => 'A new comment.', ], [ 'message' => 'Another new comment.', ], ]);
、
を使用することもできます。 firstOrNew
、firstOrCreate
、およびupdateOrCreate
メソッドを使用して、リレーショナル モデルを作成および更新します。##UpdatebelongsToAssociation
belongsTo関連付けを更新するときは、
belongsToassociate
メソッドを使用できます。このメソッドは、子モデルに外部キーを設定します。$account = App\Account::find(10); $user->account()->associate($account);$user->save();
関連付けを削除するときは、
に設定します。dissociate
メソッドを使用できます。このメソッドは、関連付けられた外部キーをnull
:$user->account()->dissociate();$user->save();
Default Model
belongsTo
リレーションシップを使用すると、デフォルト モデルを指定できます。指定されたリレーションシップがnull
の場合、デフォルト モデルが返されます。このモードは Null オブジェクト モード と呼ばれ、コード内の不要なチェックを減らすことができます。以下の例では、公開された投稿の作成者が見つからない場合、user
リレーションシップは空のApp\User
モデルを返します:/** * 获取帖子的作者。 */ public function user(){ return $this->belongsTo('App\User')->withDefault(); }
デフォルト モデル プロパティを追加するには、配列またはコールバック メソッドを
withDefault
に渡すことができます:/** * 获取帖子的作者。 */ public function user(){ return $this->belongsTo('App\User')->withDefault([ 'name' => 'Guest Author', ]); } /** * 获取帖子的作者。 */ public function user(){ return $this->belongsTo('App\User')->withDefault(function ($user) { $user->name = 'Guest Author'; }); }
#Many-to -多くの関連付け アタッチ/デタッチEloquent は、関連モデルの使用をより便利にするための追加の補助メソッドもいくつか提供します。たとえば、ユーザーが複数のロールを持つことができ、各ロールを複数のユーザーが共有できると仮定します。ユーザーにロールをアタッチするには、中間テーブルにレコードを挿入します。この操作は、attach
メソッドを使用して完了できます:
$user = App\User::find(1); $user->roles()->attach($roleId);
リレーションシップをモデルにアタッチするとき、次のことができます。中間テーブルに挿入される追加データのセットも渡します:$user->roles()->attach($roleId, ['expires' => $expires]);
もちろん、場合によってはユーザーのロールを削除することも必要です。detach
を使用すると、多対多の関連レコードを削除できます。
detachメソッドは中間テーブルに対応するレコードを削除しますが、これら 2 つのモデルはデータベースに残ります:
// 移除用户的一个角色... $user->roles()->detach($roleId); // 移除用户的所有角色... $user->roles()->detach();
便宜上、attach
と
detachでは、ID の配列を渡すこともできます。
$user = App\User::find(1); $user->roles()->detach([1, 2, 3]); $user->roles()->attach([ 1 => ['expires' => $expires], 2 => ['expires' => $expires] ]);
同期アソシエーションsync
メソッドを使用して、多数の ID を構築することもできます。 -対多の関連付け。
syncメソッドは ID の配列を受け取り、中間テーブルのレコードを置き換えます。中間テーブルのレコードのうち、ID 配列にないレコードはすべて削除されます。したがって、操作が完了した後は、指定された配列の ID のみが中間テーブルに保持されます:
$user->roles()->sync([1, 2, 3]);
また、ID によって追加の追加データを中間テーブルに渡すこともできます:$user->roles()->sync([1 => ['expires' => true], 2, 3]);
既存の ID を削除したくない場合は、syncWithoutDetaching
メソッドを使用できます:
$user->roles()->syncWithoutDetaching([1, 2, 3]);
Switch associationMany-対多の関連付けも提供されます。toggle
メソッドは、指定された ID 配列の接続状態を「切り替える」ために使用されます。指定された ID が既に中間テーブルに追加されている場合は、その ID が削除されます。同様に、指定された ID が削除されている場合は、追加されます:
$user->roles()->toggle([1, 2, 3]);
App\User::find(1)->roles()->save($role, ['expires' => $expires]);
中間テーブル レコードの更新
中間テーブル内の既存のレコードを更新する必要がある場合は、
updateExistingPivot
を使用できます。このメソッドは、中間テーブルの外部キーと、更新のために更新されるデータ配列を受け取ります:$user = App\User::find(1); $user->roles()->updateExistingPivot($roleId, $attributes);
親タイムスタンプの更新
モデルが
belongsTo
またはbelongsToMany
に別のモデルに属している場合、たとえばComment
がPost
に属している場合、サブが更新されることがあります。 -model の結果が更新される 親モデルのタイムスタンプは非常に便利です。たとえば、Comment
モデルが更新されたときに、親のPost
モデルのupdated_at
タイムスタンプの更新を自動的に「トリガー」したいとします。 Elequent ならそれが簡単になります。関連付けられた名前を含む子モデルにtouches
属性を追加するだけです:<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model{ /** * 要触发的所有关联关系 * * @var array */ protected $touches = ['post']; /** * 评论所属的文章 */ public function post() { return $this->belongsTo('App\Post'); } }
さて、
Comment
を更新すると、対応する親Post
モデルのupdated_at
フィールドも更新され、Post
モデルのキャッシュをいつ無効にするかを簡単に知ることができます:$comment = App\Comment::find(1); $comment->text = 'Edit to this comment!'; $comment->save();
この記事の初公開日LearnKu.com ウェブサイト。
- 中間テーブルを介してリレーションシップをフィルタリングします
- 関連付けの同期