نسخه:

الکوئنت: روابط

معرفی

جداول پایگاه داده اغلب با یکدیگر مرتبط هستند. به عنوان مثال، یک پست وبلاگ ممکن است نظرات زیادی داشته باشد، یا یک سفارش می تواند مربوط به کاربری باشد که آن را ارسال کرده است. Eloquent مدیریت و کار با این روابط را آسان می کند و از چندین نوع مختلف روابط پشتیبانی می کند:

تعریف روابط

روابط Eloquent به عنوان روش هایی در کلاس های مدل Eloquent شما تعریف می شوند. از آنجایی که، مانند خود مدل‌های Eloquent، روابط نیز به عنوان سازندگان پرس و جو قوی عمل می‌کنند ، تعریف روابط به‌عنوان متدها، قابلیت‌های زنجیره‌ای متد و قابلیت‌های جست‌وجو را فراهم می‌کند. به عنوان مثال، ما ممکن است محدودیت های اضافی را در این posts رابطه زنجیره ای کنیم:

$user->posts()->where('active', 1)->get();

اما، قبل از غوطه ور شدن بیش از حد در استفاده از روابط، بیایید یاد بگیریم که چگونه هر نوع را تعریف کنیم.

نام‌های روابط نمی‌توانند با نام‌های ویژگی‌ها برخورد کنند، زیرا ممکن است مدل شما نتواند بفهمد کدام یک را حل کند.

یک به یک

رابطه یک به یک یک رابطه بسیار اساسی است. برای مثال، یک User مدل ممکن است با یکی مرتبط باشد Phone . برای تعریف این رابطه، phone روشی را روی User مدل قرار می دهیم. متد 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 متد ارسال کنید:

return $this->hasOne('App\Phone', 'foreign_key');

علاوه بر این، Eloquent فرض می‌کند که کلید خارجی باید مقداری مطابق با ستون id (یا سفارشی $primaryKey ) والد داشته باشد. به عبارت دیگر، Eloquent مقدار ستون کاربر را id در user_id ستون رکورد جستجو می کند Phone . اگر می‌خواهید این رابطه از مقداری غیر از مقدار استفاده کند id ، می‌توانید آرگومان سومی را به hasOne متد ارسال کنید که کلید سفارشی شما را مشخص می‌کند:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

تعریف معکوس رابطه

بنابراین، می‌توانیم Phone از طریق ما به مدل دسترسی پیدا کنیم User . اکنون، بیایید یک رابطه در Phone مدلی تعریف کنیم که به ما امکان می دهد به User گوشی صاحب گوشی دسترسی پیدا کنیم. ما می توانیم معکوس یک hasOne رابطه را با استفاده از belongsTo روش تعریف کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Phone extends Model
{
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User');
}
}

در مثال بالا، Eloquent سعی خواهد کرد تا user_id از Phone مدل را به یک id در User مدل مطابقت دهد. Eloquent نام کلید خارجی پیش فرض را با بررسی نام روش رابطه و پسوند نام متد با _id . با این حال، اگر کلید خارجی مدل Phone نیست user_id ، می‌توانید یک نام کلید سفارشی را به عنوان آرگومان دوم به belongsTo متد ارسال کنید:

/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key');
}

اگر مدل والد شما به عنوان کلید اصلی خود استفاده نمی‌کند id ، یا می‌خواهید مدل فرزند را به ستون دیگری بپیوندید، می‌توانید آرگومان سومی را به متد ارسال کنید که belongsTo کلید سفارشی جدول والد شما را مشخص می‌کند:

/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}

یک به بسیاری

یک رابطه یک به چند برای تعریف روابطی استفاده می شود که در آن یک مدل واحد دارای هر مقدار مدل دیگر است. به عنوان مثال، یک پست وبلاگ ممکن است تعداد بی نهایت نظر داشته باشد. مانند سایر روابط Eloquent، روابط یک به چند با قرار دادن یک تابع در مدل Eloquent شما تعریف می شود:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany('App\Comment');
}
}

به یاد داشته باشید، Eloquent به طور خودکار ستون کلید خارجی مناسب را در Comment مدل تعیین می کند. طبق قرارداد، Eloquent نام "مورد مار" مدل مالک را می گیرد و پسوند آن را با _id . بنابراین، برای این مثال، Eloquent کلید خارجی مدل Comment را post_id .

زمانی که رابطه تعریف شد، می توانیم با دسترسی به comments ویژگی به مجموعه نظرات دسترسی داشته باشیم. به یاد داشته باشید، از آنجایی که Eloquent «ویژگی‌های پویا» را ارائه می‌کند، می‌توانیم به روش‌های رابطه طوری دسترسی داشته باشیم که گویی به عنوان ویژگی در مدل تعریف شده‌اند:

$comments = App\Post::find(1)->comments;
 
foreach ($comments as $comment) {
//
}

از آنجایی که همه روابط به عنوان سازنده پرس و جو نیز عمل می کنند، می توانید با فراخوانی متد 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');

یک به چند (معکوس)

اکنون که می‌توانیم به همه نظرات یک پست دسترسی پیدا کنیم، بیایید یک رابطه تعریف کنیم تا یک نظر به پست اصلی خود دسترسی پیدا کند. برای تعریف معکوس یک hasMany رابطه، یک تابع رابطه در مدل فرزند تعریف کنید که belongsTo متد را فراخوانی می کند:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}

هنگامی که رابطه تعریف شد، می‌توانیم Post مدل a را Comment با دسترسی به post "ویژگی پویا" بازیابی کنیم:

$comment = App\Comment::find(1);
 
echo $comment->post->title;

در مثال بالا، Eloquent سعی خواهد کرد تا post_id از Comment مدل را به یک id در Post مدل مطابقت دهد. Eloquent نام کلید خارجی پیش فرض را با بررسی نام روش رابطه و پسوند نام روش با _ نام ستون اصلی کلید تعیین می کند. با این حال، اگر کلید خارجی مدل Comment نیست post_id ، می‌توانید یک نام کلید سفارشی را به عنوان آرگومان دوم به belongsTo متد ارسال کنید:

/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post', 'foreign_key');
}

اگر مدل والد شما به عنوان کلید اصلی خود استفاده نمی‌کند id ، یا می‌خواهید مدل فرزند را به ستون دیگری بپیوندید، می‌توانید آرگومان سومی را به متد ارسال کنید که belongsTo کلید سفارشی جدول والد شما را مشخص می‌کند:

/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}

بسیاری به بسیاری

روابط چند به چند اندکی پیچیده تر از hasOne روابط هستند hasMany . نمونه ای از چنین رابطه ای کاربری با نقش های زیاد است که در آن نقش ها توسط سایر کاربران نیز به اشتراک گذاشته می شود. به عنوان مثال، بسیاری از کاربران ممکن است نقش "Admin" را داشته باشند.

