الکوئنت: روابط
- معرفی
- تعریف روابط
- روابط چند شکلی
- روابط پویا
- روابط پرس و جو
- مشتاق بارگیری
- درج و به روز رسانی مدل های مرتبط
- لمس کردن مهر زمانی والدین
معرفی
جداول پایگاه داده اغلب با یکدیگر مرتبط هستند. به عنوان مثال، یک پست وبلاگ ممکن است نظرات زیادی داشته باشد، یا یک سفارش می تواند مربوط به کاربری باشد که آن را ارسال کرده است. 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();