Laravel Eloquent မှာ ပုံမှန် အားဖြင့် အသုံးပြုကြတာကတော့
- One To One
- One to Many
- Many to Many
တို့ပါ။
ဒါပေမယ့် ထပ်ပြီး အသုံးပြုနိုင်သေးတာကတော့
- Through
- Morph
တို့ပါ။
Through
Through ကို ဘယ်လို နေရာတွေမှာ အသုံးပြုကြလဲ ဆိုတော့
UserGroup မှာ User ရှိတယ်။
User မှာ Post တွေ ရှိတယ်။
Premium User Group က တင်ထားသည့် Post တွေကို လိုချင်တယ် ဆိုပါဆို့။ အဲဒီလိုမျိုး Use Case တွေကို Through ကို အသုံးပြုနိုင်ပါတယ်။
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
function posts() {
return $this->hasMany(Post::class);
}
}
class UserGroup extends Model{
use HasFactory;
function users() {
return $this->hasMany(User::class);
}
function posts() {
return $this->hasManyThrough(Post::class,User::class);
}
}
ဒီ code မှာ ဆိုရင် UserGroup က posts တွေကို ရဖို့ အတွက် User class ကနေ တဆင့် ခေါ်ထားတယ် ဆိုပြီး တွေ့နိုင်ပါတယ်။
Migration table ကို ကြည့်ရအောင်။
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->foreignId("user_group_id");
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
}
};
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_groups', function (Blueprint $table) {
$table->id();
$table->text("name");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_groups');
}
};
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->text("title");
$table->text("body");
$table->foreignId("user_id");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
ဒီ migration file ကို ကြည့်လိုက်ရင် သဘောပေါက်သွားမှာပါ။
Posts table မှာ user_id ရှိတယ်။ Users table မှာ user_group_id ရှိပါတယ်။ ဒါကြောင့် UserGroups table က posts စာရင်း ကို ခေါ်လို့ရသွားတာပါ။ ဥပမာ SQL အရ ဆိုရင် အောက်ပါ အတိုင်းဖြစ်ပါလိမ့်မယ်။
SELECT * FROM Posts
INNER JOIN Users ON Users.id = Posts.id
INNER JOIN UserGroups ON Users.user_group_id = UserGroups.id
WHERE UsersGroup.id = 1
MorphOne
Larvel ရဲ့ Eloquent relationship ထဲမှာ Morph က တော်တော်မိုက်တယ်။
Post က Text Post လည်း ဖြစ်နိုင်သလို VideoPost လည်း ဖြစ်နိုင်တယ်။
ပုံမှန် အားဖြင့် Post က text post အတွက် relationship တစ်ခု။ video post အတွက် relationship တစ်ခု ဖန်တီး ရမှာပါ။ Morph နဲ့ ဆိုရင် တော့ postable_type နဲ့ postable_id ပေါ်မှာ မူတည်ပြီး ခွဲလို့ရပါတယ်။
id | postable_type | postable_id | name | user_id |
1 | App/Models/VideoPost | 1 | Sample Video | 1 |
2 | App/Models/TextPost | 1 | Sample Post | 3 |
အခု table မှာဆိုရင် id 1 က VideoPost ဖြစ်ပြီး VideoPost ရဲ့ id 1 ကို ချိတ်ထားပြီး id 2 က TextPost ဆိုရင် TextPost table ရဲ့ 1 နဲ့ ချိတ်ထားပါတယ်။
Model မှာ ဆိုရင်
class Post extends Model
{
use HasFactory;
use LikeableRealation;
function user() {
return $this->belongsTo(User::class);
}
function postable() {
return $this->morphTo();
}
}
postable မှာ morphTo နဲ့ ချိတ်ထားသည့် အတွက်ကြောင့် postable_type က VideoPost ဆိုရင် VideoPost model ကို ရမှာ ဖြစ်ပြီး TextPost ဆိုရင် TextPost model ကို ရမှာပါ။
class VideoPost extends Model
{
use HasFactory;
use PostablePost;
}
class TextPost extends Model
{
use HasFactory;
use PostablePost;
}
PostablePost ကတော့ trail နဲ့ ရေးထားပါတယ်။
trait PostablePost {
function post() {
return $this->morphOne(Post::class,"postable");
}
}
VideoPost , TextPost ကနေ post ကို ပြန်ခေါ်မယ် ဆိုရင်တော့ morphOne နဲ့ ပြန်ခေါ်လို့ရပါလိမ့်မယ်။
Migration file ကို ကြည့်ရအောင်။
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->text("title");
$table->morphs("postable"); //auto include _type and _id
$table->foreignId("user_id");
$table->timestamps();
})
$table->morphs ဆိုသည့် code က နောက်မှာ _type နဲ့ _id column အလိုလို ထည့်ပေးပါတယ်။ ဒါကြောင့် postable_type , postable_id ဆိုပြီး ကြေငြာနေဖို့ မလိုပါဘူး။
MorphToMany
morphToMany ကတော့ နည်းနည်းရှုပ်သွားပါပြီ။ User က comment ကို like လုပ်မယ်။ Post ကို like လုပ်မယ်။ ပုံမှန်အားဖြင့် Comment နဲ့ Post က likes_type နဲ့ likes_id ပဲ ပါပါမယ်။ အခု user_id ပါ ထပ်ပြီး ပါလာပါပြီ။
ဒါကြောင့် likes table တစ်ခု ထပ်ပြီး create လုပ်သည့် အမှာ user_id နဲ့ ထပ် join ပါမယ်။
Schema::create('likes', function (Blueprint $table) {
$table->foreignId("user_id");
$table->morphs("likes");
$table->timestamps();
});
ဒီ table မှာ id မပါပါဘူး။ နောက်ပြီး သတိထားရမှာက morphtoMany သုံးမယ်ဆိုရင် morphs က table name နဲ့ တူမှ အဆင်ပြေမှာပါ။ $table->morphs(“likes”) က likes_id နဲ့ likes_type ကို အလိုလို create လုပ်သွားမှာပါ။
trait LikeableRealation {
function like(User $user) {
$this->likes()->attach($user);
}
function likes() {
return $this->morphToMany(User::class,"likes")->withTimestamps();
}
}
class Post extends Model
{
use HasFactory;
use LikeableRealation;
function user() {
return $this->belongsTo(User::class);
}
function tags() {
return $this->belongsToMany(Tag::class);
}
function postable() {
return $this->morphTo();
}
}
class Comment extends Model
{
use HasFactory;
use LikeableRealation;
function user() {
return $this->belongsTo(User::class);
}
function post() {
return $this->belongsTo(Post::class);
}
}
class User extends
{
//Other code
public function likedPosts()
{
return $this->morphedByMany(Post::class, 'likes');
}
public function likedComments()
{
return $this->morphedByMany(Comment::class, 'likes');
}
}
$post->likes ဆိုရင် likes လုပ်ထားသည့် users object တွေ ရမှာပါ။
$user->likedPosts ဆိုရင်တော့ အဲဒီ user liked လုပ်ထားသည့် post တွေကို ရမှာပါ။
Source code ကို https://github.com/saturngod/eloquent_relationship မှာ ရနိုင်ပါတယ်။