ساختار جدول

برای تعریف این رابطه، به سه جدول پایگاه داده نیاز است: users , roles و role_user . جدول role_user از ترتیب حروف الفبای نام مدل های مرتبط مشتق شده است و شامل ستون های user_id و است role_id :

users
id - integer
name - string
 
roles
id - integer
name - string
 
role_user
user_id - integer
role_id - integer

ساختار مدل

روابط چند به چند با نوشتن متدی تعریف می شوند که نتیجه متد را برمی گرداند belongsToMany . به عنوان مثال، بیایید roles روش را در User مدل خود تعریف کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
/**
* The roles that belong to the user.
*/
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 دو نام مدل مرتبط را به ترتیب حروف الفبا به هم می پیوندد. با این حال، شما آزادید که این قرارداد را لغو کنید. می توانید این کار را با ارسال آرگومان دوم به belongsToMany متد انجام دهید:

return $this->belongsToMany('App\Role', 'role_user');

علاوه بر سفارشی کردن نام جدول اتصال، می‌توانید نام ستون‌های کلیدهای روی جدول را با ارسال آرگومان‌های اضافی به متد سفارشی کنید belongsToMany . آرگومان سوم، نام کلید خارجی مدلی است که بر اساس آن رابطه را تعریف می کنید، در حالی که آرگومان چهارم، نام کلید خارجی مدلی است که به آن ملحق می شوید:

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

تعریف معکوس رابطه

برای تعریف معکوس یک رابطه چند به چند، یک تماس دیگر با belongsToMany مدل مرتبط خود برقرار می کنید. برای ادامه مثال نقش کاربر، اجازه دهید users روش را روی Role مدل تعریف کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Role extends Model
{
/**
* The users that belong to the role.
*/
public function users()
{
return $this->belongsToMany('App\User');
}
}

همانطور که می بینید، رابطه دقیقاً مانند User همتای خود تعریف می شود، به استثنای ارجاع به App\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 شی وجود خواهند داشت. اگر جدول محوری شما دارای ویژگی های اضافی است، باید آنها را هنگام تعریف رابطه مشخص کنید:

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

اگر می‌خواهید جدول محوری شما به‌طور خودکار دارای مهر created_at و updated_at زمان باشد، withTimestamps از روش تعریف رابطه استفاده کنید:

return $this->belongsToMany('App\Role')->withTimestamps();

سفارشی کردن pivot نام ویژگی

همانطور که قبلا ذکر شد، ویژگی های جدول میانی ممکن است در مدل ها با استفاده از pivot ویژگی قابل دسترسی باشند. با این حال، شما آزاد هستید که نام این ویژگی را سفارشی کنید تا هدف آن را در برنامه شما بهتر نشان دهد.

به عنوان مثال، اگر برنامه شما شامل کاربرانی است که ممکن است در پادکست ها مشترک شوند، احتمالاً بین کاربران و پادکست ها رابطه چند به چند دارید. اگر اینطور است، ممکن است بخواهید به subscription جای استفاده از جدول میانی خود، نام آن را به تغییر دهید pivot . این را می توان با استفاده از 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;
}

فیلتر کردن روابط از طریق ستون های جدول میانی

همچنین می‌توانید نتایج بازگشتی را با belongsToMany استفاده از روش‌های wherePivot ، wherePivotIn و wherePivotNotIn هنگام تعریف رابطه فیلتر کنید:

return $this->belongsToMany('App\Role')->wherePivot('approved', 1);
 
return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]);
 
return $this->belongsToMany('App\Role')->wherePivotNotIn('priority', [1, 2]);

تعریف مدل های جدول میانی سفارشی

اگر می خواهید یک مدل سفارشی برای نشان دادن جدول میانی رابطه خود تعریف کنید، می توانید using هنگام تعریف رابطه، متد را فراخوانی کنید. مدل های محوری چند به چند سفارشی باید Illuminate\Database\Eloquent\Relations\Pivot کلاس را گسترش دهند در حالی که مدل های محوری چند شکلی سفارشی باید Illuminate\Database\Eloquent\Relations\MorphPivot کلاس را گسترش دهند. به عنوان مثال، ممکن است مدلی را تعریف کنیم Role که از یک مدل محوری سفارشی استفاده می کند RoleUser :

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Role extends Model
{
/**
* The users that belong to the role.
*/
public function users()
{
return $this->belongsToMany('App\User')->using('App\RoleUser');
}
}

هنگام تعریف RoleUser مدل، کلاس را گسترش می دهیم Pivot :

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Relations\Pivot;
 
class RoleUser extends Pivot
{
//
}

می توانید using و withPivot به منظور بازیابی ستون ها از جدول میانی را ترکیب کنید. برای مثال، می‌توانید ستون‌های created_by و updated_by را از RoleUser جدول محوری با ارسال نام ستون‌ها به withPivot متد بازیابی کنید:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Role extends Model
{
/**
* The users that belong to the role.
*/
public function users()
{
return $this->belongsToMany('App\User')
->using('App\RoleUser')
->withPivot([
'created_by',
'updated_by',
]);
}
}

توجه: مدل‌های Pivot ممکن است از این ویژگی استفاده نکنند SoftDeletes . اگر نیاز به حذف نرم رکوردهای محوری دارید، مدل محوری خود را به یک مدل واقعی Eloquent تبدیل کنید.

مدل‌های محوری سفارشی و شناسه‌های افزایشی

اگر یک رابطه چند به چند تعریف کرده اید که از یک مدل محوری سفارشی استفاده می کند، و آن مدل محوری دارای یک کلید اولیه افزایش خودکار است، باید مطمئن شوید که کلاس مدل pivot سفارشی شما یک incrementing ویژگی را تعریف می کند که روی true .

/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = true;

دارای یکی از طریق

رابطه "دارای یک از طریق" مدل ها را از طریق یک رابطه میانی منفرد پیوند می دهد.

به عنوان مثال، در یک برنامه تعمیرگاه خودرو، هر کدام Mechanic ممکن است یکی داشته باشند Car و هر کدام Car ممکن است یکی داشته باشند Owner . در حالی که و Mechanic و Owner هیچ ارتباط مستقیمی ندارند، می توانند از طریق خود Mechanic به آن دسترسی داشته باشند . بیایید به جداول لازم برای تعریف این رابطه نگاه کنیم: Owner Car

mechanics
id - integer
name - string
 
cars
id - integer
model - string
mechanic_id - integer
 
owners
id - integer
name - string
car_id - integer

اکنون که ساختار جدول را برای رابطه بررسی کردیم، بیایید رابطه را بر روی Mechanic مدل تعریف کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Mechanic extends Model
{
/**
* Get the car's owner.
*/
public function carOwner()
{
return $this->hasOneThrough('App\Owner', 'App\Car');
}
}

