ارتباط morph در لاراول + همراه با مثال
خیلی مواقع پیش میاد که مدل ما با بیش از یک موجودی ارتباط داره مثلا ما یک بلاگ داریم که شامل دو بخش page و posts هست و برای هر کدوم هم کاربر میتونه comment بزاره.
اگر بخواهیم از ساختار های معمول استفاده کنیم, ساختار دیتابیس ما به صورت زیر میشه:
posts:
id
title
content
posts_comments:
id
post_id
comment
date
pages:
id
body
pages_comments:
id
page_id
comment
date
الان توی این ساختار ما ۲ تا table داریم که هر کدوم به یک موجودی جدا اشاره میکنند, برای جلوگیری از این کار و انجام یه راهحل بهتر ما میتونیم از ارتباط Polymorphic استفاده کنیم.
با استفاده از این متد ما میتونیم یه ساختار دیتابیس تمیزتر به صورت زیر داشته باشیم:
posts:
id
title
content
pages:
id
body
comments:
id
comment_id
comment_type
date
body
وقتی با کد این ارتباط رو ایجاد کنیم (جلوتر بهش میرسیم) دو تا table خیلی مهم توی دیتابیس برامون ساخته میشه به اسم comment_id و comment_type. حالا در comment_id آیدی page یا post مورد نظر قرار میگیره و در comment_type نام کلاسی که کامنت مورد نظر متعلق به اونه رو قرار میده مثلا App\Page یا App\Post.
پس تا الان ۳ تا موجودی داریم:
پست Post که میتونه comment داشته باشه.
پیج Page که میتونه comment داشته باشه.
کامنت Comment که میتونه مربوط به Page یا Post.
بریم برای اجرای عملی
از ساخت migration ها شروع میکنیم:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('content');
});
Schema::create('pages', function (Blueprint $table) {
$table->increments('id');
$table->text('body');
});
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->morphs(‘comment’);
$table->text('body');
$table->date('date');
});
ساختار Model های ما هم بصورت زیر میشه:
//file: app/Post.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'comment');
}
}
//file: app/Page.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
/**
* Get all of the page's comments.
*/
public function comments()
{
return $this->morphMany('App\Comment', 'comment');
}
}
//file: app/Comment.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get all of the models that own comments.
*/
public function commenModels()
{
return $this->morphTo();
}
}
توی کد با از morphMany و morphTo استفاده میکنیم که به ما توی ایجاد این ارتباط کمک میکنه.
هم page و post ما میتونن comment داشته باشن و متد morphMany به ما comment های مربوط به اونها رو میده.
در مدل Comment هم که از morphTo استاده کردیم, تمام مدل هایی که comment دارن رو به ما برمیگردونه.
دیگه کجاها میتونی از morph استفاده کنیم؟
برای مثال یک سناریو دیگه زمانی هست که ما user های متفاوتی داریم مثلا یکی admin یکی driver و یکی user عادی هست. با این ساختار دیتابیس:
user:
id
name
email
avatar
address
phone
experience
userable_id
userable_type
drivers:
id
region
car_type //manual or automatic
long_distance_drive
admin:
id
permissions
...
و هر جای دیگه ای که یک موجودی ما مربوط به چندین موجودی هست میتونیم از این ارتباط استفاده کنیم.
موفق باشید.
لینک های مرتبط:
https://laravel.com/docs/8.x/eloquent-relationships
منبع:
https://blog.logrocket.com/polymorphic-relationships-in-laravel/
مطلبی دیگر از این انتشارات
نظرت در مورد جامعه توسعه دهندگان لاراول چیه ؟
مطلبی دیگر از این انتشارات
داکر - لاراول
مطلبی دیگر از این انتشارات
طراحی سطوح دسترسی در لاراول