درود خدمت شما عزیزان و همراهان گرامی، با مطالعه و بررسی فصل ۱۲-۱ با اسامی انواع روابط در مدلها و جداول آشنا شدید. اما تنها سه نوع رابطهی یک به یک، یک به چند، چند به چند را بررسی کردیم. حال در این فصل به ادامه روابط پرداخته و سه نوع دیگر را که تخصصی و پیشرفتهتر هستند مورد ارزیابی قرار میدهیم. با ما همراه باشید.
این رابطه یک میانبر کوتاه برای دسترسی به روابط دورتر توسط یک رابطهی میانی، ایجاد میکند. برای توضیح این نوع رابطه یک مثال میزنیم. فرض کنید میخواهیم تعداد پستهایی که کاربران یک کشور قرار دادهاند را در دسترس داشته باشیم. برای اینکار یک مدل به نام Country داریم که باید یک رابطهی یک به چند با مدل Post برقرار کند اما این وسط یک مدل به نام User وجود دارد که تعداد پستهای هر کاربر را مشخص میکند و یک کاربر دارای چندین پست میباشد. بنابراین یک رابطهی یک به چند دیگر بین کاربر و پستها برقرار است. برای روشن شدن این موضوع به عبارات زیر توجه کنید:
countries id - integer name - string users id - integer country_id - integer name - string posts id - integer user_id - integer title - string
بنابراین هر کاربر علاوه بر اینکه چندین پست دارد، متعلق به یک کشور است. در اینجا مدل User به عنوان یک مدل میانی یا رابطهی میانی معرفی میشود. چون جدول posts ستونی به نام country_id ندارد بلکه به واسطهی جدول users به این ستون دسترسی پیدا میکند. این رابطه توسط متد hasManyThrough معرفی میشود. که اجازه میدهد پستهای یک کشور توسط دستور country->posts$ قابل دسترسی است. این کوئری بدین صورت اجرا میشود که Eloquent ابتدا ستون country_id را درون جدول users پیدا میکند سپس id هر کاربر را درون ستون user_id در جدول posts بررسی کرده و پس از تطبیق آن را نمایش میدهد. حال برای تکمیل کردن مثال فوق ابتدا فایل Country.php را ایجاد کرده و سپس درون آن متد posts را به صورت زیر مینویسیم:
<?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 را پر کرد. آرگومان سوم نام کلید خارجی در مدل میانی است و آرگومان چهارم نام کلید خارجی در مدلی است که در نهایت با آن رابطه خواهیم داشت. همچنین کلید اصلی را هم میتوان با ارسال آرگومان پنجم در مدل Country تغییر داد (این کلید به صورت پیش فرض id نام دارد)
class Country extends Model { public function posts() { return $this->hasManyThrough( 'App\Post', 'App\User', 'country_id', 'user_id', 'id' ); } }
ساختار جداول
روابط یک به چند پلی مورفیک به مدل اجازه میدهد که با بیش از یک مدل روابط belongsTo ایجاد کند. یعنی به صورت همزمان و در یک ارتباط با چندین مدل دیگر رابطه " ۱ " داشته باشد. مطابق روشهای قبلی باید با یک مثال شما را آشنا کرده تا مفهوم را به دقت درک کنید. فرض کنید کاربران وب سایت شما میتوانند در هر دو بخش پستها و ویدیوها نظر بگذارند. ما اینجا چندین مدل داریم User, Comment, Post, Video. با استفاده از رابطه پلی مورفیک میتوان یک جدول comments را در هر دو جدول posts و videos استفاده کرد. ابتدا ساختار جداول را میکشیم:
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
جداول posts و videos که مشخص هستند و ابهامی در آنها وجود ندارد اما در جدول comments دو ستون بسیار ارزشمند و مهم تحت عناوین commentable_id و commentable_type وجود دارند. ستون commentable_id یک ID از ویدیو یا پست را در خود ذخیره میکند درحالیکه commentable_type شامل نام مدلی است که جدول comments با آن ارتباط برقرار میکند. مثلا اگر بخواهیم نظرات مرتبط با یک پست را که آی دی آن ۴۵۳ است را استخراج کنیم مقدار commentable_id برابر ۴۵۳ و مقدار commentable_type برابر Post خواهد بود.
ساختار مدل
بنابراین جدول comments را باید به صورت زیر تعریف کنیم:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Comment extends Model { /** * Get all of the owning commentable models. */ public function commentable() { return $this->morphTo(); } }
برای مدل Post خواهیم داشت:
<?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', 'commentable'); } }
همچنین برای مدل Video داریم:
class Video extends Model { /** * Get all of the video's comments. */ public function comments() { return $this->morphMany('App\Comment', 'commentable'); } }
بازیابی اطلاعات از روابط پلی مورفیک
پس از اینکه مدلها و جداول دیتابیس تعریف شدند دسترسی به این روابط و اطلاعات درون آنها بسیار ساده میشود. برای نمونه، جهت دستیابی به نظرات یک پست باید ابتدا id پست را پیدا کرده و سپس از ویژگی پویای comments استفاده کنیم:
$post = App\Post::find(1); foreach ($post->comments as $comment) { // }
همچنین برای استخراج نام مدل موردنظر که از رابطهی پلی مورفیک استفاده میکند میتوان از متد commentable استفاده کرد. یعنی در حالت کلی متدی که از ساختار morphTo استفاده کرده است. بنابراین داریم:
$comment = App\Comment::find(1); $commentable = $comment->commentable;
در مثال فوق بررسی کردهایم که یک دیدگاه با id =1 با چه نوع مدل ذخیره شده است ( مثلا Post یا Video).
انواع دلخواه پلی مورفیک
در حالت پیشفرض، لاراول نام کلاس مدل را به عنوان type در جدول ذخیره میکند. به عنوان نمونه، در مثال بالا مدل Comment با مدلهای Post و Video رابطه یک به چند داشته و به صورت پیشفرض ستون commentable_type دارای مقادیر App\Post و App\Video است. همانطور که ملاحظه میکنید در این حالت پایگاه داده وابسته به مسیر App است و اگر پوشه شما تغییری داشته باشد هیچ اطلاعاتی در دسترس نخواهد بود. بنابراین برای جداسازی پایگاه داده از مسیر نرم افزاری باید یک morph map تعریف کرد تا نام دلخواهی را به جای مدلها در دیتابیس ذخیره کنیم:
use Illuminate\Database\Eloquent\Relations\Relation; Relation::morphMap([ 'posts' => 'App\Post', 'videos' => 'App\Video', ]);
همینطور که ملاحظه میکنید در کدهای بالا مسیرهای App\Post و App\Video به عناوین posts و videos توسط متد morphMap از Relation Facade تغییر کرده است. برای ثبت این کدها باید آنها را درون تابع boot موجود در کلاس AppServiceProvider ایجاد کرد.
علاوه بر روابط یک به چند که در بالا بررسی کردیم. روابط چند به چند پلی مورفیک وجود دارند. مجددا ادامهی این آموزش را با مطرح کردن یک مثال پیش میبریم. یک وبلاگ مدلهایی با عناوین Post و Video دارد. حال هر پست و ویدیو دارای چندین تگ یا برچسب است و متقابلا هر برچسب به چندین پست و ویدیو اختصاص دارد. در اینجا یک رابطهی چند به چند بین مدل Tag با هر یک از مدلهای Video و Post وجود دارد. بنابراین برای ایجاد همچنین رابطهای باید و باید یک جدول تحت عنوان taggables ایجاد کرده که لیستی از تگها را که به پست یا ویدیوی مشخصی ارتباط دارند مشخص کند. بنابراین ساختار جداول برای این سه مدل به صورت زیر خواهد بود:
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
همانطور که مشاهده میکنید جدولی به نام taggables ایجاد شده است که شامل ستونهای tag_id (آی دی هر تگ که از جدول tags استخراج میشود)، ستون taggable_id (آی دی هر پست یا ویدیو که میخواهیم تگ را به آن اختصاص دهیم) و ستون taggable_type (نوع مدلی که تگ به آن اتصال پیدا میکند).
ساختار Model
حال به تعریف مدلها میپردازیم. مدلهای Post و Video هر دو متدی به عنوان tags خواهند داشت که درون آنها متد morphToMany بازگردانده میشود:
در مدل Post.php خواهیم داشت:
<?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'); } }
همچنین درون مدل Video:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Video extends Model { /** * Get all of the tags for the post. */ public function tags() { return $this->morphToMany('App\Tag', 'taggable'); } }
حال درون مدل Tag,php باید رابطهی معکوس و دو طرفه را برقرار کنیم. بنابراین باید برای هر یک از مدلهای Post و Video متدهای 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'); } }
بازیابی اطلاعات از این روابط
پس از تعریف جداول و مدلها برای بازیابی اطلاعات از این روابط اقدام میکنیم:
$post = App\Post::find(1); foreach ($post->tags as $tag) { // }
همچنین میتوان تمام تگهای موجود در یک پست و یا ویدیو را با استفاده از دستور زیر بدست آورد:
$tag = App\Tag::find(1); foreach ($tag->videos as $video) { // }
بسیار عالی! مباحث مربوط به روابط Eloquent به اتمام رسید و شما با مطالعهی فصل ۱۲ میتوانید ۶ نوع رابطهای که برای جداول هر پایگاه داده نیاز است را ایجاد کنید. در جلسهی بعدی به توضیح مختصری درباره انواع کوئری این روابط و همچنین نحوهی بارگذاری آنها میپردازیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.