اولین آرگومان ارسال شده به hasOneThrough متد، نام مدل نهایی است که می خواهیم به آن دسترسی داشته باشیم، در حالی که آرگومان دوم، نام مدل میانی است.

قراردادهای کلید خارجی Eloquent معمولی هنگام انجام پرس و جوهای رابطه استفاده می شود. اگر می خواهید کلیدهای رابطه را سفارشی کنید، می توانید آنها را به عنوان آرگومان های سوم و چهارم به hasOneThrough متد ارسال کنید. آرگومان سوم نام کلید خارجی در مدل میانی است. آرگومان چهارم نام کلید خارجی در مدل نهایی است. آرگومان پنجم کلید محلی است، در حالی که آرگومان ششم کلید محلی مدل میانی است:

class Mechanic extends Model
{
/**
* Get the car's owner.
*/
public function carOwner()
{
return $this->hasOneThrough(
'App\Owner',
'App\Car',
'mechanic_id', // Foreign key on cars table...
'car_id', // Foreign key on owners table...
'id', // Local key on mechanics table...
'id' // Local key on cars table...
);
}
}

دارای بسیاری از طریق

رابطه "has-hany-through" میانبر مناسبی برای دسترسی به روابط دور از طریق یک رابطه میانی فراهم می کند. به عنوان مثال، یک Country مدل ممکن است Post مدل های زیادی را از طریق یک مدل میانی داشته باشد User . در این مثال، می توانید به راحتی تمام پست های وبلاگ را برای یک کشور خاص جمع آوری کنید. بیایید به جداول مورد نیاز برای تعریف این رابطه نگاه کنیم:

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 جدول country_id میانی را بررسی می کند users . پس از یافتن شناسه های کاربر منطبق، از آنها برای جستجو در posts جدول استفاده می شود.

اکنون که ساختار جدول را برای رابطه بررسی کردیم، اجازه دهید آن را بر روی Country مدل تعریف کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Country extends Model
{
/**
* Get all of the posts for the country.
*/
public function posts()
{
return $this->hasManyThrough('App\Post', 'App\User');
}
}

اولین آرگومان ارسال شده به hasManyThrough متد، نام مدل نهایی است که می خواهیم به آن دسترسی داشته باشیم، در حالی که آرگومان دوم، نام مدل میانی است.

قراردادهای کلید خارجی Eloquent معمولی هنگام انجام پرس و جوهای رابطه استفاده می شود. اگر می خواهید کلیدهای رابطه را سفارشی کنید، می توانید آنها را به عنوان آرگومان های سوم و چهارم به hasManyThrough متد ارسال کنید. آرگومان سوم نام کلید خارجی در مدل میانی است. آرگومان چهارم نام کلید خارجی در مدل نهایی است. آرگومان پنجم کلید محلی است، در حالی که آرگومان ششم کلید محلی مدل میانی است:

class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}

روابط چند شکلی

یک رابطه چند شکلی به مدل هدف اجازه می دهد تا با استفاده از یک انجمن واحد به بیش از یک نوع مدل تعلق داشته باشد.

یک به یک (چند شکلی)

ساختار جدول

یک رابطه چند شکلی یک به یک شبیه یک رابطه ساده یک به یک است. با این حال، مدل هدف می تواند به بیش از یک نوع مدل در یک انجمن واحد تعلق داشته باشد. برای مثال، یک وبلاگ Post و a User ممکن است یک رابطه چند شکلی با یک Image مدل به اشتراک بگذارند. استفاده از یک رابطه چند شکلی یک به یک به شما امکان می دهد یک لیست واحد از تصاویر منحصر به فرد داشته باشید که هم برای پست های وبلاگ و هم برای حساب های کاربری استفاده می شود. ابتدا ساختار جدول را بررسی می کنیم:

posts
id - integer
name - string
 
users
id - integer
name - string
 
images
id - integer
url - string
imageable_id - integer
imageable_type - string

imageable_id به ستون ها و imageable_type روی جدول توجه کنید images . ستون imageable_id حاوی مقدار شناسه پست یا کاربر است، در حالی که imageable_type ستون حاوی نام کلاس مدل والد است. ستون imageable_type توسط Eloquent استفاده می‌شود تا تعیین کند که کدام «نوع» مدل والد را هنگام دسترسی به رابطه بازگرداند imageable .

ساختار مدل

سپس، اجازه دهید تعاریف مدل مورد نیاز برای ایجاد این رابطه را بررسی کنیم:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Image extends Model
{
/**
* Get the owning imageable model.
*/
public function imageable()
{
return $this->morphTo();
}
}
 
