ارتباط 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 نام کلاسی که کامنت مورد نظر متعلق به اونه رو قرار میده مثلا AppPage یا AppPost.

پس تا الان ۳ تا موجودی داریم:

پست 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 IlluminateDatabaseEloquentModel;

class Post extends Model
{
    /**
     * Get all of the post's comments.
     */
    public function comments()
    {
        return $this->morphMany('AppComment', 'comment');
    }
}


//file: app/Page.php
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

class Page extends Model
{
    /**
     * Get all of the page's comments.
     */
    public function comments()
    {
        return $this->morphMany('AppComment', 'comment');
    }
}

//file: app/Comment.php
<?php

namespace App;

use IlluminateDatabaseEloquentModel;

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

منبع:

Polymorphic relationships in Laravel and their use cases

نوشته ارتباط morph در لاراول +‌ همراه با مثال اولین بار در ویرگول پدیدار شد.

گردآوری توسط ایده طلایی

دیدگاهتان را بنویسید