روابط polymorphic در لاراول

حمید تیموری 2468 بازدید 1397/12/04
روابط polymorphic در لاراول

برای توضیح این مطلب، یک مثال میزنم:
فکر کنید که 2 تا مدل داریم به اسم Page و Video که هر دو، Comment دارند.
فرض کنید دیتابیس به صورت زیر است:

// post table
posts:
  id
  title
  content

// comments of post 
posts_comments:
  id
  post_id
  comment
  date
  



// video table
videos:
  id
  title

// comments of videos  
videos_comments:
  id
  video_id
  comment
  date

در طراحی بالا، دو جدول وجود دارد که کار یکسانی انجام میدهند، اما بعضی از فیلدها متفاوت هستند
هرکدام comment ها را ذخیره میکنند ولی تنها تفاوت در ID موجودیتی است که comment متعلق به آن بوده است.
هر دو موجودیت post و video میتوانند تعداد زیادی comment داشته باشند.

 

با استفاده از رابطه polymorphic میتوانیم خیلی راحت تر و تمیزتر این کار را انجام دهیم.
به ساختار زیر دقت کنید:

posts:
  id
  title
  content
  
videos:
  id
  title
  
comments:
  id
  commentable_id
  commentable_type
  date

در جدول نظرات، دو ستون مهم داریم که مشاهده میکنید.
در واقع ما دوتا جدول videos_comments و posts_comments را  ادغام کردیم و یک جدول نظرات ساختیم.
به جای ستونهای post_id و video_id از ستون commentable_id استفاده شده است و 
فیلد commentable_type اشاره به مدلی یا جدولی میکند که commnet به آن تعلق دارد.

برای مثال اگر video یک نظر ثبت شود، فیلد commantable_type به صورت 'App\Video' پر میشود.

به migration زیر دقت کنید:

Schema::create('posts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->text('content');
});

Schema::create('videos', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
});

Schema::create('comments', function (Blueprint $table) {
    $table->increments('id');
    $table->morphs(‘comment’);
    $table->date('body');
});


ستون morph در کد بالا، به صورت اتوماتیک دو فیلد در جدول میسازد که ترکیبی از اسم ستونی که به آن پاس داده شده است و type و id و همچنین از کلمه able است.

 comment + able + _type => commentable_type
 comment + able + _id   => commentable_id

حالا مدل ها را میسازیم:

<?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(Comment::class, 'commentable');
    }
}
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{

    /**
     * Get all of the video's comments.
     */
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

در دو مدل بالا، با استفاده از morphMany میتوان رابطه را با مدل Comment برقرار کرد، دقت کنید که پارامتر دوم این متد، نام فیلدی است که در دیتابیس هم استفاده شده است.

commentable + _type = commentable_type
commentable + _id   = commentable_id

مدل Comment به شرح زیر است:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{


    /**
     * Get all of the models that own comments.
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

مدل Comment رابطه ای به نام commentable دارد که به صورت morphTo پیاده شده است، یعنی با هر مدل دیگری میتواند رابطه برقرار کند.
بنابراین به هیچ اسمی از مدل های دیگر نیازی نیست که اشاره شود.

طریقه ی استفاده از این relation شبیه به oneToMany است:

$video = Video::find(1);

foreach($video->comment as $comment)
{
    // working with comment here...
}

با نوشتن کد زیر میتوانید از comment به مدلی برسید که comment برای آن ذخیره شده است:

$comment = Comment::find(15);

// getting the model...
var_dump($comment->commentable);


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


اگر سوالی داشتید از قسمت نظرات میتونید بپرسید.

دیگر مقالات
امید کیانی 3010 بازدید 1398/07/20
حمید تیموری 1133 بازدید 1398/01/14
حمید تیموری 1209 بازدید 1398/02/23
حمید تیموری 1368 بازدید 1397/12/13
حمید تیموری 1380 بازدید 1397/05/07


نظرات (3)
rouhollah kamaneh azari
1399/12/20 - 02:41
با سلام خیلی عالی بود. فقط اگر بخوایم کلید خارجی هم بکنیم کلید خارجی نمیشه کرد که به دوتا جدول...درسته شنیدم استفاده از مدل ها ما رو بی نیاز میکنه از کلید خارجی ولی بازم اگر من اصرار به استفاده از کلید خارجی داشته باشم راهش چیه؟ منظورم در مورد ارتباط پلی مورفیک هست که چطور فیلد commentable_id رو از یکطرف به id جدول videos و از طرف دیگر به id جدول posts کلید خارجی کنم؟
hashem shafai
1399/03/08 - 21:14
ممنون عالی بود
فقط مربوط به کدوم نسخه از لاراول بود ؟
حمید تیموری
1399/03/09 - 19:26
خواهش میکنم. تفاوتی نمیکنه تو همه نسخه ها به همین شکله.
برای ثبت نظر ابتدا وارد سایت شوید