class Post extends Model
{
/**
* Get the post's image.
*/
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
 
class User extends Model
{
/**
* Get the user's image.
*/
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}

بازیابی رابطه

هنگامی که جدول پایگاه داده و مدل های شما تعریف شد، می توانید از طریق مدل های خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای بازیابی تصویر برای یک پست، می توانیم از image ویژگی پویا استفاده کنیم:

$post = App\Post::find(1);
 
$image = $post->image;

همچنین می توانید با دسترسی به نام روشی که فراخوانی را انجام می دهد، والد را از مدل چند شکلی بازیابی کنید morphTo . در مورد ما، این imageable روش روی Image مدل است. بنابراین، ما به آن متد به عنوان یک ویژگی پویا دسترسی خواهیم داشت:

$image = App\Image::find(1);
 
$imageable = $image->imageable;

بسته به نوع مدلی که تصویر را در اختیار دارد، رابطه imageable روی مدل یک یا نمونه Image برمی‌گرداند . اگر نیاز به تعیین سفارشی و ستون‌ها برای رابطه دارید، همیشه مطمئن شوید که نام رابطه (که باید دقیقاً با نام متد مطابقت داشته باشد) را به عنوان اولین پارامتر وارد کنید: Post User type id morphTo

/**
* Get the model that the image belongs to.
*/
public function imageable()
{
return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
}

یک به چند (چند شکلی)

ساختار جدول

یک رابطه چند شکلی یک به چند شبیه به یک رابطه ساده یک به چند است. با این حال، مدل هدف می تواند به بیش از یک نوع مدل در یک انجمن واحد تعلق داشته باشد. به عنوان مثال، تصور کنید کاربران برنامه شما می‌توانند هم روی پست‌ها و هم روی ویدیوها «نظر بدهند». با استفاده از روابط چند شکلی، می توانید از یک 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
{
/**
* Get the owning commentable model.
*/
public function commentable()
{
return $this->morphTo();
}
}
 
class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
 
class Video extends Model
{
/**
* Get all of the video's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}

بازیابی رابطه

هنگامی که جدول پایگاه داده و مدل های شما تعریف شد، می توانید از طریق مدل های خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای دسترسی به تمام نظرات یک پست، می توانیم از comments ویژگی پویا استفاده کنیم:

$post = App\Post::find(1);
 
foreach ($post->comments as $comment) {
//
}

همچنین می توانید با دسترسی به نام روشی که فراخوانی را انجام می دهد، مالک یک رابطه چند شکلی را از مدل چند شکلی بازیابی کنید morphTo . در مورد ما، این commentable روش روی Comment مدل است. بنابراین، ما به آن متد به عنوان یک ویژگی پویا دسترسی خواهیم داشت:

$comment = App\Comment::find(1);
 
$commentable = $comment->commentable;

بسته به نوع مدلی که صاحب نظر است، رابطه commentable روی مدل یک یا نمونه Comment برمی‌گرداند . 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 هر دو متدی خواهند داشت tags که morphToMany متد را در کلاس پایه Eloquent فراخوانی می‌کند:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable');
}
}

تعریف معکوس رابطه

در مرحله بعد، روی Tag مدل، باید برای هر یک از مدل های مرتبط با آن، یک متد تعریف کنید. posts بنابراین، برای این مثال، یک متد و یک متد را تعریف می کنیم videos :

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany('App\Post', 'taggable');
}
 
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany('App\Video', 'taggable');
}
}

بازیابی رابطه

هنگامی که جدول پایگاه داده و مدل های شما تعریف شد، می توانید از طریق مدل های خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای دسترسی به تمام برچسب های یک پست، می توانید از tags ویژگی پویا استفاده کنید:

$post = App\Post::find(1);
 
foreach ($post->tags as $tag) {
//
}

همچنین می توانید با دسترسی به نام روشی که فراخوانی را انجام می دهد، مالک یک رابطه چند شکلی را از مدل چند شکلی بازیابی کنید morphedByMany . در مورد ما، این روش posts یا videos روش های موجود در Tag مدل است. بنابراین، شما به آن متدها به عنوان خواص پویا دسترسی خواهید داشت:

$tag = App\Tag::find(1);
 
foreach ($tag->videos as $video) {
//
}

انواع چند شکلی سفارشی

به طور پیش فرض، لاراول از نام کلاس کاملاً واجد شرایط برای ذخیره نوع مدل مرتبط استفاده می کند. به عنوان مثال، با توجه به مثال یک به چند بالا که در آن a Comment ممکن است متعلق به a Post یا a باشد Video ، پیش فرض به ترتیب یا یا یا commentable_type خواهد بود . با این حال، ممکن است بخواهید پایگاه داده خود را از ساختار داخلی برنامه خود جدا کنید. در این صورت، می‌توانید یک «نقشه مورف» تعریف کنید تا به Eloquent دستور دهید که از یک نام سفارشی برای هر مدل به جای نام کلاس استفاده کند: App\Post App\Video

use Illuminate\Database\Eloquent\Relations\Relation;
 
Relation::morphMap([
'posts' => 'App\Post',
'videos' => 'App\Video',
]);

در صورت تمایل می توانید آن را morphMap در boot عملکرد خود ثبت کنید یا یک ارائه دهنده خدمات جداگانه ایجاد کنید. AppServiceProvider

هنگام افزودن یک "نقشه مورف" به برنامه موجود خود، هر *_type مقدار ستون قابل تغییر در پایگاه داده شما که هنوز دارای یک کلاس کاملاً واجد شرایط است باید به نام "نقشه" آن تبدیل شود.

شما می توانید نام مستعار مورف یک مدل معین را در زمان اجرا با استفاده از getMorphClass روش تعیین کنید. برعکس، می‌توانید نام کلاس کاملاً واجد شرایط مرتبط با نام مستعار مورف را با استفاده از Relation::getMorphedModel روش تعیین کنید:

use Illuminate\Database\Eloquent\Relations\Relation;
 
$alias = $post->getMorphClass();
 
$class = Relation::getMorphedModel($alias);

روابط پویا

می توانید از این resolveRelationUsing روش برای تعریف روابط بین مدل های Eloquent در زمان اجرا استفاده کنید. در حالی که معمولاً برای توسعه برنامه های کاربردی معمولی توصیه نمی شود، ممکن است گاهی اوقات هنگام توسعه بسته های لاراول مفید باشد:

use App\Order;
use App\Customer;
 
Order::resolveRelationUsing('customer', function ($orderModel) {
return $orderModel->belongsTo(Customer::class, 'customer_id');
});

هنگام تعریف روابط پویا، همیشه آرگومان های نام کلیدی صریح را برای روش های رابطه Eloquent ارائه دهید.

روابط پرس و جو

از آنجایی که همه انواع روابط Eloquent از طریق متدها تعریف می شوند، می توانید آن متدها را برای به دست آوردن نمونه ای از رابطه بدون اجرای واقعی پرس و جوهای رابطه فراخوانی کنید. علاوه بر این، همه انواع روابط Eloquent نیز به عنوان سازندگان پرس و جو عمل می کنند ، و به شما این امکان را می دهند تا قبل از اجرای نهایی SQL در برابر پایگاه داده خود، به زنجیره محدودیت ها در پرس و جوی رابطه ادامه دهید.

به عنوان مثال، سیستم وبلاگی را تصور کنید که در آن یک User مدل دارای Post مدل های مرتبط زیادی است:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class User extends Model
{
/**
* Get all of the posts for the user.
*/
public function posts()
{
return $this->hasMany('App\Post');
}
}

شما می توانید posts رابطه را پرس و جو کنید و محدودیت های اضافی را به این رابطه اضافه کنید:

$user = App\User::find(1);
 
$user->posts()->where('active', 1)->get();

شما می‌توانید از هر یک از روش‌های سازنده پرس و جو در رابطه استفاده کنید، بنابراین حتماً مستندات سازنده پرس و جو را بررسی کنید تا در مورد همه روش‌هایی که در دسترس شما هستند اطلاعات کسب کنید.

بندهای زنجیره ای orWhere بعد از روابط

همانطور که در مثال بالا نشان داده شد، شما می توانید در هنگام پرس و جوی روابط، محدودیت های اضافی را به آنها اضافه کنید. با این حال، هنگام زنجیر کردن orWhere جملات به یک رابطه احتیاط کنید، زیرا orWhere بندها به طور منطقی در همان سطح محدودیت رابطه گروه بندی می شوند:

$user->posts()
->where('active', 1)
->orWhere('votes', '>=', 100)
->get();
 
// select * from posts
// where user_id = ? and active = 1 or votes >= 100

در بیشتر موقعیت‌ها، احتمالاً قصد دارید از گروه‌های محدودیت برای گروه‌بندی منطقی بررسی‌های شرطی بین پرانتز استفاده کنید:

use Illuminate\Database\Eloquent\Builder;
 
$user->posts()
->where(function (Builder $query) {
return $query->where('active', 1)
->orWhere('votes', '>=', 100);
})
->get();
 
// select * from posts
// where user_id = ? and (active = 1 or votes >= 100)

روش های رابطه در مقابل. ویژگی های دینامیک

اگر نیازی به اضافه کردن محدودیت‌های اضافی به پرس و جوی رابطه Eloquent ندارید، می‌توانید به این رابطه مانند یک ویژگی دسترسی داشته باشید. برای مثال، با ادامه استفاده از مدل‌های ما User و Post نمونه، ممکن است به همه پست‌های کاربر مانند این دسترسی داشته باشیم:

$user = App\User::find(1);
 
foreach ($user->posts as $post) {
//
}

ویژگی های پویا "بارگذاری تنبل" هستند، به این معنی که آنها فقط زمانی که شما واقعا به آنها دسترسی داشته باشید، داده های رابطه خود را بارگیری می کنند. به همین دلیل، توسعه دهندگان اغلب از بارگذاری مشتاق برای پیش بارگذاری روابطی استفاده می کنند که می دانند پس از بارگذاری مدل به آن دسترسی خواهند داشت. بارگذاری مشتاق کاهش قابل توجهی در پرس و جوهای SQL را فراهم می کند که باید برای بارگذاری روابط یک مدل اجرا شوند.

پرس و جو از وجود رابطه

هنگام دسترسی به رکوردهای یک مدل، ممکن است بخواهید نتایج خود را بر اساس وجود یک رابطه محدود کنید. به عنوان مثال، تصور کنید می خواهید تمام پست های وبلاگی را که حداقل یک نظر دارند، بازیابی کنید. برای انجام این کار، می توانید نام رابطه را به has و orHas متدها ارسال کنید:

// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();

همچنین می‌توانید یک اپراتور را مشخص کنید و برای سفارشی‌سازی بیشتر پرس و جو تعداد آن‌ها را مشخص کنید:

// Retrieve all posts that have three or more comments...
$posts = App\Post::has('comments', '>=', 3)->get();

عبارات تودرتو has نیز ممکن است با استفاده از نماد "نقطه" ساخته شوند. به عنوان مثال، می توانید تمام پست هایی که حداقل یک نظر دارند را بازیابی کنید و رای دهید:

// Retrieve posts that have at least one comment with votes...
$posts = App\Post::has('comments.votes')->get();

اگر حتی به قدرت بیشتری نیاز دارید، می توانید از روش whereHas و orWhereHas برای قرار دادن شرایط "where" در has جستجوهای خود استفاده کنید. این روش‌ها به شما اجازه می‌دهند تا محدودیت‌های سفارشی‌شده را به یک محدودیت رابطه اضافه کنید، مانند بررسی محتوای یک نظر:

use Illuminate\Database\Eloquent\Builder;
 
// Retrieve posts with at least one comment containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
})->get();
 
