الکوئنت: روابط
- معرفی
- تعریف روابط
- روابط بسیار به بسیاری
- روابط چند شکلی
- روابط پویا
- روابط پرس و جو
- تجمیع مدل های مرتبط
- مشتاق بارگیری
- درج و به روز رسانی مدل های مرتبط
- لمس کردن مهر زمانی والدین
معرفی
جداول پایگاه داده اغلب با یکدیگر مرتبط هستند. به عنوان مثال، یک پست وبلاگ ممکن است نظرات زیادی داشته باشد یا یک سفارش می تواند مربوط به کاربری باشد که آن را ارسال کرده است. Eloquent مدیریت و کار با این روابط را آسان می کند و از انواع روابط رایج پشتیبانی می کند:
تعریف روابط
روابط Eloquent به عنوان روش هایی در کلاس های مدل Eloquent شما تعریف می شوند. از آنجایی که روابط نیز به عنوان
سازندگان پرس و جو
قوی عمل می کنند ، تعریف روابط به عنوان متدها، قابلیت های زنجیره ای متد و پرس و جوی قدرتمندی را فراهم می کند. برای مثال، ممکن است محدودیتهای پرس و جو اضافی را در این
posts
رابطه زنجیرهای کنیم:
$user->posts()->where('active', 1)->get();
اما، قبل از غوطه ور شدن بیش از حد در استفاده از روابط، بیایید یاد بگیریم که چگونه هر نوع رابطه ای را که توسط Eloquent پشتیبانی می شود، تعریف کنیم.
یک به یک
رابطه یک به یک نوع بسیار ابتدایی رابطه پایگاه داده است. به عنوان مثال، یک
User
مدل ممکن است با یک مدل مرتبط باشد
Phone
. برای تعریف این رابطه،
phone
روشی را روی مدل
قرار می دهیم
User
. متد
phone
باید
hasOne
متد را فراخوانی کرده و نتیجه آن را برگرداند. این
hasOne
روش از طریق کلاس پایه مدل برای مدل شما در دسترس است
Illuminate\Database\Eloquent\Model
:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasOne; class User extends Model{ /** * Get the phone associated with the user. */ public function phone(): HasOne { return $this->hasOne(Phone::class); }}
اولین آرگومان ارسال شده به
hasOne
متد، نام کلاس مدل مرتبط است. هنگامی که رابطه تعریف شد، ممکن است رکورد مربوطه را با استفاده از ویژگی های دینامیکی Eloquent بازیابی کنیم. ویژگیهای پویا به شما امکان میدهند به روشهای رابطه دسترسی داشته باشید، گویی که آنها ویژگیهایی هستند که در مدل تعریف شدهاند:
$phone = User::find(1)->phone;
Eloquent کلید خارجی رابطه را بر اساس نام مدل والد تعیین می کند. در این حالت،
Phone
مدل به طور خودکار دارای یک
user_id
کلید خارجی فرض می شود. اگر می خواهید این قرارداد را لغو کنید، می توانید یک آرگومان دوم را به
hasOne
متد ارسال کنید:
return $this->hasOne(Phone::class, 'foreign_key');
علاوه بر این، Eloquent فرض میکند که کلید خارجی باید دارای مقداری مطابق با ستون کلید اصلی والد باشد. به عبارت دیگر، Eloquent مقدار ستون کاربر را
id
در
user_id
ستون رکورد جستجو می کند
Phone
. اگر میخواهید این رابطه از یک مقدار کلید اصلی غیر از ویژگی
id
مدل شما
استفاده کند
$primaryKey
، میتوانید آرگومان سومی را به
hasOne
متد ارسال کنید:
return $this->hasOne(Phone::class, 'foreign_key', 'local_key');
تعریف معکوس رابطه
بنابراین، ما می توانیم
Phone
از
User
مدل خود به مدل دسترسی پیدا کنیم. در مرحله بعد، بیایید یک رابطه در
Phone
مدل تعریف کنیم که به ما امکان می دهد به کاربر صاحب تلفن دسترسی پیدا کنیم. ما می توانیم معکوس یک
hasOne
رابطه را با استفاده از
belongsTo
روش تعریف کنیم:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; class Phone extends Model{ /** * Get the user that owns the phone. */ public function user(): BelongsTo { return $this->belongsTo(User::class); }}
هنگام فراخوانی روش، Eloquent تلاش میکند
مدلی را
user
بیابد که با
ستون روی مدل
مطابقت داشته باشد
.
User
id
user_id
Phone
Eloquent نام کلید خارجی را با بررسی نام روش رابطه و پسوند نام متد با
_id
. بنابراین، در این مورد، Eloquent فرض می کند که
Phone
مدل دارای یک
user_id
ستون است. با این حال، اگر کلید خارجی مدل
Phone
نیست
user_id
، میتوانید یک نام کلید سفارشی را به عنوان آرگومان دوم به
belongsTo
متد ارسال کنید:
/** * Get the user that owns the phone. */public function user(): BelongsTo{ return $this->belongsTo(User::class, 'foreign_key');}
اگر مدل والد به عنوان کلید اصلی خود استفاده نمیکند
id
، یا میخواهید مدل مرتبط را با استفاده از ستون دیگری پیدا کنید، میتوانید آرگومان سومی را به متد ارسال کنید که
belongsTo
کلید سفارشی جدول والد را مشخص میکند:
/** * Get the user that owns the phone. */public function user(): BelongsTo{ return $this->belongsTo(User::class, 'foreign_key', 'owner_key');}
یک به بسیاری
یک رابطه یک به چند برای تعریف روابطی استفاده می شود که در آن یک مدل واحد والدین یک یا چند مدل فرزند است. به عنوان مثال، یک پست وبلاگ ممکن است تعداد بی نهایت نظر داشته باشد. مانند سایر روابط Eloquent، روابط یک به چند با تعریف یک روش در مدل Eloquent شما تعریف می شود:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany; class Post extends Model{ /** * Get the comments for the blog post. */ public function comments(): HasMany { return $this->hasMany(Comment::class); }}
به یاد داشته باشید، Eloquent به طور خودکار ستون کلید خارجی مناسب را برای
Comment
مدل تعیین می کند. طبق قرارداد، Eloquent نام "snake case" مدل والد را می گیرد و آن را پسوند می کند
_id
. بنابراین، در این مثال، Eloquent ستون کلید خارجی مدل
Comment
را
post_id
.
هنگامی که متد رابطه تعریف شد، می توانیم با دسترسی به ویژگی به
مجموعه
نظرات مرتبط دسترسی پیدا کنیم
comments
. به یاد داشته باشید، از آنجایی که Eloquent "ویژگی های رابطه پویا" را ارائه می دهد، می توانیم به روش های رابطه به گونه ای دسترسی داشته باشیم که گویی به عنوان ویژگی در مدل تعریف شده اند:
use App\Models\Post; $comments = Post::find(1)->comments; foreach ($comments as $comment) { // ...}
comments
از آنجایی که همه روابط به عنوان سازنده پرس و جو نیز عمل می کنند، می توانید با فراخوانی متد و ادامه دادن به شرایط زنجیره ای در پرس و جو،
محدودیت های بیشتری به پرس و جوی رابطه اضافه کنید :
$comment = Post::find(1)->comments() ->where('title', 'foo') ->first();
مانند
hasOne
متد، میتوانید کلیدهای خارجی و محلی را نیز با ارسال آرگومانهای اضافی به
hasMany
متد لغو کنید:
return $this->hasMany(Comment::class, 'foreign_key'); return $this->hasMany(Comment::class, 'foreign_key', 'local_key');
یک به بسیاری (معکوس) / متعلق به
اکنون که میتوانیم به همه نظرات یک پست دسترسی پیدا کنیم، بیایید یک رابطه تعریف کنیم تا یک نظر به پست اصلی خود دسترسی پیدا کند. برای تعریف معکوس یک
hasMany
رابطه، یک روش رابطه در مدل فرزند تعریف کنید که
belongsTo
متد را فراخوانی می کند:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; class Comment extends Model{ /** * Get the post that owns the comment. */ public function post(): BelongsTo { return $this->belongsTo(Post::class); }}
هنگامی که رابطه تعریف شد، میتوانیم با دسترسی به
post
"ویژگی رابطه پویا" پست والد یک نظر را بازیابی کنیم:
use App\Models\Comment; $comment = Comment::find(1); return $comment->post->title;
در مثال بالا، Eloquent تلاش میکند
Post
مدلی را پیدا کند که با
ستون روی مدل
id
مطابقت داشته باشد
.
post_id
Comment
Eloquent نام کلید خارجی پیشفرض را با بررسی نام روش رابطه و پسوند نام متد با
_
نام ستون کلید اصلی مدل والد تعیین میکند. بنابراین، در این مثال، Eloquent فرض میکند که
Post
کلید خارجی مدل روی
comments
جدول است
post_id
.
با این حال، اگر کلید خارجی برای رابطه شما از این قراردادها پیروی نمی کند، می توانید یک نام کلید خارجی سفارشی را به عنوان آرگومان دوم برای متد ارسال کنید
belongsTo
:
/** * Get the post that owns the comment. */public function post(): BelongsTo{ return $this->belongsTo(Post::class, 'foreign_key');}
اگر مدل والد شما بهعنوان کلید اصلی خود استفاده نمیکند
id
، یا میخواهید مدل مرتبط را با استفاده از ستون دیگری پیدا کنید، میتوانید آرگومان سومی را به متد ارسال کنید که
belongsTo
کلید سفارشی جدول والد شما را مشخص میکند:
/** * Get the post that owns the comment. */public function post(): BelongsTo{ return $this->belongsTo(Post::class, 'foreign_key', 'owner_key');}
مدل های پیش فرض
روابط
belongsTo
,
hasOne
,
hasOneThrough
, و
morphOne
به شما این امکان را می دهد که یک مدل پیش فرض تعریف کنید که اگر رابطه داده شده باشد، برگردانده می شود
null
. این الگو اغلب به عنوان
الگوی شی تهی
شناخته می شود و می تواند به حذف بررسی های شرطی در کد شما کمک کند. در مثال زیر،
اگر هیچ کاربری به مدل متصل نباشد،
user
رابطه یک مدل خالی برمیگرداند
:
App\Models\User
Post
/** * Get the author of the post. */public function user(): BelongsTo{ return $this->belongsTo(User::class)->withDefault();}
برای پر کردن مدل پیشفرض با ویژگیها، میتوانید یک آرایه یا بسته را به
withDefault
متد ارسال کنید:
/** * Get the author of the post. */public function user(): BelongsTo{ return $this->belongsTo(User::class)->withDefault([ 'name' => 'Guest Author', ]);} /** * Get the author of the post. */public function user(): BelongsTo{ return $this->belongsTo(User::class)->withDefault(function (User $user, Post $post) { $user->name = 'Guest Author'; });}
پرس و جو متعلق به روابط است
هنگام پرس و جو برای فرزندان یک رابطه " متعلق به "، می توانید به صورت دستی این
where
عبارت را برای بازیابی مدل های Eloquent مربوطه بسازید:
use App\Models\Post; $posts = Post::where('user_id', $user->id)->get();
با این حال، ممکن است استفاده از
whereBelongsTo
روشی که به طور خودکار رابطه مناسب و کلید خارجی مدل داده شده را تعیین می کند، راحت تر باشد:
$posts = Post::whereBelongsTo($user)->get();
همچنین می توانید یک نمونه
مجموعه
برای
whereBelongsTo
روش ارائه دهید. هنگام انجام این کار، لاراول مدل هایی را که متعلق به هر یک از مدل های والد مجموعه هستند بازیابی می کند:
$users = User::where('vip', true)->get(); $posts = Post::whereBelongsTo($users)->get();
به طور پیش فرض، لاراول رابطه مرتبط با مدل داده شده را بر اساس نام کلاس مدل تعیین می کند. با این حال، می توانید نام رابطه را به صورت دستی با ارائه آن به عنوان آرگومان دوم متد مشخص کنید
whereBelongsTo
:
$posts = Post::whereBelongsTo($user, 'author')->get();
یکی از بسیاری را دارد
گاهی اوقات یک مدل ممکن است مدلهای مرتبط زیادی داشته باشد، اما شما میخواهید به راحتی «آخرین» یا «قدیمیترین» مدل مرتبط رابطه را بازیابی کنید. به عنوان مثال، یک
User
مدل ممکن است به بسیاری از مدلها مرتبط باشد
Order
، اما شما میخواهید روشی مناسب برای تعامل با آخرین سفارشی که کاربر قرار داده است، تعریف کنید. شما می توانید این کار را با استفاده از
hasOne
نوع رابطه ترکیب شده با
ofMany
روش های زیر انجام دهید:
/** * Get the user's most recent order. */public function latestOrder(): HasOne{ return $this->hasOne(Order::class)->latestOfMany();}
به همین ترتیب، میتوانید روشی را برای بازیابی «قدیمیترین» یا اولین مدل مرتبط یک رابطه تعریف کنید:
/** * Get the user's oldest order. */public function oldestOrder(): HasOne{ return $this->hasOne(Order::class)->oldestOfMany();}
به طور پیشفرض، متدهای
latestOfMany
و
oldestOfMany
آخرین یا قدیمیترین مدل مرتبط را بر اساس کلید اصلی مدل، که باید قابل مرتبسازی باشد، بازیابی میکنند. با این حال، گاهی اوقات ممکن است بخواهید یک مدل واحد را از یک رابطه بزرگتر با استفاده از معیارهای مرتب سازی متفاوت بازیابی کنید.
به عنوان مثال، با استفاده از
ofMany
روش، ممکن است گران ترین سفارش کاربر را بازیابی کنید. این
ofMany
متد ستون قابل مرتبسازی را بهعنوان اولین آرگومان خود میپذیرد و کدام تابع جمع (
min
یا
max
) را هنگام پرس و جو برای مدل مرتبط اعمال میکند:
/** * Get the user's largest order. */public function largestOrder(): HasOne{ return $this->hasOne(Order::class)->ofMany('price', 'max');}
از آنجایی که PostgreSQL از اجرای تابع در برابر ستونهای UUID پشتیبانی نمیکند
MAX
، در حال حاضر امکان استفاده از یکی از چندین رابطه در ترکیب با ستونهای PostgreSQL UUID وجود ندارد.
تبدیل روابط "بسیار" به دارای یک رابطه
اغلب، هنگام بازیابی یک مدل واحد با استفاده از متدهای
latestOfMany
،
oldestOfMany
یا،
ofMany
از قبل یک رابطه "دارای بسیاری" برای همان مدل تعریف شده است. برای راحتی کار، لاراول به شما اجازه می دهد تا با استفاده از
one
متد روی رابطه،
این رابطه را به راحتی به یک رابطه "یک" تبدیل کنید :
/** * Get the user's orders. */public function orders(): HasMany{ return $this->hasMany(Order::class);} /** * Get the user's largest order. */public function largestOrder(): HasOne{ return $this->orders()->one()->ofMany('price', 'max');}
Advanced یکی از بسیاری از روابط را دارد
می توان روابط پیشرفته تری ساخت "یکی از چندین" را دارد. به عنوان مثال، یک
Product
مدل ممکن است مدل های مرتبط زیادی داشته باشد
Price
که حتی پس از انتشار قیمت گذاری جدید در سیستم حفظ می شوند. علاوه بر این، دادههای قیمتگذاری جدید برای محصول ممکن است از قبل منتشر شود تا در تاریخ آینده از طریق یک
published_at
ستون اعمال شود.
بنابراین، به طور خلاصه، ما باید آخرین قیمت منتشر شده را در جایی که تاریخ منتشر شده در آینده نیست، بازیابی کنیم. علاوه بر این، اگر دو قیمت تاریخ انتشار یکسانی داشته باشند، قیمت با بیشترین شناسه را ترجیح می دهیم. برای انجام این کار، باید آرایهای را به
ofMany
متد ارسال کنیم که حاوی ستونهای قابل مرتبسازی است که آخرین قیمت را تعیین میکنند. علاوه بر این، یک بسته به عنوان آرگومان دوم برای
ofMany
روش ارائه خواهد شد. این بسته شدن مسئول اضافه کردن محدودیت های تاریخ انتشار اضافی به پرس و جو رابطه خواهد بود:
/** * Get the current pricing for the product. */public function currentPricing(): HasOne{ return $this->hasOne(Price::class)->ofMany([ 'published_at' => 'max', 'id' => 'max', ], function (Builder $query) { $query->where('published_at', '<', now()); });}
دارای یکی از طریق
رابطه "دارای یک از طریق" یک رابطه یک به یک را با مدل دیگری تعریف می کند. با این حال، این رابطه نشان میدهد که مدل اعلامکننده را میتوان با یک نمونه از مدل دیگر با ادامه مدل سوم مطابقت داد .
به عنوان مثال، در یک برنامه تعمیرگاه خودرو، هر
Mechanic
مدل ممکن است با یک
Car
مدل و هر مدل ممکن است با یک
مدل
Car
مرتبط باشد .
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\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasOneThrough; class Mechanic extends Model{ /** * Get the car's owner. */ public function carOwner(): HasOneThrough { return $this->hasOneThrough(Owner::class, Car::class); }}
اولین آرگومان ارسال شده به
hasOneThrough
متد، نام مدل نهایی است که می خواهیم به آن دسترسی داشته باشیم، در حالی که آرگومان دوم، نام مدل میانی است.
یا، اگر روابط مربوطه قبلاً روی همه مدلهای درگیر در رابطه تعریف شدهاند، میتوانید با فراخوانی روش
through
و ارائه نام آن روابط، یک رابطه «دارای یک از طریق» را روان تعریف کنید. به عنوان مثال، اگر
Mechanic
مدل دارای یک
cars
رابطه است و
Car
مدل دارای یک
owner
رابطه است، می توانید یک رابطه "دارای یک از طریق" را تعریف کنید که مکانیک و مالک را به این صورت متصل می کند:
// String based syntax...return $this->through('cars')->has('owner'); // Dynamic syntax...return $this->throughCars()->hasOwner();
کنوانسیون های کلیدی
قراردادهای کلید خارجی Eloquent معمولی هنگام انجام پرس و جوهای رابطه استفاده می شود. اگر می خواهید کلیدهای رابطه را سفارشی کنید، می توانید آنها را به عنوان آرگومان های سوم و چهارم به
hasOneThrough
متد ارسال کنید. آرگومان سوم نام کلید خارجی در مدل میانی است. آرگومان چهارم نام کلید خارجی در مدل نهایی است. آرگومان پنجم کلید محلی است، در حالی که آرگومان ششم کلید محلی مدل میانی است:
class Mechanic extends Model{ /** * Get the car's owner. */ public function carOwner(): HasOneThrough { return $this->hasOneThrough( Owner::class, Car::class, 'mechanic_id', // Foreign key on the cars table... 'car_id', // Foreign key on the owners table... 'id', // Local key on the mechanics table... 'id' // Local key on the cars table... ); }}
یا، همانطور که قبلاً بحث شد، اگر روابط مربوطه قبلاً در همه مدلهای درگیر در رابطه تعریف شدهاند، میتوانید با فراخوانی روش
through
و ارائه نام آن روابط، یک رابطه «دارای یک از طریق» را روان تعریف کنید. این رویکرد مزیت استفاده مجدد از قراردادهای کلیدی که قبلاً در روابط موجود تعریف شده است را ارائه می دهد:
// String based syntax...return $this->through('cars')->has('owner'); // Dynamic syntax...return $this->throughCars()->hasOwner();
دارای بسیاری از طریق
رابطه "دارای بسیاری از طریق" یک راه راحت برای دسترسی به روابط دور از طریق یک رابطه میانی فراهم می کند. به عنوان مثال، فرض کنید در حال ساخت یک پلت فرم استقرار مانند
Laravel Vapor
هستیم . یک
Project
مدل ممکن است
Deployment
از طریق یک مدل میانی به بسیاری از مدل ها دسترسی پیدا کند
Environment
. با استفاده از این مثال، شما به راحتی می توانید تمام استقرارها را برای یک پروژه معین جمع آوری کنید. بیایید به جداول مورد نیاز برای تعریف این رابطه نگاه کنیم:
projects id - integer name - string environments id - integer project_id - integer name - string deployments id - integer environment_id - integer commit_hash - string
اکنون که ساختار جدول را برای رابطه بررسی کردیم، بیایید رابطه را بر روی
Project
مدل تعریف کنیم:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasManyThrough; class Project extends Model{ /** * Get all of the deployments for the project. */ public function deployments(): HasManyThrough { return $this->hasManyThrough(Deployment::class, Environment::class); }}
اولین آرگومان ارسال شده به
hasManyThrough
متد، نام مدل نهایی است که می خواهیم به آن دسترسی داشته باشیم، در حالی که آرگومان دوم، نام مدل میانی است.
یا، اگر روابط مربوطه قبلاً روی همه مدلهای درگیر در رابطه تعریف شدهاند، میتوانید با فراخوانی روش
through
و ارائه نام آن روابط، یک رابطه «دارای بسیاری از طریق» را روان تعریف کنید. به عنوان مثال، اگر
Project
مدل دارای یک
environments
رابطه است و
Environment
مدل دارای یک
deployments
رابطه است، می توانید یک رابطه "دارای بسیاری از طریق" تعریف کنید که پروژه و استقرارهای مشابه را به هم متصل می کند:
// String based syntax...return $this->through('environments')->has('deployments'); // Dynamic syntax...return $this->throughEnvironments()->hasDeployments();
اگرچه
Deployment
جدول مدل شامل ستونی نیست
project_id
، اما این
hasManyThrough
رابطه از طریق
$project->deployments
. برای بازیابی این مدل ها، Eloquent ستون روی
جدول مدل
project_id
میانی را بررسی می کند.
Environment
پس از یافتن شناسه های محیط مربوطه، از آنها برای پرس و جوی
Deployment
جدول مدل استفاده می شود.
کنوانسیون های کلیدی
قراردادهای کلید خارجی Eloquent معمولی هنگام انجام پرس و جوهای رابطه استفاده می شود. اگر می خواهید کلیدهای رابطه را سفارشی کنید، می توانید آنها را به عنوان آرگومان های سوم و چهارم به
hasManyThrough
متد ارسال کنید. آرگومان سوم نام کلید خارجی در مدل میانی است. آرگومان چهارم نام کلید خارجی در مدل نهایی است. آرگومان پنجم کلید محلی است، در حالی که آرگومان ششم کلید محلی مدل میانی است:
class Project extends Model{ public function deployments(): HasManyThrough { return $this->hasManyThrough( Deployment::class, Environment::class, 'project_id', // Foreign key on the environments table... 'environment_id', // Foreign key on the deployments table... 'id', // Local key on the projects table... 'id' // Local key on the environments table... ); }}
یا، همانطور که قبلاً بحث شد، اگر روابط مربوطه قبلاً در همه مدلهای درگیر در رابطه تعریف شدهاند، میتوانید با فراخوانی روش
through
و ارائه نام آن روابط، یک رابطه «دارای بسیاری از طریق» را روان تعریف کنید. این رویکرد مزیت استفاده مجدد از قراردادهای کلیدی که قبلاً در روابط موجود تعریف شده است را ارائه می دهد:
// String based syntax...return $this->through('environments')->has('deployments'); // Dynamic syntax...return $this->throughEnvironments()->hasDeployments();
روابط بسیار به بسیاری
روابط چند به چند اندکی پیچیده تر از
hasOne
روابط هستند
hasMany
. نمونه ای از رابطه چند به چند، کاربری است که نقش های زیادی دارد و آن نقش ها توسط سایر کاربران در برنامه نیز به اشتراک گذاشته می شود. به عنوان مثال، ممکن است به یک کاربر نقش "نویسنده" و "ویرایشگر" اختصاص داده شود. با این حال، این نقش ها ممکن است به کاربران دیگر نیز اختصاص داده شود. بنابراین، یک کاربر دارای نقش های زیادی است و یک نقش دارای کاربران زیادی است.
ساختار جدول
برای تعریف این رابطه، به سه جدول پایگاه داده نیاز است:
users
,
roles
و
role_user
. جدول
role_user
از ترتیب حروف الفبای نام مدل های مرتبط و شامل
user_id
و
role_id
ستون ها مشتق شده است. این جدول به عنوان یک جدول میانی برای پیوند دادن کاربران و نقش ها استفاده می شود.
به یاد داشته باشید، از آنجایی که یک نقش می تواند به کاربران زیادی تعلق داشته باشد، نمی توانیم به سادگی یک
user_id
ستون را روی
roles
جدول قرار دهیم. این بدان معناست که یک نقش فقط می تواند به یک کاربر تعلق داشته باشد. به منظور پشتیبانی از نقش هایی که به چندین کاربر اختصاص داده می شوند،
role_user
جدول مورد نیاز است. میتوانیم ساختار جدول رابطه را به صورت زیر خلاصه کنیم:
users id - integer name - string roles id - integer name - string role_user user_id - integer role_id - integer
ساختار مدل
روابط چند به چند با نوشتن متدی تعریف می شوند که نتیجه متد را برمی گرداند
belongsToMany
. این
belongsToMany
روش توسط
Illuminate\Database\Eloquent\Model
کلاس پایه ارائه شده است که توسط همه مدل های Eloquent برنامه شما استفاده می شود. برای مثال، بیایید یک
roles
متد را روی
User
مدل خود تعریف کنیم. اولین آرگومان ارسال شده به این متد، نام کلاس مدل مرتبط است:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany; class User extends Model{ /** * The roles that belong to the user. */ public function roles(): BelongsToMany { return $this->belongsToMany(Role::class); }}
هنگامی که رابطه تعریف شد، می توانید با استفاده از ویژگی رابطه پویا به نقش های کاربر دسترسی داشته باشید
roles
:
use App\Models\User; $user = User::find(1); foreach ($user->roles as $role) { // ...}
roles
از آنجایی که همه روابط به عنوان سازنده پرس و جو نیز عمل می کنند، می توانید با فراخوانی متد و ادامه دادن به شرایط زنجیره ای در پرس و جو،
محدودیت های بیشتری به پرس و جوی رابطه اضافه کنید :
$roles = User::find(1)->roles()->orderBy('name')->get();
برای تعیین نام جدول جدول میانی رابطه، Eloquent دو نام مدل مرتبط را به ترتیب حروف الفبا به هم می پیوندد. با این حال، شما آزادید که این قرارداد را لغو کنید. می توانید این کار را با ارسال آرگومان دوم به
belongsToMany
متد انجام دهید:
return $this->belongsToMany(Role::class, 'role_user');
علاوه بر سفارشی کردن نام جدول میانی، میتوانید با ارسال آرگومانهای اضافی به متد، نام ستونهای کلیدهای روی جدول را نیز سفارشی کنید
belongsToMany
. آرگومان سوم، نام کلید خارجی مدلی است که بر اساس آن رابطه را تعریف می کنید، در حالی که آرگومان چهارم، نام کلید خارجی مدلی است که به آن ملحق می شوید:
return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
تعریف معکوس رابطه
برای تعریف «معکوس» یک رابطه چند به چند، باید متدی را روی مدل مرتبط تعریف کنید که نتیجه متد را نیز برمی گرداند
belongsToMany
. برای تکمیل مثال کاربر/نقش، اجازه دهید
users
روش را روی
Role
مدل تعریف کنیم:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Role extends Model{ /** * The users that belong to the role. */ public function users(): BelongsToMany { return $this->belongsToMany(User::class); }}
همانطور که می بینید، رابطه دقیقاً مانند
User
همتای مدل خود به استثنای ارجاع به
App\Models\User
مدل تعریف می شود. از آنجایی که ما در حال استفاده مجدد از این
belongsToMany
روش هستیم، تمام جدول های معمول و گزینه های سفارشی سازی کلید هنگام تعریف «معکوس» روابط چند به چند در دسترس هستند.
بازیابی ستون های جدول میانی
همانطور که قبلاً آموختید، کار با روابط چند به چند مستلزم وجود یک جدول میانی است. Eloquent راه های بسیار مفیدی برای تعامل با این جدول ارائه می دهد. به عنوان مثال، فرض کنید
User
مدل ما مدل های زیادی دارد
Role
که به آنها مربوط می شود. پس از دسترسی به این رابطه، ممکن است با استفاده از
pivot
ویژگی روی مدل ها
به جدول میانی دسترسی پیدا کنیم :
use App\Models\User; $user = User::find(1); foreach ($user->roles as $role) { echo $role->pivot->created_at;}
توجه داشته باشید که به هر
Role
مدلی که بازیابی می کنیم به طور خودکار یک
pivot
ویژگی اختصاص می یابد. این ویژگی شامل مدلی است که جدول میانی را نشان می دهد.
بهطور پیشفرض، فقط کلیدهای مدل در
pivot
مدل وجود خواهند داشت. اگر جدول میانی شما دارای ویژگی های اضافی است، باید آنها را هنگام تعریف رابطه مشخص کنید:
return $this->belongsToMany(Role::class)->withPivot('active', 'created_by');
اگر میخواهید جدول میانی شما دارای
created_at
مُهرهای زمانی باشد
updated_at
که بهطور خودکار توسط Eloquent نگهداری میشوند،
withTimestamps
هنگام تعریف رابطه، متد را فراخوانی کنید:
return $this->belongsToMany(Role::class)->withTimestamps();
جداول میانی که از مهرهای زمانی Eloquent استفاده میکنند، باید دارای ستونهای هر دو
created_at
و مهر زمان باشند.updated_at
سفارشی کردن
pivot
نام ویژگی
همانطور که قبلا ذکر شد، ویژگی های جدول میانی ممکن است در مدل ها از طریق
pivot
ویژگی قابل دسترسی باشند. با این حال، شما آزاد هستید که نام این ویژگی را سفارشی کنید تا هدف آن را در برنامه شما بهتر نشان دهد.
به عنوان مثال، اگر برنامه شما دارای کاربرانی باشد که ممکن است در پادکست ها مشترک شوند، احتمالاً بین کاربران و پادکست ها رابطه چند به چند دارید. اگر اینطور است، ممکن است بخواهید به
subscription
جای خصیصه جدول میانی خود را به تغییر نام دهید
pivot
. این را می توان با استفاده از
as
روش در هنگام تعریف رابطه انجام داد:
return $this->belongsToMany(Podcast::class) ->as('subscription') ->withTimestamps();
هنگامی که ویژگی جدول میانی سفارشی مشخص شد، می توانید با استفاده از نام سفارشی به داده های جدول میانی دسترسی داشته باشید:
$users = User::with('podcasts')->get(); foreach ($users->flatMap->podcasts as $podcast) { echo $podcast->subscription->created_at;}
فیلتر کردن کوئری ها از طریق ستون های جدول میانی
همچنین می توانید نتایج بازگردانده شده توسط
belongsToMany
پرس و جوهای رابطه را با استفاده از روش های
wherePivot
,
wherePivotIn
,
wherePivotNotIn
,
wherePivotBetween
,
wherePivotNotBetween
,
wherePivotNull
و
wherePivotNotNull
هنگام تعریف رابطه فیلتر کنید:
return $this->belongsToMany(Role::class) ->wherePivot('approved', 1); return $this->belongsToMany(Role::class) ->wherePivotIn('priority', [1, 2]); return $this->belongsToMany(Role::class) ->wherePivotNotIn('priority', [1, 2]); return $this->belongsToMany(Podcast::class) ->as('subscriptions') ->wherePivotBetween('created_at', ['2020-01-01 00:00:00', '2020-12-31 00:00:00']); return $this->belongsToMany(Podcast::class) ->as('subscriptions') ->wherePivotNotBetween('created_at', ['2020-01-01 00:00:00', '2020-12-31 00:00:00']); return $this->belongsToMany(Podcast::class) ->as('subscriptions') ->wherePivotNull('expired_at'); return $this->belongsToMany(Podcast::class) ->as('subscriptions') ->wherePivotNotNull('expired_at');
سفارش پرس و جو از طریق ستون های جدول میانی
با استفاده از این روش میتوانید نتایجی را که توسط
belongsToMany
کوئریهای رابطه بازگردانده میشوند، سفارش دهید
orderByPivot
. در مثال زیر، تمام آخرین نشانها را برای کاربر بازیابی میکنیم:
return $this->belongsToMany(Badge::class) ->where('rank', 'gold') ->orderByPivot('created_at', 'desc');
تعریف مدل های جدول میانی سفارشی
اگر می خواهید یک مدل سفارشی برای نمایش جدول میانی رابطه چند به چند خود تعریف کنید، می توانید
using
در هنگام تعریف رابطه، متد را فراخوانی کنید. مدلهای محوری سفارشی به شما این فرصت را میدهند تا رفتارهای اضافی را روی مدل محوری تعریف کنید، مانند روشها و قالبها.
مدل های محوری چند به چند سفارشی باید
Illuminate\Database\Eloquent\Relations\Pivot
کلاس را گسترش دهند در حالی که مدل های محوری چند شکلی سفارشی باید
Illuminate\Database\Eloquent\Relations\MorphPivot
کلاس را گسترش دهند. به عنوان مثال، ممکن است مدلی را تعریف کنیم
Role
که از یک
RoleUser
مدل محوری سفارشی استفاده می کند:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Role extends Model{ /** * The users that belong to the role. */ public function users(): BelongsToMany { return $this->belongsToMany(User::class)->using(RoleUser::class); }}
هنگام تعریف
RoleUser
مدل، باید
Illuminate\Database\Eloquent\Relations\Pivot
کلاس را گسترش دهید:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Relations\Pivot; class RoleUser extends Pivot{ // ...}
مدلهای محوری ممکن است از این ویژگی استفاده نکنند
SoftDeletes
. اگر نیاز به حذف نرم رکوردهای محوری دارید، مدل محوری خود را به یک مدل واقعی Eloquent تبدیل کنید.
مدلهای محوری سفارشی و شناسههای افزایشی
اگر یک رابطه چند به چند تعریف کردهاید که از یک مدل محوری سفارشی استفاده میکند، و آن مدل محوری دارای یک کلید اصلی افزایش خودکار است، باید مطمئن شوید که کلاس مدل محوری سفارشی شما یک
incrementing
ویژگی را تعریف میکند که روی
true
.
/** * Indicates if the IDs are auto-incrementing. * * @var bool */public $incrementing = true;
روابط چند شکلی
یک رابطه چند شکلی به مدل فرزند اجازه می دهد تا با استفاده از یک ارتباط واحد به بیش از یک نوع مدل تعلق داشته باشد. به عنوان مثال، تصور کنید در حال ساخت اپلیکیشنی هستید که به کاربران اجازه می دهد پست ها و ویدیوهای وبلاگ را به اشتراک بگذارند. در چنین برنامه ای، یک
Comment
مدل ممکن است به هر دو مدل
Post
و و تعلق داشته باشد
Video
.
یک به یک (چند شکلی)
ساختار جدول
یک رابطه چند شکلی یک به یک شبیه به یک رابطه معمولی یک به یک است. با این حال، مدل فرزند می تواند به بیش از یک نوع مدل با استفاده از یک ارتباط واحد تعلق داشته باشد. برای مثال، یک وبلاگ
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
. در این مورد، ستون شامل یک
App\Models\Post
یا
App\Models\User
.
ساختار مدل
سپس، اجازه دهید تعاریف مدل مورد نیاز برای ایجاد این رابطه را بررسی کنیم:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphTo; class Image extends Model{ /** * Get the parent imageable model (user or post). */ public function imageable(): MorphTo { return $this->morphTo(); }} use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphOne; class Post extends Model{ /** * Get the post's image. */ public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); }} use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphOne; class User extends Model{ /** * Get the user's image. */ public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); }}
بازیابی رابطه
هنگامی که جدول پایگاه داده و مدل های شما تعریف شد، می توانید از طریق مدل های خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای بازیابی تصویر برای یک پست، می توانیم به
image
ویژگی ارتباط پویا دسترسی داشته باشیم:
use App\Models\Post; $post = Post::find(1); $image = $post->image;
می توانید با دسترسی به نام روشی که فراخوانی را انجام می دهد، والد مدل چند شکلی را بازیابی کنید
morphTo
. در این مورد، این
imageable
روش روی
Image
مدل است. بنابراین، ما به آن متد به عنوان یک ویژگی رابطه پویا دسترسی خواهیم داشت:
use App\Models\Image; $image = Image::find(1); $imageable = $image->imageable;
بسته به نوع مدلی که تصویر را در اختیار دارد،
رابطه
imageable
روی مدل یک
یا نمونه
Image
برمیگرداند .
Post
User
کنوانسیون های کلیدی
در صورت لزوم، میتوانید نام ستونهای «id» و «type» را که توسط مدل فرزند چندشکل خود استفاده میشود، مشخص کنید. اگر این کار را انجام می دهید، مطمئن شوید که همیشه نام رابطه را به عنوان اولین آرگومان به
morphTo
متد ارسال می کنید. به طور معمول، این مقدار باید با نام روش مطابقت داشته باشد، بنابراین می توانید از ثابت PHP استفاده کنید
__FUNCTION__
:
/** * Get the model that the image belongs to. */public function imageable(): MorphTo{ 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\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphTo; class Comment extends Model{ /** * Get the parent commentable model (post or video). */ public function commentable(): MorphTo { return $this->morphTo(); }} use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphMany; class Post extends Model{ /** * Get all of the post's comments. */ public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); }} use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphMany; class Video extends Model{ /** * Get all of the video's comments. */ public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); }}
بازیابی رابطه
هنگامی که جدول پایگاه داده و مدلهای شما تعریف شد، میتوانید از طریق ویژگیهای رابطه پویا مدل خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای دسترسی به تمام نظرات یک پست، می توانیم از
comments
ویژگی پویا استفاده کنیم:
use App\Models\Post; $post = Post::find(1); foreach ($post->comments as $comment) { // ...}
همچنین میتوانید والد یک مدل فرزند چندشکلی را با دسترسی به نام روشی که فراخوانی را انجام میدهد، بازیابی کنید
morphTo
. در این مورد، این
commentable
روش روی
Comment
مدل است. بنابراین، برای دسترسی به مدل والد نظر، به آن متد به عنوان یک ویژگی رابطه پویا دسترسی خواهیم داشت:
use App\Models\Comment; $comment = Comment::find(1); $commentable = $comment->commentable;
بسته به نوع مدلی که والد نظر است،
رابطه
commentable
روی مدل یک
یا نمونه
Comment
برمیگرداند .
Post
Video
یکی از بسیاری (چند شکلی)
گاهی اوقات یک مدل ممکن است مدلهای مرتبط زیادی داشته باشد، اما شما میخواهید به راحتی «آخرین» یا «قدیمیترین» مدل مرتبط رابطه را بازیابی کنید. به عنوان مثال، یک
User
مدل ممکن است به بسیاری از
Image
مدلها مرتبط باشد، اما شما میخواهید روشی مناسب برای تعامل با جدیدترین تصویری که کاربر آپلود کرده است، تعریف کنید. شما می توانید این کار را با استفاده از
morphOne
نوع رابطه ترکیب شده با
ofMany
روش های زیر انجام دهید:
/** * Get the user's most recent image. */public function latestImage(): MorphOne{ return $this->morphOne(Image::class, 'imageable')->latestOfMany();}
به همین ترتیب، میتوانید روشی را برای بازیابی «قدیمیترین» یا اولین مدل مرتبط یک رابطه تعریف کنید:
/** * Get the user's oldest image. */public function oldestImage(): MorphOne{ return $this->morphOne(Image::class, 'imageable')->oldestOfMany();}
به طور پیشفرض، متدهای
latestOfMany
و
oldestOfMany
آخرین یا قدیمیترین مدل مرتبط را بر اساس کلید اصلی مدل، که باید قابل مرتبسازی باشد، بازیابی میکنند. با این حال، گاهی اوقات ممکن است بخواهید یک مدل واحد را از یک رابطه بزرگتر با استفاده از معیارهای مرتب سازی متفاوت بازیابی کنید.
به عنوان مثال، با استفاده از
ofMany
روش، ممکن است بیشترین "پسند" تصویر کاربر را بازیابی کنید. این
ofMany
متد ستون قابل مرتبسازی را بهعنوان اولین آرگومان خود میپذیرد و کدام تابع جمع (
min
یا
max
) را هنگام پرس و جو برای مدل مرتبط اعمال میکند:
/** * Get the user's most popular image. */public function bestImage(): MorphOne{ return $this->morphOne(Image::class, 'imageable')->ofMany('likes', 'max');}
ایجاد روابط پیشرفته تر "یکی از چندین" امکان پذیر است. برای کسب اطلاعات بیشتر، لطفاً به یکی از اسناد متعدد مراجعه کنید .
خیلی به خیلی ها (چند شکلی)
ساختار جدول
روابط چند شکلی خیلی به چند کمی پیچیده تر از روابط «مورف یک» و «مورف بسیاری» است. به عنوان مثال، یک
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 را فراخوانی می کند.
این
morphToMany
روش نام مدل مرتبط و همچنین "نام رابطه" را می پذیرد. بر اساس نامی که به نام جدول میانی خود اختصاص دادهایم و کلیدهایی که در آن وجود دارد، به این رابطه به عنوان "taggable" اشاره خواهیم کرد:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphToMany; class Post extends Model{ /** * Get all of the tags for the post. */ public function tags(): MorphToMany { return $this->morphToMany(Tag::class, 'taggable'); }}
تعریف معکوس رابطه
در مرحله بعد، روی
Tag
مدل، باید برای هر یک از مدلهای والد احتمالی آن، یک متد تعریف کنید. بنابراین در این مثال یک
posts
متد و یک
videos
متد را تعریف می کنیم. هر دوی این روش ها باید نتیجه روش را برگردانند
morphedByMany
.
این
morphedByMany
روش نام مدل مرتبط و همچنین "نام رابطه" را می پذیرد. بر اساس نامی که به نام جدول میانی خود اختصاص دادهایم و کلیدهایی که در آن وجود دارد، به این رابطه به عنوان "taggable" اشاره خواهیم کرد:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphToMany; class Tag extends Model{ /** * Get all of the posts that are assigned this tag. */ public function posts(): MorphToMany { return $this->morphedByMany(Post::class, 'taggable'); } /** * Get all of the videos that are assigned this tag. */ public function videos(): MorphToMany { return $this->morphedByMany(Video::class, 'taggable'); }}
بازیابی رابطه
هنگامی که جدول پایگاه داده و مدل های شما تعریف شد، می توانید از طریق مدل های خود به روابط دسترسی پیدا کنید. به عنوان مثال، برای دسترسی به تمام برچسبهای یک پست، میتوانید از
tags
ویژگی ارتباط پویا استفاده کنید:
use App\Models\Post; $post = Post::find(1); foreach ($post->tags as $tag) { // ...}
می توانید با دسترسی به نام روشی که فراخوانی را انجام می دهد، والد یک رابطه چند شکلی را از مدل فرزند چند شکلی بازیابی کنید
morphedByMany
. در این مورد، این
posts
یا
videos
متدهای موجود در
Tag
مدل است:
use App\Models\Tag; $tag = Tag::find(1); foreach ($tag->posts as $post) { // ...} foreach ($tag->videos as $video) { // ...}
انواع چند شکلی سفارشی
بهطور پیشفرض، لاراول از نام کلاس کاملاً واجد شرایط برای ذخیره «نوع» مدل مرتبط استفاده میکند. به عنوان مثال، با توجه به مثال رابطه یک به چند در بالا که در آن یک
Comment
مدل ممکن است به یک
Post
یا یک
Video
مدل تعلق داشته باشد، پیشفرض به ترتیب
یا یا
commentable_type
خواهد بود
. با این حال، ممکن است بخواهید این مقادیر را از ساختار داخلی برنامه خود جدا کنید.
App\Models\Post
App\Models\Video
به عنوان مثال، به جای استفاده از نام مدل به عنوان "نوع"، ممکن است از رشته های ساده مانند
post
و استفاده کنیم
video
. با انجام این کار، مقادیر ستون "نوع" چند شکلی در پایگاه داده ما، حتی اگر مدل ها تغییر نام داده شوند، معتبر می مانند:
use Illuminate\Database\Eloquent\Relations\Relation; Relation::enforceMorphMap([ 'post' => 'App\Models\Post', 'video' => 'App\Models\Video',]);
در صورت تمایل
می توانید
enforceMorphMap
متد را در
boot
متد کلاس خود فراخوانی کنید یا یک ارائه دهنده خدمات جداگانه ایجاد کنید.
App\Providers\AppServiceProvider
شما می توانید نام مستعار مورف یک مدل معین را در زمان اجرا با استفاده از روش مدل تعیین کنید
getMorphClass
. برعکس، میتوانید نام کلاس کاملاً واجد شرایط مرتبط با نام مستعار مورف را با استفاده از
Relation::getMorphedModel
روش تعیین کنید:
use Illuminate\Database\Eloquent\Relations\Relation; $alias = $post->getMorphClass(); $class = Relation::getMorphedModel($alias);
هنگام افزودن یک "نقشه مورف" به برنامه موجود خود، هر
*_type
مقدار ستون قابل تغییر در پایگاه داده شما که هنوز دارای یک کلاس کاملاً واجد شرایط است باید به نام "نقشه" آن تبدیل شود.
روابط پویا
می توانید از این
resolveRelationUsing
روش برای تعریف روابط بین مدل های Eloquent در زمان اجرا استفاده کنید. اگرچه معمولاً برای توسعه نرمافزارهای معمولی توصیه نمیشود، اما گاهی اوقات ممکن است هنگام توسعه بستههای لاراول مفید باشد.
متد
resolveRelationUsing
نام رابطه مورد نظر را به عنوان اولین آرگومان خود می پذیرد. آرگومان دومی که به متد ارسال میشود باید یک بسته باشد که نمونه مدل را میپذیرد و یک تعریف معتبر رابطه Eloquent را برمیگرداند. به طور معمول، باید روابط پویا را در روش بوت یک
ارائه دهنده خدمات
پیکربندی کنید :
use App\Models\Order;use App\Models\Customer; Order::resolveRelationUsing('customer', function (Order $orderModel) { return $orderModel->belongsTo(Customer::class, 'customer_id');});
هنگام تعریف روابط پویا، همیشه آرگومان های نام کلیدی صریح را برای روش های رابطه Eloquent ارائه دهید.
روابط پرس و جو
از آنجایی که تمام روابط Eloquent از طریق متدها تعریف میشوند، میتوانید آن متدها را برای به دست آوردن نمونهای از رابطه فراخوانی کنید، بدون اینکه واقعاً یک پرس و جو برای بارگذاری مدلهای مرتبط اجرا کنید. علاوه بر این، همه انواع روابط Eloquent نیز به عنوان سازندگان پرس و جو عمل می کنند ، و به شما این امکان را می دهند تا قبل از اجرای نهایی پرس و جو SQL در پایگاه داده خود، به زنجیره محدودیت ها در کوئری رابطه ادامه دهید.
به عنوان مثال، یک برنامه وبلاگ را تصور کنید که در آن یک
User
مدل دارای چندین
Post
مدل مرتبط است:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany; class User extends Model{ /** * Get all of the posts for the user. */ public function posts(): HasMany { return $this->hasMany(Post::class); }}
شما می توانید
posts
رابطه را پرس و جو کنید و محدودیت های اضافی را به این رابطه اضافه کنید:
use App\Models\User; $user = User::find(1); $user->posts()->where('active', 1)->get();
شما می توانید از هر یک از متدهای سازنده پرس و جو لاراول در رابطه استفاده کنید، پس حتما اسناد سازنده پرس و جو را بررسی کنید تا در مورد همه روش هایی که در دسترس شما هستند اطلاعات کسب کنید.
بندهای زنجیره ای
orWhere
بعد از روابط
همانطور که در مثال بالا نشان داده شد، شما می توانید در هنگام پرس و جوی روابط، محدودیت های اضافی را به آنها اضافه کنید. با این حال، هنگام زنجیر کردن
orWhere
جملات به یک رابطه احتیاط کنید، زیرا
orWhere
بندها به طور منطقی در همان سطح محدودیت رابطه گروه بندی می شوند:
$user->posts() ->where('active', 1) ->orWhere('votes', '>=', 100) ->get();
مثال بالا SQL زیر را تولید می کند. همانطور که می بینید، این بند به پرس و جو دستور می دهد تا
هر
پستی که بیش از 100 رای داشته باشد را
or
برگرداند .
پرس و جو دیگر محدود به یک کاربر خاص نیست:
select *from postswhere 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();
مثال بالا SQL زیر را تولید می کند. توجه داشته باشید که گروه بندی منطقی محدودیت ها را به درستی گروه بندی کرده است و پرس و جو برای یک کاربر خاص محدود می ماند:
select *from postswhere user_id = ? and (active = 1 or votes >= 100)
روش های رابطه در مقابل ویژگی های پویا
اگر نیازی به اضافه کردن محدودیتهای اضافی به پرس و جوی رابطه Eloquent ندارید، میتوانید به این رابطه مانند یک ویژگی دسترسی داشته باشید. برای مثال، با ادامه استفاده از مدلهای ما
User
و
Post
نمونه، ممکن است به همه پستهای کاربر مانند این دسترسی داشته باشیم:
use App\Models\User; $user = User::find(1); foreach ($user->posts as $post) { // ...}
ویژگی های رابطه پویا "بارگذاری تنبل" را انجام می دهند، به این معنی که آنها فقط زمانی که شما واقعا به آنها دسترسی داشته باشید، داده های رابطه خود را بارگذاری می کنند. به همین دلیل، توسعه دهندگان اغلب از بارگذاری مشتاق برای پیش بارگذاری روابطی استفاده می کنند که می دانند پس از بارگذاری مدل به آن دسترسی خواهند داشت. بارگذاری مشتاق کاهش قابل توجهی در پرس و جوهای SQL را فراهم می کند که باید برای بارگذاری روابط یک مدل اجرا شوند.
پرس و جو از وجود رابطه
هنگام بازیابی رکوردهای مدل، ممکن است بخواهید نتایج خود را بر اساس وجود یک رابطه محدود کنید. به عنوان مثال، تصور کنید می خواهید تمام پست های وبلاگی را که حداقل یک نظر دارند، بازیابی کنید. برای انجام این کار، می توانید نام رابطه را به
has
و
orHas
متدها ارسال کنید:
use App\Models\Post; // Retrieve all posts that have at least one comment...$posts = Post::has('comments')->get();
همچنین می توانید یک عملگر و مقدار شمارش را برای سفارشی کردن بیشتر پرس و جو تعیین کنید:
// Retrieve all posts that have three or more comments...$posts = Post::has('comments', '>=', 3)->get();
عبارات تودرتو
has
ممکن است با استفاده از نماد "نقطه" ساخته شوند. برای مثال، میتوانید تمام پستهایی را که حداقل یک نظر دارند که حداقل یک تصویر دارند، بازیابی کنید:
// Retrieve posts that have at least one comment with images...$posts = Post::has('comments.images')->get();
اگر حتی به قدرت بیشتری نیاز دارید، میتوانید از روشها
whereHas
و
orWhereHas
برای تعریف محدودیتهای پرس و جو اضافی در
has
جستارهای خود استفاده کنید، مانند بررسی محتوای یک نظر:
use Illuminate\Database\Eloquent\Builder; // Retrieve posts with at least one comment containing words like code%...$posts = Post::whereHas('comments', function (Builder $query) { $query->where('content', 'like', 'code%');})->get(); // Retrieve posts with at least ten comments containing words like code%...$posts = Post::whereHas('comments', function (Builder $query) { $query->where('content', 'like', 'code%');}, '>=', 10)->get();
Eloquent در حال حاضر از پرس و جو برای وجود رابطه در میان پایگاه های داده پشتیبانی نمی کند. روابط باید در یک پایگاه داده وجود داشته باشد.
پرس و جوهای وجود رابطه درون خطی
اگر می خواهید وجود یک رابطه را با یک شرط ساده و منفرد که به پرس و جوی رابطه متصل شده است، جستجو کنید، ممکن است استفاده از روش های، و، و را
whereRelation
راحت
orWhereRelation
تر
whereMorphRelation
بیابید
orWhereMorphRelation
. به عنوان مثال، ما ممکن است برای همه پست هایی که نظرات تایید نشده ای دارند، پرس و جو کنیم:
use App\Models\Post; $posts = Post::whereRelation('comments', 'is_approved', false)->get();
البته، مانند فراخوانیهای متد سازنده پرس و جو
where
، میتوانید یک اپراتور را نیز مشخص کنید:
$posts = Post::whereRelation( 'comments', 'created_at', '>=', now()->subHour())->get();
پرس و جو عدم وجود رابطه
هنگام بازیابی رکوردهای مدل، ممکن است بخواهید نتایج خود را بر اساس عدم وجود رابطه محدود کنید. به عنوان مثال، تصور کنید می خواهید تمام پست های وبلاگی را که
هیچ نظری ندارند،
بازیابی
کنید. برای انجام این کار، می توانید نام رابطه را به
doesntHave
و
orDoesntHave
متدها ارسال کنید:
use App\Models\Post; $posts = Post::doesntHave('comments')->get();
اگر حتی به قدرت بیشتری نیاز دارید، میتوانید از روشهای
whereDoesntHave
و
orWhereDoesntHave
برای افزودن محدودیتهای پرس و جو اضافی به
doesntHave
درخواستهای خود استفاده کنید، مانند بررسی محتوای یک نظر:
use Illuminate\Database\Eloquent\Builder; $posts = Post::whereDoesntHave('comments', function (Builder $query) { $query->where('content', 'like', 'code%');})->get();
می توانید از نماد "نقطه" برای اجرای یک پرس و جو در برابر یک رابطه تودرتو استفاده کنید. به عنوان مثال، پرس و جو زیر همه پست هایی را که نظر ندارند بازیابی می کند. با این حال، پست هایی که نظرات نویسندگانی دارند که ممنوع نشده اند در نتایج گنجانده می شوند:
use Illuminate\Database\Eloquent\Builder; $posts = Post::whereDoesntHave('comments.author', function (Builder $query) { $query->where('banned', 0);})->get();
پرس و جوی شکل به روابط
برای پرس و جو در مورد وجود روابط "morph to"، می توانید از روش
whereHasMorph
و استفاده کنید
whereDoesntHaveMorph
. این روش ها نام رابطه را به عنوان اولین استدلال خود می پذیرند. در مرحله بعد، متدها نام مدلهای مرتبطی را که میخواهید در پرس و جو قرار دهید، میپذیرند. در نهایت، میتوانید بستهای را ارائه کنید که پرس و جوی رابطه را سفارشی میکند:
use App\Models\Comment;use App\Models\Post;use App\Models\Video;use Illuminate\Database\Eloquent\Builder; // Retrieve comments associated to posts or videos with a title like code%...$comments = Comment::whereHasMorph( 'commentable', [Post::class, Video::class], function (Builder $query) { $query->where('title', 'like', 'code%'); })->get(); // Retrieve comments associated to posts with a title not like code%...$comments = Comment::whereDoesntHaveMorph( 'commentable', Post::class, function (Builder $query) { $query->where('title', 'like', 'code%'); })->get();
ممکن است گاهی نیاز به افزودن محدودیتهای پرس و جو بر اساس «نوع» مدل چندشکلی مرتبط داشته باشید. بسته شدن به
whereHasMorph
متد ممکن است یک
$type
مقدار را به عنوان آرگومان دوم خود دریافت کند. این آرگومان به شما امکان می دهد تا "نوع" پرس و جوی ساخته شده را بررسی کنید:
use Illuminate\Database\Eloquent\Builder; $comments = Comment::whereHasMorph( 'commentable', [Post::class, Video::class], function (Builder $query, string $type) { $column = $type === Post::class ? 'content' : 'title'; $query->where($column, 'like', 'code%'); })->get();
پرس و جو از همه مدل های مرتبط
به جای ارسال آرایهای از مدلهای چند شکلی ممکن، میتوانید
*
به عنوان یک مقدار عام ارائه دهید. این به لاراول دستور می دهد تا همه انواع چند شکلی ممکن را از پایگاه داده بازیابی کند. لاراول یک کوئری اضافی را برای انجام این عملیات اجرا می کند:
use Illuminate\Database\Eloquent\Builder; $comments = Comment::whereHasMorph('commentable', '*', function (Builder $query) { $query->where('title', 'like', 'foo%');})->get();
تجمیع مدل های مرتبط
شمارش مدل های مرتبط
گاهی اوقات ممکن است بخواهید تعداد مدل های مرتبط را برای یک رابطه مشخص بدون بارگذاری واقعی مدل ها بشمارید. برای انجام این کار، می توانید از
withCount
روش استفاده کنید. این روش یک
ویژگی را بر روی مدل های به دست آمده
withCount
قرار می دهد :
{relation}_count
use App\Models\Post; $posts = Post::withCount('comments')->get(); foreach ($posts as $post) { echo $post->comments_count;}
با ارسال یک آرایه به
withCount
متد، میتوانید «counts» را برای چندین رابطه اضافه کنید و همچنین محدودیتهای اضافی را به کوئریها اضافه کنید:
use Illuminate\Database\Eloquent\Builder; $posts = Post::withCount(['votes', 'comments' => function (Builder $query) { $query->where('content', 'like', 'code%');}])->get(); echo $posts[0]->votes_count;echo $posts[0]->comments_count;
همچنین میتوانید با نام مستعار نتیجه شمارش رابطه، شمارشهای متعدد در یک رابطه را مجاز کنید:
use Illuminate\Database\Eloquent\Builder; $posts = 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;
بارگیری تعداد معوق
با استفاده از این
loadCount
روش، میتوانید یک تعداد رابطه را پس از بازیابی مدل والد بارگیری کنید:
$book = Book::first(); $book->loadCount('genres');
اگر نیاز به تعیین محدودیتهای پرس و جو اضافی در پرس و جوی تعداد دارید، میتوانید آرایهای را ارسال کنید که توسط روابطی که میخواهید شمارش کنید، کلید میزنید. مقادیر آرایه باید بسته هایی باشند که نمونه سازنده query را دریافت می کنند:
$book->loadCount(['reviews' => function (Builder $query) { $query->where('rating', 5);}])
بیانیه های شمارش رابطه و انتخاب سفارشی
withCount
اگر با یک دستور
ترکیب میکنید ، مطمئن شوید که
بعد از متد
select
فراخوانی میکنید
:
withCount
select
$posts = Post::select(['title', 'body']) ->withCount('comments') ->get();
سایر توابع جمع
withCount
Eloquent
علاوه بر روش، روش
های , ,
withMin
,
withMax
و
را ارائه می دهد
. این روش ها یک
ویژگی را در مدل های به دست آمده شما
قرار می دهند :
withAvg
withSum
withExists
{relation}_{function}_{column}
use App\Models\Post; $posts = Post::withSum('comments', 'votes')->get(); foreach ($posts as $post) { echo $post->comments_sum_votes;}
اگر میخواهید با استفاده از نام دیگری به نتیجه تابع مجموع دسترسی پیدا کنید، میتوانید نام مستعار خود را مشخص کنید:
$posts = Post::withSum('comments as total_comments', 'votes')->get(); foreach ($posts as $post) { echo $post->total_comments;}
مانند
loadCount
روش، نسخه های معوق این روش ها نیز موجود است. این عملیات جمع اضافی ممکن است بر روی مدل های Eloquent که قبلاً بازیابی شده اند انجام شود:
$post = Post::first(); $post->loadSum('comments', 'votes');
اگر این متدهای انبوه را با یک دستور ترکیب می کنید
select
، مطمئن شوید که متدهای انبوه را بعد از
select
متد فراخوانی می کنید:
$posts = Post::select(['title', 'body']) ->withExists('comments') ->get();
شمارش مدلهای مرتبط در رابطههای Morph To
اگر میخواهید مشتاقانه یک رابطه «morph to» و همچنین تعداد مدلهای مرتبط برای موجودیتهای مختلفی را که ممکن است توسط آن رابطه برگردانده شوند بارگیری کنید، میتوانید از این
with
روش در ترکیب با روش
morphTo
رابطه استفاده کنید
morphWithCount
.
در این مثال، فرض می کنیم که
Photo
و
Post
مدل ها ممکن است
ActivityFeed
مدل هایی ایجاد کنند. فرض می کنیم که
ActivityFeed
مدل یک رابطه "morph to" به نام تعریف می کند
parentable
که به ما امکان می دهد والد
Photo
یا
Post
مدل را برای یک
ActivityFeed
نمونه معین بازیابی کنیم. علاوه بر این، فرض کنیم که
Photo
مدلها
Tag
مدلهای «بسیار» دارند و
Post
مدلها
Comment
مدلهای «بسیار» دارند.
حال، بیایید تصور کنیم که میخواهیم
ActivityFeed
نمونهها را بازیابی کنیم و مشتاقانه
parentable
مدلهای والد را برای هر
ActivityFeed
نمونه بارگذاری کنیم. علاوه بر این، میخواهیم تعداد برچسبهایی را که با هر عکس والدین مرتبط است و تعداد نظرات مرتبط با هر پست والدین را بازیابی کنیم:
use Illuminate\Database\Eloquent\Relations\MorphTo; $activities = ActivityFeed::with([ 'parentable' => function (MorphTo $morphTo) { $morphTo->morphWithCount([ Photo::class => ['tags'], Post::class => ['comments'], ]); }])->get();
بارگیری تعداد معوق
بیایید فرض کنیم قبلاً مجموعهای از
ActivityFeed
مدلها را بازیابی کردهایم و اکنون میخواهیم تعداد روابط تودرتو را برای
parentable
مدلهای مختلف مرتبط با فیدهای فعالیت بارگیری کنیم.
loadMorphCount
برای انجام این کار
می توانید از روش زیر استفاده کنید :
$activities = ActivityFeed::with('parentable')->get(); $activities->loadMorphCount('parentable', [ Photo::class => ['tags'], Post::class => ['comments'],]);
مشتاق بارگیری
هنگام دسترسی به روابط Eloquent به عنوان ویژگی، مدل های مرتبط "بارگذاری تنبل" هستند. این بدان معنی است که تا زمانی که شما برای اولین بار به ویژگی دسترسی نداشته باشید، داده های رابطه در واقع بارگذاری نمی شوند. با این حال، Eloquent میتواند روابط را در زمانی که مدل والد را پرس و جو میکنید، «بارگیری کند». بارگیری مشتاق مشکل پرس و جو "N + 1" را کاهش می دهد. برای نشان دادن مشکل پرس و جو N + 1،
Book
مدلی را در نظر بگیرید که به یک
Author
مدل "متعلق دارد":
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; class Book extends Model{ /** * Get the author that wrote the book. */ public function author(): BelongsTo { return $this->belongsTo(Author::class); }}
اکنون بیایید همه کتاب ها و نویسندگان آنها را بازیابی کنیم:
use App\Models\Book; $books = Book::all(); foreach ($books as $book) { echo $book->author->name;}
این حلقه یک پرس و جو را برای بازیابی همه کتاب های موجود در جدول پایگاه داده و سپس یک پرس و جو برای هر کتاب به منظور بازیابی نویسنده کتاب اجرا می کند. بنابراین، اگر 25 کتاب داشته باشیم، کد بالا 26 پرس و جو را اجرا می کند: یکی برای کتاب اصلی، و 25 درخواست اضافی برای بازیابی نویسنده هر کتاب.
خوشبختانه، ما می توانیم از بارگذاری مشتاق برای کاهش این عملیات به تنها دو پرس و جو استفاده کنیم. هنگام ساخت یک پرس و جو، می توانید مشخص کنید که کدام روابط باید با استفاده از روش بارگذاری شوند
with
:
$books = 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 = Book::with(['author', 'publisher'])->get();
Nested Eager Loading
برای بارگذاری مشتاقانه روابط یک رابطه، می توانید از نحو "نقطه" استفاده کنید. برای مثال، بیایید مشتاقانه همه نویسندگان کتاب و همه مخاطبین شخصی نویسنده را بارگیری کنیم:
$books = Book::with('author.contacts')->get();
همچنین، میتوانید با ارائه یک آرایه تودرتو به روش، روابط بارگذاری شده تودرتو را مشخص کنید
with
، که میتواند هنگام بارگیری چندین رابطه تودرتو راحت باشد:
$books = Book::with([ 'author' => [ 'contacts', 'publisher', ],])->get();
morphTo
روابط
بارگیری مشتاق تو در تو
اگر میخواهید مشتاقانه یک
morphTo
رابطه و همچنین روابط تودرتو در موجودیتهای مختلفی را که ممکن است توسط آن رابطه برگردانده شوند بارگذاری کنید، میتوانید از این
with
روش در ترکیب با روش
morphTo
رابطه استفاده کنید
morphWith
. برای کمک به توضیح این روش، بیایید مدل زیر را در نظر بگیریم:
<?php use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphTo; class ActivityFeed extends Model{ /** * Get the parent of the activity feed record. */ public function parentable(): MorphTo { 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 = Book::with('author:id,name,book_id')->get();
هنگام استفاده از این ویژگی، همیشه باید
id
ستون و هر ستون کلید خارجی مربوطه را در لیست ستون هایی که می خواهید بازیابی کنید، قرار دهید.
بارگیری مشتاق به صورت پیش فرض
گاهی اوقات ممکن است بخواهید همیشه برخی از روابط را هنگام بازیابی یک مدل بارگیری کنید. برای انجام این کار، می توانید یک
$with
ویژگی را در مدل تعریف کنید:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; 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(): BelongsTo { return $this->belongsTo(Author::class); } /** * Get the genre of the book. */ public function genre(): BelongsTo { return $this->belongsTo(Genre::class); }}
اگر می خواهید
$with
برای یک پرس و جو، موردی را از ویژگی حذف کنید، می توانید از
without
روش زیر استفاده کنید:
$books = Book::without('author')->get();
اگر میخواهید همه آیتمهای داخل
$with
ویژگی را برای یک پرسوجو لغو کنید، میتوانید از
withOnly
روش زیر استفاده کنید:
$books = Book::withOnly('genre')->get();
محدود کردن بارهای مشتاق
گاهی اوقات ممکن است بخواهید مشتاقانه یک رابطه را بارگیری کنید، اما همچنین شرایط پرس و جو اضافی را برای درخواست بارگیری مشتاق مشخص کنید. شما می توانید این کار را با ارسال یک آرایه از روابط به
with
روشی انجام دهید که در آن کلید آرایه یک نام رابطه است و مقدار آرایه یک بسته است که محدودیت های اضافی را به درخواست بارگیری مشتاق اضافه می کند:
use App\Models\User;use Illuminate\Contracts\Database\Eloquent\Builder; $users = User::with(['posts' => function (Builder $query) { $query->where('title', 'like', '%code%');}])->get();
در این مثال، Eloquent فقط مشتاقانه پستهایی را بارگذاری میکند که ستون پست
title
حاوی کلمه باشد
code
.
برای سفارشی کردن بیشتر عملیات بارگذاری مشتاق،
می توانید سایر روش های
سازنده پرس و جو را فراخوانی کنید:
$users = User::with(['posts' => function (Builder $query) { $query->orderBy('created_at', 'desc');}])->get();
بارگذاری مشتاق محدود
morphTo
روابط
اگر مشتاق بارگیری یک رابطه هستید
morphTo
، Eloquent چندین پرسوجو را برای واکشی هر نوع مدل مرتبط اجرا میکند. می توانید با استفاده از روش
MorphTo
رابطه ، محدودیت های اضافی را به هر یک از این پرس و جوها اضافه کنید
constrain
:
use Illuminate\Database\Eloquent\Relations\MorphTo; $comments = Comment::with(['commentable' => function (MorphTo $morphTo) { $morphTo->constrain([ Post::class => function ($query) { $query->whereNull('hidden_at'); }, Video::class => function ($query) { $query->where('type', 'educational'); }, ]);}])->get();
در این مثال، Eloquent فقط مشتاقانه پست هایی را بارگذاری می کند که پنهان نشده اند و ویدیوهایی که دارای
type
ارزش "آموزشی" هستند.
محدود کردن بارهای مشتاق با وجود رابطه
ممکن است گاهی اوقات نیاز به بررسی وجود یک رابطه داشته باشید در حالی که به طور همزمان رابطه را بر اساس همان شرایط بارگذاری می کنید. برای مثال، ممکن است بخواهید فقط
User
مدلهایی را بازیابی کنید که دارای
Post
مدلهای فرزندی هستند که با شرایط پرسوجو مطابقت دارند و در عین حال مشتاق بارگیری پستهای منطبق هستند. شما می توانید این کار را با استفاده از
withWhereHas
روش زیر انجام دهید:
use App\Models\User; $users = User::withWhereHas('posts', function ($query) { $query->where('featured', true);})->get();
تنبل مشتاق بارگیری
گاهی اوقات ممکن است نیاز داشته باشید که مشتاقانه یک رابطه را پس از بازیابی مدل والد بارگیری کنید. برای مثال، اگر بخواهید به صورت پویا تصمیم بگیرید که آیا مدلهای مرتبط را بارگیری کنید، این ممکن است مفید باشد:
use App\Models\Book; $books = Book::all(); if ($someCondition) { $books->load('author', 'publisher');}
اگر نیاز به تعیین محدودیتهای پرس و جو اضافی در پرسوجوی بارگیری مشتاق دارید، میتوانید آرایهای را ارسال کنید که توسط روابطی که میخواهید بارگیری کنید کلید خورده است. مقادیر آرایه باید نمونه های بسته شدنی باشند که نمونه پرس و جو را دریافت می کنند:
$author->load(['books' => function (Builder $query) { $query->orderBy('published_date', 'asc');}]);
برای بارگیری یک رابطه فقط زمانی که قبلاً بارگذاری نشده باشد، از
loadMissing
روش استفاده کنید:
$book->loadMissing('author');
Nested Lazy Eager Loading و
morphTo
اگر میخواهید مشتاقانه یک
morphTo
رابطه و همچنین روابط تودرتو در موجودیتهای مختلفی که ممکن است توسط آن رابطه برگردانده شوند بارگذاری کنید، میتوانید از این
loadMorph
روش استفاده کنید.
این روش نام
morphTo
رابطه را به عنوان اولین آرگومان خود و آرایه ای از جفت های مدل / رابطه را به عنوان آرگومان دوم می پذیرد. برای کمک به توضیح این روش، بیایید مدل زیر را در نظر بگیریم:
<?php use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\MorphTo; class ActivityFeed extends Model{ /** * Get the parent of the activity feed record. */ public function parentable(): MorphTo { 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'], ]);
جلوگیری از بارگذاری تنبل
همانطور که قبلاً بحث شد، روابط بارگذاری مشتاق اغلب می تواند مزایای عملکرد قابل توجهی را برای برنامه شما فراهم کند. بنابراین، در صورت تمایل، می توانید به لاراول دستور دهید که همیشه از بارگذاری تنبل روابط جلوگیری کند. برای انجام این کار، می توانید
preventLazyLoading
روش ارائه شده توسط کلاس مدل پایه Eloquent را فراخوانی کنید. به طور معمول، شما باید این متد را در
boot
متد کلاس برنامه خود فراخوانی کنید
AppServiceProvider
.
این
preventLazyLoading
روش یک آرگومان بولی اختیاری را می پذیرد که نشان می دهد آیا باید از بارگذاری تنبل جلوگیری شود. به عنوان مثال، ممکن است بخواهید فقط بارگذاری تنبل را در محیط های غیر تولیدی غیرفعال کنید تا محیط تولید شما به طور عادی به کار خود ادامه دهد، حتی اگر یک رابطه بارگذاری تنبل به طور تصادفی در کد تولید وجود داشته باشد:
use Illuminate\Database\Eloquent\Model; /** * Bootstrap any application services. */public function boot(): void{ Model::preventLazyLoading(! $this->app->isProduction());}
Illuminate\Database\LazyLoadingViolationException
پس از جلوگیری از بارگذاری تنبل، Eloquent زمانی که برنامه شما تلاش می کند هر رابطه Eloquent را تنبل بارگذاری کند، استثنا
ایجاد می کند .
میتوانید با استفاده از این روش، رفتار نقض بارگذاری تنبل را سفارشی کنید
handleLazyLoadingViolationsUsing
. برای مثال، با استفاده از این روش، میتوانید به نقضهای بارگذاری تنبل دستور دهید به جای قطع کردن اجرای برنامه با استثنائات، فقط ثبت شوند:
Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) { $class = $model::class; info("Attempted to lazy load [{$relation}] on model [{$class}].");});
درج و به روز رسانی مدل های مرتبط
روش
save
Eloquent روش های مناسبی را برای افزودن مدل های جدید به روابط ارائه می دهد. به عنوان مثال، شاید لازم باشد یک نظر جدید به یک پست اضافه کنید. به جای تنظیم دستی
post_id
ویژگی روی
Comment
مدل، میتوانید نظر را با استفاده از روش رابطه وارد کنید
save
:
use App\Models\Comment;use App\Models\Post; $comment = new Comment(['message' => 'A new comment.']); $post = Post::find(1); $post->comments()->save($comment);
comments
توجه داشته باشید که ما به رابطه به عنوان یک ویژگی پویا
دسترسی نداشتیم . در عوض،
comments
روش را برای به دست آوردن یک نمونه از رابطه
فراخوانی کردیم .
این
save
روش به طور خودکار مقدار مناسب را
post_id
به
Comment
مدل جدید اضافه می کند.
اگر نیاز به ذخیره چندین مدل مرتبط دارید، می توانید از
saveMany
روش زیر استفاده کنید:
$post = Post::find(1); $post->comments()->saveMany([ new Comment(['message' => 'A new comment.']), new Comment(['message' => 'Another new comment.']),]);
متدهای
save
و
saveMany
نمونههای مدل دادهشده را حفظ میکنند، اما مدلهای تازه تداومشده را به هیچیک از روابط درون حافظهای که قبلاً روی مدل والد بارگذاری شدهاند اضافه نمیکنند. اگر قصد دارید پس از استفاده از روش
save
یا به رابطه دسترسی پیدا کنید
saveMany
، ممکن است بخواهید از
refresh
روش برای بارگذاری مجدد مدل و روابط آن استفاده کنید:
$post->comments()->save($comment); $post->refresh(); // All comments, including the newly saved comment...$post->comments;
ذخیره بازگشتی مدل ها و روابط
اگر مایل به
save
مدل خود و همه روابط مرتبط با آن هستید، می توانید از
push
روش استفاده کنید. در این مثال،
Post
مدل و همچنین نظرات آن و نویسندگان نظر ذخیره می شود:
$post = Post::find(1); $post->comments[0]->message = 'Message';$post->comments[0]->author->name = 'Author Name'; $post->push();
این
pushQuietly
روش ممکن است برای ذخیره یک مدل و روابط مرتبط با آن بدون ایجاد هیچ رویدادی استفاده شود:
$post->pushQuietly();
روش
create
علاوه بر متدهای
save
و
saveMany
، میتوانید از
create
روشی نیز استفاده کنید که آرایهای از ویژگیها را میپذیرد، یک مدل ایجاد میکند و آن را در پایگاه داده قرار میدهد. تفاوت بین
save
و
create
این است که
save
یک نمونه مدل کامل Eloquent را می پذیرد در حالی که
create
یک PHP ساده را می پذیرد
array
. مدل جدید ایجاد شده با
create
روش زیر برگردانده می شود:
use App\Models\Post; $post = Post::find(1); $comment = $post->comments()->create([ 'message' => 'A new comment.',]);
می توانید از
createMany
روش برای ایجاد چندین مدل مرتبط استفاده کنید:
$post = Post::find(1); $post->comments()->createMany([ ['message' => 'A new comment.'], ['message' => 'Another new comment.'],]);
متدهای
createQuietly
و
createManyQuietly
ممکن است برای ایجاد یک مدل(ها) بدون ارسال هیچ رویدادی استفاده شوند:
$user = User::find(1); $user->posts()->createQuietly([ 'title' => 'Post title.',]); $user->posts()->createManyQuietly([ ['title' => 'First post.'], ['title' => 'Second post.'],]);
همچنین می توانید از روش های
findOrNew
,
firstOrNew
,
firstOrCreate
, و
updateOrCreate
برای
ایجاد و به روز رسانی مدل های روابط
استفاده کنید .
قبل از استفاده از
create
روش، حتما اسناد انتساب انبوه را بررسی کنید .
متعلق به روابط است
اگر می خواهید یک مدل فرزند را به یک مدل والد جدید اختصاص دهید، می توانید از این
associate
روش استفاده کنید. در این مثال، مدل
رابطه ای را با مدل
User
تعریف می کند
. این
روش کلید خارجی را در مدل فرزند تنظیم می کند:
belongsTo
Account
associate
use App\Models\Account; $account = Account::find(10); $user->account()->associate($account); $user->save();
برای حذف مدل والد از مدل فرزند، میتوانید از این
dissociate
روش استفاده کنید. این روش کلید خارجی رابطه را به صورت زیر تنظیم می کند
null
:
$user->account()->dissociate(); $user->save();
روابط بسیار به بسیاری
پیوست کردن / جدا کردن
Eloquent همچنین روشهایی را برای راحتتر کردن کار با روابط چند به چند ارائه میکند. به عنوان مثال، بیایید تصور کنیم یک کاربر می تواند نقش های زیادی داشته باشد و یک نقش می تواند کاربران زیادی داشته باشد. میتوانید از این
attach
روش برای پیوست کردن یک نقش به کاربر با درج یک رکورد در جدول میانی رابطه استفاده کنید:
use App\Models\User; $user = 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 = 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]);
اگر میخواهید همان مقادیر جدول میانی را با هر یک از شناسههای مدل همگامسازی شده درج کنید، میتوانید از
syncWithPivotValues
روش زیر استفاده کنید:
$user->roles()->syncWithPivotValues([1, 2, 3], ['active' => true]);
اگر نمیخواهید شناسههای موجود را که در آرایه داده شده وجود ندارد جدا کنید، میتوانید از
syncWithoutDetaching
روش زیر استفاده کنید:
$user->roles()->syncWithoutDetaching([1, 2, 3]);
تضعیف انجمن ها
رابطه چند به چند نیز
toggle
روشی را ارائه میکند که وضعیت پیوست شناسههای مدل مرتبط را تغییر میدهد. اگر شناسه داده شده در حال حاضر پیوست باشد، جدا می شود. به همین ترتیب، اگر در حال حاضر جدا شده باشد، پیوست خواهد شد:
$user->roles()->toggle([1, 2, 3]);
همچنین می توانید مقادیر جدول میانی اضافی را با شناسه ها ارسال کنید:
$user->roles()->toggle([ 1 => ['expires' => true], 2 => ['expires' => true],]);
به روز رسانی یک رکورد در جدول میانی
اگر نیاز دارید یک ردیف موجود در جدول میانی رابطه خود را به روز کنید، می توانید از این
updateExistingPivot
روش استفاده کنید. این روش کلید خارجی رکورد میانی و آرایه ای از ویژگی ها را برای به روز رسانی می پذیرد:
$user = User::find(1); $user->roles()->updateExistingPivot($roleId, [ 'active' => false,]);
لمس کردن مهر زمانی والدین
هنگامی که یک مدل یک
belongsTo
یا
belongsToMany
رابطه ای را با مدل دیگری تعریف می کند، مانند مدلی
Comment
که متعلق به یک است
Post
، گاهی اوقات هنگام به روز رسانی مدل فرزند، به روز رسانی مهر زمانی والدین مفید است.
به عنوان مثال، هنگامی که یک
Comment
مدل به روز می شود، ممکن است بخواهید به طور خودکار
updated_at
مهر زمانی مالکیت را "لمس" کنید
Post
تا روی تاریخ و زمان فعلی تنظیم شود. برای انجام این کار، می توانید یک
touches
ویژگی به مدل فرزند خود اضافه کنید که حاوی نام روابط است که باید
updated_at
زمانی که مدل فرزند به روز می شود، مهر زمانی آنها به روز شود:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; 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(): BelongsTo { return $this->belongsTo(Post::class); }}
مهر زمانی مدل والد تنها در صورتی به روز می شود که مدل فرزند با استفاده از روش Eloquent به روز شود
save
.