// Retrieve posts with at least ten comments containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'foo%');
}, '>=', 10)->get();

پرس و جو عدم وجود رابطه

هنگام دسترسی به رکوردهای یک مدل، ممکن است بخواهید نتایج خود را بر اساس عدم وجود رابطه محدود کنید. به عنوان مثال، تصور کنید می خواهید تمام پست های وبلاگی را که هیچ نظری ندارند، بازیابی کنید. برای انجام این کار، می توانید نام رابطه را به doesntHave و orDoesntHave متدها ارسال کنید:

$posts = App\Post::doesntHave('comments')->get();

اگر حتی به قدرت بیشتری نیاز دارید، می توانید از روش whereDoesntHave و orWhereDoesntHave برای قرار دادن شرایط "where" در doesntHave جستجوهای خود استفاده کنید. این روش‌ها به شما اجازه می‌دهند تا محدودیت‌های سفارشی‌شده را به یک محدودیت رابطه اضافه کنید، مانند بررسی محتوای یک نظر:

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', 0);
})->get();

پرس و جو از روابط چند شکلی

برای پرس و جو در مورد وجود MorphTo روابط، می توانید از whereHasMorph روش و روش های مربوط به آن استفاده کنید:

use Illuminate\Database\Eloquent\Builder;
 
// Retrieve comments associated to posts or videos with a title like foo%...
$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query) {
$query->where('title', 'like', 'foo%');
}
)->get();
 
// Retrieve comments associated to posts with a title not like foo%...
$comments = App\Comment::whereDoesntHaveMorph(
'commentable',
'App\Post',
function (Builder $query) {
$query->where('title', 'like', 'foo%');
}
)->get();

$type بسته به مدل مربوطه می‌توانید از این پارامتر برای اضافه کردن محدودیت‌های مختلف استفاده کنید :

use Illuminate\Database\Eloquent\Builder;
 
$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query, $type) {
$query->where('title', 'like', 'foo%');
 
if ($type === 'App\Post') {
$query->orWhere('content', 'like', 'foo%');
}
}
)->get();

به جای ارسال آرایه‌ای از مدل‌های چندشکل ممکن، می‌توانید * به‌عنوان یک علامت عام ارائه کنید و به لاراول اجازه دهید همه انواع چندشکلی ممکن را از پایگاه داده بازیابی کند. لاراول یک کوئری اضافی را برای انجام این عملیات اجرا می کند:

use Illuminate\Database\Eloquent\Builder;
 
$comments = App\Comment::whereHasMorph('commentable', '*', function (Builder $query) {
$query->where('title', 'like', 'foo%');
})->get();

اگر می‌خواهید تعداد نتایج یک رابطه را بدون بارگیری واقعی آنها بشمارید، می‌توانید از روشی استفاده کنید که یک ستون بر روی مدل‌های به دست آمده شما withCount قرار می‌دهد . {relation}_count مثلا:

$posts = App\Post::withCount('comments')->get();
 
foreach ($posts as $post) {
echo $post->comments_count;
}

می‌توانید «شمارش» را برای چندین رابطه اضافه کنید و همچنین محدودیت‌هایی را به کوئری‌ها اضافه کنید:

use Illuminate\Database\Eloquent\Builder;
 
$posts = App\Post::withCount(['votes', 'comments' => function (Builder $query) {
$query->where('content', 'like', 'foo%');
}])->get();
 
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;

همچنین می‌توانید با نام مستعار نتیجه شمارش رابطه، شمارش‌های متعدد در یک رابطه را مجاز کنید:

use Illuminate\Database\Eloquent\Builder;
 
$posts = App\Post::withCount([
'comments',
'comments as pending_comments_count' => function (Builder $query) {
$query->where('approved', false);
},
])->get();
 
echo $posts[0]->comments_count;
 
echo $posts[0]->pending_comments_count;

withCount اگر با یک دستور ترکیب می‌کنید ، مطمئن شوید که بعد از متد select فراخوانی می‌کنید : withCount select

$posts = App\Post::select(['title', 'body'])->withCount('comments')->get();
 
echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;

علاوه بر این، با استفاده از این loadCount روش، می‌توانید تعداد رابطه را پس از بازیابی مدل والد بارگیری کنید:

$book = App\Book::first();
 
$book->loadCount('genres');

اگر نیاز به تعیین محدودیت‌های پرس و جو اضافی در پرس‌وجوی بارگیری مشتاق دارید، می‌توانید آرایه‌ای را ارسال کنید که توسط روابطی که می‌خواهید بارگیری کنید کلید خورده است. مقادیر آرایه باید Closure نمونه هایی باشند که نمونه سازنده query را دریافت می کنند:

$book->loadCount(['reviews' => function ($query) {
$query->where('rating', 5);
}])

اگر می‌خواهید مشتاقانه یک morphTo رابطه را بارگذاری کنید، و همچنین تعداد روابط تودرتو روی موجودیت‌های مختلفی که ممکن است توسط آن رابطه برگردانده شود، حساب می‌شود، می‌توانید از این with روش در ترکیب با روش morphTo رابطه استفاده کنید morphWithCount .

در این مثال، بیایید فرض کنیم Photo که Post مدل‌ها ممکن است ActivityFeed مدل‌هایی ایجاد کنند. علاوه بر این، فرض کنیم که Photo مدل‌ها با Tag مدل‌ها و Post مدل‌ها با Comment مدل‌ها مرتبط هستند.

ActivityFeed با استفاده از این تعاریف و روابط مدل، ممکن است نمونه‌های مدل را بازیابی کنیم و مشتاقانه همه parentable مدل‌ها و تعداد روابط تودرتو مربوطه را بارگیری کنیم:

use Illuminate\Database\Eloquent\Relations\MorphTo;
 
$activities = ActivityFeed::query()
->with(['parentable' => function (MorphTo $morphTo) {
$morphTo->morphWithCount([
Photo::class => ['tags'],
Post::class => ['comments'],
]);
}])->get();

علاوه بر این، اگر مدل‌ها قبلاً بازیابی شده باشند، می‌توانید از این loadMorphCount روش برای بارگذاری مشتاقانه همه تعداد روابط تودرتو در موجودیت‌های مختلف رابطه چندشکلی استفاده کنید: ActivityFeed

$activities = ActivityFeed::with('parentable')
->get()
->loadMorphCount('parentable', [
Photo::class => ['tags'],
Post::class => ['comments'],
]);

مشتاق بارگیری

هنگام دسترسی به روابط Eloquent به عنوان ویژگی، داده های رابطه "بارگذاری تنبل" هستند. این بدان معنی است که تا زمانی که شما برای اولین بار به ویژگی دسترسی نداشته باشید، داده های رابطه در واقع بارگذاری نمی شوند. با این حال، Eloquent می‌تواند روابط را در زمانی که مدل والد را پرس و جو می‌کنید، «بارگیری کند». بارگیری مشتاق مشکل پرس و جو N + 1 را کاهش می دهد. برای نشان دادن مشکل پرس و جو N + 1، Book مدلی را در نظر بگیرید که مربوط به Author :

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Book extends Model
{
/**
* Get the author that wrote the book.
*/
public function author()
{
return $this->belongsTo('App\Author');
}
}

اکنون بیایید همه کتاب ها و نویسندگان آنها را بازیابی کنیم:

$books = App\Book::all();
 
foreach ($books as $book) {
echo $book->author->name;
}

این حلقه 1 پرس و جو را برای بازیابی همه کتاب های روی میز اجرا می کند، سپس یک پرس و جو برای هر کتاب برای بازیابی نویسنده انجام می دهد. بنابراین، اگر 25 کتاب داشته باشیم، این حلقه 26 پرس و جو را اجرا می کند: 1 برای کتاب اصلی، و 25 پرس و جو اضافی برای بازیابی نویسنده هر کتاب.

خوشبختانه، ما می توانیم از بارگذاری مشتاق برای کاهش این عملیات به تنها 2 پرس و جو استفاده کنیم. هنگام پرس و جو، می توانید مشخص کنید که کدام روابط باید با استفاده از روش بارگذاری شوند with :

$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, ...)

مشتاق بارگیری روابط چندگانه

گاهی اوقات ممکن است نیاز داشته باشید که مشتاقانه چندین رابطه مختلف را در یک عملیات بارگیری کنید. برای انجام این کار، فقط آرگومان های اضافی را به with متد ارسال کنید:

$books = App\Book::with(['author', 'publisher'])->get();

Nested Eager Loading

برای بارگیری مشتاقانه روابط تودرتو، می توانید از نحو "نقطه" استفاده کنید. برای مثال، بیایید مشتاقانه همه نویسندگان کتاب و همه تماس های شخصی نویسنده را در یک بیانیه Eloquent بارگذاری کنیم:

$books = App\Book::with('author.contacts')->get();

morphTo روابط بارگیری مشتاق تو در تو

اگر می‌خواهید مشتاقانه یک morphTo رابطه و همچنین روابط تودرتو در موجودیت‌های مختلفی را که ممکن است توسط آن رابطه برگردانده شوند بارگذاری کنید، می‌توانید از این with روش در ترکیب با روش morphTo رابطه استفاده کنید morphWith . برای کمک به توضیح این روش، بیایید مدل زیر را در نظر بگیریم:

<?php
 
use Illuminate\Database\Eloquent\Model;
 
class ActivityFeed extends Model
{
/**
* Get the parent of the activity feed record.
*/
public function parentable()
{
return $this->morphTo();
}
}

در این مثال، فرض کنید Event ، Photo و Post مدل ها ممکن است ActivityFeed مدل هایی ایجاد کنند. علاوه بر این، فرض کنیم که Event مدل‌ها متعلق به یک Calendar مدل هستند، Photo مدل‌ها با مدل‌ها مرتبط هستند Tag ، و Post مدل‌ها متعلق به یک Author مدل هستند.

با استفاده از این تعاریف و روابط مدل، ممکن است نمونه‌های مدل را بازیابی کنیم ActivityFeed و مشتاقانه همه parentable مدل‌ها و روابط تودرتوی مربوطه را بارگیری کنیم:

use Illuminate\Database\Eloquent\Relations\MorphTo;
 
$activities = ActivityFeed::query()
->with(['parentable' => function (MorphTo $morphTo) {
$morphTo->morphWith([
Event::class => ['calendar'],
Photo::class => ['tags'],
Post::class => ['author'],
]);
}])->get();

Eager Loading ستون های خاص

ممکن است همیشه به هر ستون از روابطی که بازیابی می کنید نیاز نداشته باشید. به همین دلیل، Eloquent به شما اجازه می دهد تا مشخص کنید کدام ستون از رابطه را می خواهید بازیابی کنید:

$books = App\Book::with('author:id,name')->get();

هنگام استفاده از این ویژگی، همیشه باید id ستون و هر ستون کلید خارجی مربوطه را در لیست ستون هایی که می خواهید بازیابی کنید، قرار دهید.

Eager Loading به صورت پیش فرض

گاهی اوقات ممکن است بخواهید همیشه برخی از روابط را هنگام بازیابی یک مدل بارگیری کنید. برای انجام این کار، می توانید یک $with ویژگی را در مدل تعریف کنید:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Book extends Model
{
/**
* The relationships that should always be loaded.
*
* @var array
*/
protected $with = ['author'];
 
/**
* Get the author that wrote the book.
*/
public function author()
{
return $this->belongsTo('App\Author');
}
}

اگر می خواهید $with برای یک پرس و جو، موردی را از ویژگی حذف کنید، می توانید از without روش زیر استفاده کنید:

$books = App\Book::without('author')->get();

محدود کردن بارهای مشتاق

گاهی اوقات ممکن است بخواهید مشتاقانه یک رابطه را بارگیری کنید، اما همچنین شرایط پرس و جو اضافی را برای درخواست بارگیری مشتاق مشخص کنید. در اینجا یک مثال است:

$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();

روش‌های سازنده پرس limit و جو و take درخواست ممکن است هنگام محدود کردن بارهای مشتاق مورد استفاده قرار نگیرند.

تنبل مشتاق بارگیری

گاهی اوقات ممکن است نیاز داشته باشید که مشتاقانه یک رابطه را پس از بازیابی مدل والد بارگیری کنید. برای مثال، اگر بخواهید به صورت پویا تصمیم بگیرید که آیا مدل‌های مرتبط را بارگیری کنید، این ممکن است مفید باشد:

$books = App\Book::all();
 
if ($someCondition) {
$books->load('author', 'publisher');
}

اگر نیاز به تعیین محدودیت‌های پرس و جو اضافی در پرس‌وجوی بارگیری مشتاق دارید، می‌توانید آرایه‌ای را ارسال کنید که توسط روابطی که می‌خواهید بارگیری کنید کلید خورده است. مقادیر آرایه باید Closure نمونه هایی باشند که نمونه پرس و جو را دریافت می کنند:

$author->load(['books' => function ($query) {
$query->orderBy('published_date', 'asc');
}]);

برای بارگیری یک رابطه فقط زمانی که قبلاً بارگذاری نشده باشد، از loadMissing روش استفاده کنید:

public function format(Book $book)
{
$book->loadMissing('author');
 
return [
'name' => $book->name,
'author' => $book->author->name,
];
}

Nested Lazy Eager Loading & morphTo

اگر می‌خواهید مشتاقانه یک morphTo رابطه و همچنین روابط تودرتو در موجودیت‌های مختلفی که ممکن است توسط آن رابطه برگردانده شوند بارگذاری کنید، می‌توانید از این loadMorph روش استفاده کنید.

این روش نام morphTo رابطه را به عنوان اولین آرگومان خود و آرایه ای از جفت های مدل / رابطه را به عنوان آرگومان دوم می پذیرد. برای کمک به توضیح این روش، بیایید مدل زیر را در نظر بگیریم:

<?php
 
use Illuminate\Database\Eloquent\Model;
 
class ActivityFeed extends Model
{
/**
* Get the parent of the activity feed record.
*/
public function parentable()
{
return $this->morphTo();
}
}

در این مثال، فرض کنید Event ، Photo و Post مدل ها ممکن است ActivityFeed مدل هایی ایجاد کنند. علاوه بر این، فرض کنیم که Event مدل‌ها متعلق به یک Calendar مدل هستند، Photo مدل‌ها با مدل‌ها مرتبط هستند Tag ، و Post مدل‌ها متعلق به یک Author مدل هستند.

با استفاده از این تعاریف و روابط مدل، ممکن است نمونه‌های مدل را بازیابی کنیم ActivityFeed و مشتاقانه همه parentable مدل‌ها و روابط تودرتوی مربوطه را بارگیری کنیم:

$activities = ActivityFeed::with('parentable')
->get()
->loadMorph('parentable', [
Event::class => ['calendar'],
Photo::class => ['tags'],
Post::class => ['author'],
]);

روش ذخیره

Eloquent روش های مناسبی را برای افزودن مدل های جدید به روابط ارائه می دهد. برای مثال، شاید لازم باشد یک مدل جدید درج Comment کنید Post . به جای تنظیم دستی post_id مشخصه روی Comment , می توانید Comment مستقیماً از متد رابطه وارد کنید save :

$comment = new App\Comment(['message' => 'A new comment.']);
 
$post = App\Post::find(1);
 
$post->comments()->save($comment);

comments توجه داشته باشید که ما به رابطه به عنوان یک ویژگی پویا دسترسی نداشتیم . comments در عوض، روش را برای به دست آوردن یک نمونه از رابطه فراخوانی کردیم . این save روش به طور خودکار مقدار مناسب را post_id به Comment مدل جدید اضافه می کند.

اگر نیاز به ذخیره چندین مدل مرتبط دارید، می توانید از saveMany روش زیر استفاده کنید:

$post = App\Post::find(1);
 
$post->comments()->saveMany([
new App\Comment(['message' => 'A new comment.']),
new App\Comment(['message' => 'Another comment.']),
]);

متدهای save و saveMany مدل‌های جدید را به هیچ رابطه‌ای در حافظه اضافه نمی‌کنند که قبلاً روی مدل والد بارگذاری شده است. اگر قصد دارید پس از استفاده از روش save یا به رابطه دسترسی پیدا کنید saveMany ، ممکن است بخواهید از refresh روش برای بارگذاری مجدد مدل و روابط آن استفاده کنید:

$post->comments()->save($comment);
 
$post->refresh();
 
// All comments, including the newly saved comment...
$post->comments;

ذخیره بازگشتی مدل ها و روابط

اگر مایل به save مدل خود و همه روابط مرتبط با آن هستید، می توانید از push روش زیر استفاده کنید:

$post = App\Post::find(1);
 
$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';
 
$post->push();

روش ایجاد

علاوه بر متدهای save و saveMany ، می‌توانید از create روشی نیز استفاده کنید که آرایه‌ای از ویژگی‌ها را می‌پذیرد، یک مدل ایجاد می‌کند و آن را در پایگاه داده قرار می‌دهد. باز هم، تفاوت بین save و create این است که save یک نمونه مدل کامل Eloquent را می پذیرد در حالی که create یک PHP ساده را می پذیرد array :

$post = App\Post::find(1);
 
$comment = $post->comments()->create([
'message' => 'A new comment.',
]);

قبل از استفاده از create روش، مطمئن شوید که مستندات مربوط به تخصیص جرم مشخصه را بررسی کنید .

می توانید از createMany روش برای ایجاد چندین مدل مرتبط استفاده کنید:

$post = App\Post::find(1);
 
$post->comments()->createMany([
[
'message' => 'A new comment.',
],
[
'message' => 'Another new comment.',
],
]);

همچنین می‌توانید از روش‌های، findOrNew و برای ایجاد و به‌روزرسانی مدل‌های روابط استفاده کنید . firstOrNew firstOrCreate updateOrCreate

متعلق به روابط است

هنگام به روز رسانی یک belongsTo رابطه، می توانید از این associate روش استفاده کنید. این روش کلید خارجی را در مدل فرزند تنظیم می کند:

$account = App\Account::find(10);
 
$user->account()->associate($account);
 
$user->save();

هنگام حذف یک belongsTo رابطه، می توانید از این dissociate روش استفاده کنید. این روش کلید خارجی رابطه را به صورت زیر تنظیم می کند null :

$user->account()->dissociate();
 
$user->save();

مدل های پیش فرض

روابط belongsTo , hasOne , hasOneThrough , و morphOne به شما این امکان را می دهد که یک مدل پیش فرض تعریف کنید که اگر رابطه داده شده باشد، برگردانده می شود null . این الگو اغلب به عنوان الگوی شی تهی شناخته می شود و می تواند به حذف بررسی های شرطی در کد شما کمک کند. در مثال زیر، این user رابطه یک مدل خالی را برمی‌گرداند App\User اگر خیر user به پست پیوست شود:

/**
* Get the author of the post.
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault();
}

برای پر کردن مدل پیش‌فرض با ویژگی‌ها، می‌توانید یک آرایه یا Closure را به withDefault متد ارسال کنید:

/**
* Get the author of the post.
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault([
'name' => 'Guest Author',
]);
}
 
/**
* Get the author of the post.
*/
public function user()
{
return $this->belongsTo('App\User')->withDefault(function ($user, $post) {
$user->name = 'Guest Author';
});
}

بسیاری از روابط

پیوست کردن / جدا کردن

Eloquent همچنین چند روش کمکی اضافی را برای راحت‌تر کردن کار با مدل‌های مرتبط ارائه می‌کند. به عنوان مثال، بیایید تصور کنیم یک کاربر می تواند نقش های زیادی داشته باشد و یک نقش می تواند کاربران زیادی داشته باشد. برای پیوست کردن یک نقش به یک کاربر با قرار دادن یک رکورد در جدول میانی که به مدل ها می پیوندد، از attach روش استفاده کنید:

$user = App\User::find(1);
 
$user->roles()->attach($roleId);

هنگام پیوست کردن یک رابطه به یک مدل، می‌توانید آرایه‌ای از داده‌های اضافی را نیز برای درج در جدول میانی ارسال کنید:

$user->roles()->attach($roleId, ['expires' => $expires]);

گاهی اوقات ممکن است لازم باشد که یک نقش از یک کاربر حذف شود. برای حذف یک رکورد رابطه چند به چند، از detach روش استفاده کنید. این detach روش رکورد مناسب را از جدول میانی حذف می کند. با این حال، هر دو مدل در پایگاه داده باقی می مانند:

// Detach a single role from the user...
$user->roles()->detach($roleId);
 
// Detach all roles from the user...
$user->roles()->detach();

برای راحتی attach و detach همچنین پذیرش آرایه های شناسه به عنوان ورودی:

$user = App\User::find(1);
 
$user->roles()->detach([1, 2, 3]);
 
$user->roles()->attach([
1 => ['expires' => $expires],
2 => ['expires' => $expires],
]);

همگام سازی انجمن ها

همچنین می‌توانید از این sync روش برای ایجاد ارتباط چند به چند استفاده کنید. این sync روش آرایه ای از شناسه ها را برای قرار دادن در جدول میانی می پذیرد. هر شناسه ای که در آرایه داده شده نباشد از جدول میانی حذف می شود. بنابراین، پس از تکمیل این عملیات، تنها شناسه های موجود در آرایه داده شده در جدول میانی وجود خواهند داشت:

$user->roles()->sync([1, 2, 3]);

همچنین می توانید مقادیر جدول میانی اضافی را با شناسه ها ارسال کنید:

$user->roles()->sync([1 => ['expires' => true], 2, 3]);

اگر نمی‌خواهید شناسه‌های موجود را جدا کنید، می‌توانید از syncWithoutDetaching روش زیر استفاده کنید:

$user->roles()->syncWithoutDetaching([1, 2, 3]);

ضامن انجمن ها

رابطه چند به چند نیز toggle روشی را ارائه می دهد که وضعیت پیوست شناسه های داده شده را "تغییر" می کند. اگر شناسه داده شده در حال حاضر پیوست باشد، جدا می شود. به همین ترتیب، اگر در حال حاضر جدا شده باشد، پیوست خواهد شد:

$user->roles()->toggle([1, 2, 3]);

ذخیره داده های اضافی در جدول محوری

هنگام کار با یک رابطه چند به چند، save متد آرایه ای از ویژگی های جدول میانی اضافی را به عنوان آرگومان دوم خود می پذیرد:

App\User::find(1)->roles()->save($role, ['expires' => $expires]);

به روز رسانی یک رکورد در جدول محوری

اگر نیاز به به روز رسانی یک ردیف موجود در جدول محوری خود دارید، می توانید از updateExistingPivot روش استفاده کنید. این روش کلید خارجی رکورد محوری و آرایه ای از ویژگی ها را برای به روز رسانی می پذیرد:

$user = App\User::find(1);
 
$user->roles()->updateExistingPivot($roleId, $attributes);

لمس کردن مهر زمانی والدین

هنگامی که یک مدل belongsTo یا belongsToMany مدل دیگری، مانند مدلی Comment که متعلق به یک است Post ، گاهی اوقات مفید است که وقتی مدل فرزند به روز می شود، مهر زمانی والدین را به روز کنید. به عنوان مثال، هنگامی که یک Comment مدل به روز می شود، ممکن است بخواهید به طور خودکار updated_at مهر زمانی مالکیت را "لمس" کنید Post . الکوئنت آن را آسان می کند. فقط یک touches ویژگی حاوی نام روابط را به مدل فرزند اضافه کنید:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Comment extends Model
{
/**
* All of the relationships to be touched.
*
* @var array
*/
protected $touches = ['post'];
 
/**
* Get the post that the comment belongs to.
*/
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();