Laravel Database Eloquent ORM
Laravel Polymorphic Relationships
Laravel এ Polymorphic Relationship কি?
Polymorphic Relationship হল এমন একটি রিলেশনশিপ যেখানে একটি মডেল একাধিক অন্য মডেলের সাথে সংযুক্ত হতে পারে এবং সংযোগ করা মডেলের টাইপ ডাইনামিকভাবে পরিবর্তন করা যায়। অর্থাৎ, একটি টেবিলে একাধিক মডেলের রেকর্ড সংরক্ষণ করতে পারি এবং যাতে একটি reusable বা পুনরাবৃত্তিমূলক রিলেশনশিপ দ্বারা এই রেকর্ডগুলি সংযুক্ত করা যায়, আর এই কাজটি পলিমরফিক রিলেশনশিপ ব্যবহার করে করা হয়।
Polymorphic Relationship ডাটাবেসের নির্দিষ্ট টেবিলে তিনটি কলাম ব্যবহার করে। প্রথমটি হল “Polymorphic Type” কলাম, যা সংশ্লিষ্ট মডেলের নাম সংরক্ষণ করে। দ্বিতীয়টি হল “Polymorphic Id” কলাম, যা সংশ্লিষ্ট মডেলের আইডি সংরক্ষণ করে। তৃতীয়টি হল “Polymorphic Subject” কলাম, যা Polymorphic Relationship সাথে সংযুক্ত মডেলের নাম সংরক্ষণ করে।
Polymorphic Relationship ব্যবহার করার জন্য, আপনার মডেলগুলির মধ্যে একটা Relationship সেটআপ করতে হবে এবং আপনি কমেন্ট মডেলে Polymorphic Relationship ব্যবহার করতে হবে।
Laravel Framework এ Polymorphic Relationship তিন ধরণের হয়।
- One To One (Polymorphic)
- One To Many (Polymorphic)
- Many To Many (Polymorphic)
Laravel One To One (Polymorphic) Relationship
Laravel Framework এ One-to-One Polymorphic Relationship হল এমন একটি Relationship যেখানে একটি মডেল অন্য একটি মডেলের সাথে একটি মধ্যবর্তী সংখ্যার রেফারেন্স সংরক্ষণ করে। এই রিলেশনশিপে একটি সংখ্যার সমান মান শুধুমাত্র একটি মডেলে এবং একটি মধ্যবর্তী মডেলের সাথে ম্যাচ করে।
উদাহরণস্বরূপ, ধরা যাক আপনার একটি “Image” মডেল, “User” মডেল এবং “Post” মডেল রয়েছে। আপনি এমন একটি একটি রিলেশনশিপ স্থাপন করতে চান যেখানে প্রতিটি পোস্ট এবং প্রতিটি ইউজার কে একটি ইমেজের সাথে সংযুক্ত করা হয়েছে। প্রতিটি পোস্ট শুধুমাত্র একটি ইমেজের সাথে সংযুক্ত হতে পারে এবং একটি ইমেজ শুধুমাত্র একটি পোস্টের সাথে সংযুক্ত হতে পারে। একইভাবে প্রতিটি ইউজার শুধুমাত্র একটি ইমেজের সাথে সংযুক্ত হতে পারে এবং একটি ইমেজ শুধুমাত্র একটি ইউজারের সাথে সংযুক্ত হতে পারে। এটি একটি One-to-One Polymorphic Relationship।
Create Migration Files
Laravel Framework এ One To One Polymorphic Relationship বুঝার জন্য আমরা এখন posts, users এবং images নামে এই তিনটি টেবিল তৈরি করব। এর জন্য প্রথমে নিম্নোক্ত artisan command রান করার মাধ্যমে আমরা table তিনটির Migration File তৈরি করব :
php artisan make:migration create_posts_table php artisan make:migration create_users_table php artisan make:migration create_images_table
এবার সদ্য তৈরি হওয়া Migration File গুলোকে নিচের মতো করে আপডেট করে নিন :
create_posts_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('content'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('posts'); } };
create_users_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } };
create_images_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('images', function (Blueprint $table) { $table->id(); $table->string('url'); $table->unsignedBigInteger('imageable_id'); $table->string('imageable_type'); $table->index(['imageable_id', 'imageable_type']); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('images'); } };
এবার উক্ত মাইগ্রেশন ফাইল গুলো ব্যবহার করে টেবিল তৈরির জন্য নিম্নোক্ত artisan command গুলো রান করুন। আর অবশ্যই নিম্নোক্ত কমান্ডে ব্যবহৃত ফাইল নামের পরিবর্তে আপনার সদ্য তৈরি হওয়া মাইগ্রেশন ফাইলের নাম ব্যবহার করুন :
php artisan migrate --path=/database/migrations/your_posts_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_users_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_images_table_migration_file_name.php
এবার সদ্য তৈরি হওয়া টেবিল তিনটির জন্য নিম্নোক্ত artisan command এর মাধ্যমে তিনটি Model তৈরি করব।
php artisan make:model Post php artisan make:model User php artisan make:model Image
table এবং Model গুলো তৈরির কাজ শেষ , এবার table গুলোতে কিছু স্যাম্পল ডেটা তৈরির জন্য আমরা তিনটি seed file তৈরি করব। seed file তিনটি তৈরির জন্য নিম্নোক্ত কমান্ড ব্যবহার করুন :
php artisan make:seed PostsTableSeeder php artisan make:seed UsersTableSeeder php artisan make:seed ImagesTableSeeder
এবার সদ্য তৈরি হওয়া Seed File গুলোকে নিচের মতো করে আপডেট করে নিন :
PostsTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Post; class PostsTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { // Create some example posts Post::create([ 'title' => 'First Post', 'content' => 'This is the content of the first post.', ]); Post::create([ 'title' => 'Second Post', 'content' => 'This is the content of the second post.', ]); Post::create([ 'title' => 'Third Post', 'content' => 'This is the content of the Third post.', ]); // You can create more posts as needed } }
UsersTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; use App\Models\User; class UsersTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { // Create an example user User::create([ 'name' => 'John Doe', 'email' => 'johndoe@example.com', 'email_verified_at' => now(), 'password' => Hash::make('password'), 'remember_token' => str::random(10), ]); User::create([ 'name' => 'Jane Doe', 'email' => 'janedoe@example.com', 'email_verified_at' => now(), 'password' => Hash::make('password'), 'remember_token' => str::random(10), ]); User::create([ 'name' => 'Wiliam Petrik', 'email' => 'wilium@example.com', 'email_verified_at' => now(), 'password' => Hash::make('password'), 'remember_token' => str::random(10), ]); // You can create more users as needed } }
ImagesTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Image; use App\Models\Post; use App\Models\User; class ImagesTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { // Create example images for posts Image::create([ 'url' => 'https://example.com/image1.jpg', 'imageable_id' => Post::first()->id, 'imageable_type' => Post::class, ]); Image::create([ 'url' => 'https://example.com/image2.jpg', 'imageable_id' => Post::find(2)->id, 'imageable_type' => Post::class, ]); // Create example images for users Image::create([ 'url' => 'https://example.com/image3.jpg', 'imageable_id' => User::first()->id, 'imageable_type' => User::class, ]); // You can create more images as needed for different models } }
এবার নিম্নোক্ত artisan command ব্যবহার করে উপরোক্ত seed file গুলো রান করুন :
php artisan db:seed --class=UsersTableSeeder php artisan db:seed --class=PostsTableSeeder php artisan db:seed --class=ImagesTableSeeder
এতক্ষনে আমরা table গুলোর structure তৈরির জন্য Migration File গুলো এবং উক্ত টেবিল গুলোর জন্য dummy data এর জন্য seeding এর কাজ গুলো করেছি। এখন One To One Polymorphic Relationship এর জন্য আপনার User, Post, এবং Image Model কে নিচের মতো করে আপডেট করে নিন :
User.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Database\Eloquent\Relations\MorphOne; class User extends Authenticatable { use HasFactory; /** * Get the user's image. */ public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); } }
Post.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOne; class Post extends Model { use HasFactory; /** * Get the post's image. */ public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); } }
Image.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo; class Image extends Model { use HasFactory; /** * Get the parent imageable model (user or post). */ public function imageable(): MorphTo { return $this->morphTo(); } }
মোটামুটি One To One Polymorphic Relationship এর জন্য যে ধরণের function যুক্ত করার দরকার ছিল , তার সবই আমরা যুক্ত করেছি। এখন আপনার web.php ফাইলে নিম্নোক্ত route দিয়ে One To One Polymorphic Relationship এর উদাহরণ গুলো দেখে নিন :
use App\Models\Post; use App\Models\Image; Route::get('/morph-one',function(){ $post = Post::find(1); //dd($post->image); $image = Image::find(1); $imageable = $image->imageable; //dd($imageable); });
Laravel One To Many (Polymorphic) Relationship
Laravel Framework এ One-to-Many Polymorphic Relationship হল এমন একটি Relationship যেখানে একটি মডেল অন্য অনেকগুলো মডেলের সাথে একটি মধ্যবর্তী সংখ্যার রেফারেন্স সংরক্ষণ করে। এই রিলেশনশিপে একটি সংখ্যার সমান মান অনেকগুলো মডেলের সাথে এবং অনেকগুলো মধ্যবর্তী মডেলের সাথে ম্যাচ করে।
Laravel One To Many Polymorphic Relationship ব্যবহার করার একটি সহজ উদাহরণ হল, ধরুন আপনার একটি Comments Table রয়েছে, কিন্তু এই Comments Table এর কমেন্টস গুলো হতে পারে কোনো একটি posts table এর বা একটি videos table সাথে সম্পর্কৃত। আর তাই প্রতিটি কমেন্ট কোন টেবিল এর সাথে সম্পর্কৃত তা সহজে বুঝার জন্য প্রতিটি comment রেকর্ডে তার সাথে রিলেটেড বা সংযুক্ত মডেল এবং সংযুক্ত মডেলের আইডি সংরক্ষণ করা দরকার। এটি দ্বারা সিস্টেমটি বোঝানো হয় যে এই কমেন্টগুলি কোন মডেল এর সাথে Related বা সংযুক্ত আছে।
Create Migration Files
Laravel Framework এ Laravel One To Many Polymorphic Relationship বুঝার জন্য আমরা এখন posts, videos এবং comments নামে এই তিনটি টেবিল তৈরি করব। এর জন্য প্রথমে নিম্নোক্ত artisan command রান করার মাধ্যমে আমরা table তিনটির Migration File তৈরি করব :
php artisan make:migration create_posts_table php artisan make:migration create_videos_table php artisan make:migration create_comments_table
এবার সদ্য তৈরি হওয়া Migration File গুলোকে নিচের মতো করে আপডেট করে নিন :
create_posts_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('content'); $table->unsignedBigInteger('commentable_id'); $table->string('commentable_type'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('posts'); } };
create_videos_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('videos', function (Blueprint $table) { $table->id(); $table->string('title'); $table->string('url'); $table->unsignedBigInteger('commentable_id'); $table->string('commentable_type'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('videos'); } };
create_comments_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('comments', function (Blueprint $table) { $table->id(); $table->text('body'); $table->unsignedBigInteger('commentable_id'); $table->string('commentable_type'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('comments'); } };
এবার উক্ত মাইগ্রেশন ফাইল গুলো ব্যবহার করে টেবিল তৈরির জন্য নিম্নোক্ত artisan command গুলো রান করুন। আর অবশ্যই নিম্নোক্ত কমান্ডে ব্যবহৃত ফাইল নামের পরিবর্তে আপনার সদ্য তৈরি হওয়া মাইগ্রেশন ফাইলের নাম ব্যবহার করুন :
php artisan migrate --path=/database/migrations/your_posts_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_videos_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_comments_table_migration_file_name.php
এবার সদ্য তৈরি হওয়া টেবিল তিনটির জন্য নিম্নোক্ত artisan command এর মাধ্যমে তিনটি Model তৈরি করব।
php artisan make:model Post php artisan make:model Video php artisan make:model Comment
table এবং Model গুলো তৈরির কাজ শেষ , এবার table গুলোতে কিছু স্যাম্পল ডেটা তৈরির জন্য আমরা তিনটি seed file তৈরি করব। seed file তিনটি তৈরির জন্য নিম্নোক্ত কমান্ড ব্যবহার করুন :
php artisan make:seed PostsTableSeeder php artisan make:seed VideosTableSeeder php artisan make:seed CommentsTableSeeder
এবার সদ্য তৈরি হওয়া Seed File গুলোকে নিচের মতো করে আপডেট করে নিন :
PostsTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Post; class PostsTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { Post::create([ 'title' => 'First Post', 'content' => 'This is the content of the first post.', 'commentable_id' => 1, 'commentable_type' => 'App\Models\Post', ]); Post::create([ 'title' => 'Second Post', 'content' => 'This is the content of the Second post.', 'commentable_id' => 2, 'commentable_type' => 'App\Models\Post', ]); } }
VideosTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Video; class VideosTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { Video::create([ 'title' => 'First Video', 'url' => 'https://example.com/video1.mp4', 'commentable_id' => 1, 'commentable_type' => 'App\Models\Video', ]); Video::create([ 'title' => 'Second Video', 'url' => 'https://example.com/video1.mp4', 'commentable_id' => 2, 'commentable_type' => 'App\Models\Video', ]); } }
CommentsTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use App\Models\Comment; class CommentsTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { Comment::create([ 'body' => 'Great post!', 'commentable_id' => 1, 'commentable_type' => 'App\Models\Post', ]); Comment::create([ 'body' => 'Nice video!', 'commentable_id' => 1, 'commentable_type' => 'App\Models\Video', ]); } }
এবার নিম্নোক্ত artisan command ব্যবহার করে উপরোক্ত seed file গুলো রান করুন :
php artisan db:seed --class=PostsTableSeeder php artisan db:seed --class=VideosTableSeeder php artisan db:seed --class=CommentsTableSeeder
এতক্ষনে আমরা table গুলোর structure তৈরির জন্য Migration File গুলো এবং উক্ত টেবিল গুলোর জন্য dummy data এর জন্য seeding এর কাজ গুলো করেছি। এখন One To Many Polymorphic Relationship এর জন্য আপনার Post,Videos এবং Comment Model কে নিচের মতো করে আপডেট করে নিন :
Post.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Database\Eloquent\Relations\MorphMany; class Post extends Model { use HasFactory; public function image():MorphOne { return $this->morphOne(Image::class,'imageable'); } /** * Get all of the post's comments. */ public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); } }
Video.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphMany; class Video extends Model { use HasFactory; /** * Get all of the video's comments. */ public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); } }
Comment.php Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphTo; class Comment extends Model { use HasFactory; /** * Get the parent commentable model (post or video). */ public function commentable(): MorphTo { return $this->morphTo(); } }
Retrieving The Relationship
এতক্ষন আমরা আমাদের ডাটাবেস টেবিল, টেবিল এর জন্য স্যাম্পল ডেটা এবং মডেলগুলি তৈরি করেছি, এখন আপনি আপনার dynamic relationship properties গুলির মাধ্যমে relationships গুলি অ্যাক্সেস করতে পারেন। উদাহরণস্বরূপ, একটি পোস্টের জন্য সমস্ত comments এ অ্যাক্সেস করতে, আমরা comments dynamic property ব্যবহার করতে পারি:
use App\Models\Post; Route::get('/morph-many',function(){ $post = Post::find(1); foreach ($post->comments as $comment) { echo $comment->body,"<br>"; } });
এছাড়াও আপনি morphTo-তে কল সম্পাদনকারী method name অ্যাক্সেস করে একটি পলিমরফিক চাইল্ড মডেলের parent ও retrieve করতে পারেন। এই ক্ষেত্রে, এটি Comment মডেলের commentable method। সুতরাং, comment এর parent model এ অ্যাক্সেস করার জন্য আমরা একটি dynamic relationship property হিসাবে সেই method টি অ্যাক্সেস করব:
use App\Models\Comment; Route::get('/morph-many',function(){ $comment = Comment::find(1); echo $comment->commentable; });
Comment মডেলের commentable relation টি একটি Post বা Video instance instance প্রদান করবে, আর এটা নির্ভর করে কোন ধরনের মডেল comment’s parent তার উপর ।
One Of Many (Polymorphic)
কখনও কখনও একটি মডেলের অনেক related models থাকতে পারে, তবুও আপনি related মডেল গুলোর “latest” বা “oldest” মডেলটি সহজেই retrieve করতে পারেন। উদাহরণস্বরূপ, একটি User model এর অনেকগুলি Image models এর সাথে related হতে পারে, তবে আপনি ইউজারের আপলোড করা সাম্প্রতিক (Latest) image গুলির সাথে ইন্টারঅ্যাক্ট করার একটি সুবিধাজনক উপায় নির্ধারণ করতে চান৷ তাহলে আপনি User Model এ ofMany methods দিয়ে morphOne relationship type ব্যবহার করে এই কাজটি করতে পারেন:
/** * Get the user's most recent image. */ public function latestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->latestOfMany(); }
এখন আপনি আপনার route এ web.php ফাইলে নিম্নোক্ত কোডের মাধ্যমে আপনার লেটেস্ট ছবি গুলো সহজেই পেতে পারেন :
use App\Models\User; Route::get('/latest-image',function(){ $user = User::find(1); // Retrieve the user instance $latestImage = $user->latestImage; // Access the latestImage relationship if ($latestImage) { // Access the image attributes echo $latestImage->url,"<br>"; echo $latestImage->imageable_id,"<br>"; echo $latestImage->imageable_type,"<br>"; // You can perform further operations with the image data // ... } else { // No image found for the user } });
একইভাবে, আপনি একটি relationship এর “oldest”, বা first, related model retrieve করার একটি method সংজ্ঞায়িত করতে পারেন:
/** * Get the user's oldest image. */ public function oldestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->oldestOfMany(); }
এখন আপনি আপনার route এ web.php ফাইলে নিম্নোক্ত কোডের মাধ্যমে আপনার Oldest Image গুলো সহজেই পেতে পারেন :
use App\Models\User; Route::get('/oldest-image',function(){ $user = User::find(1); // Retrieve the user instance $oldestImage = $user->oldestImage; // Access the latestImage relationship if ($oldestImage) { // Access the image attributes echo $oldestImage->url,"<br>"; echo $oldestImage->imageable_id,"<br>"; echo $oldestImage->imageable_type,"<br>"; // You can perform further operations with the image data // ... } else { // No image found for the user } });
ডিফল্টরূপে, latestOfMany এবং oldestOfMany method গুলি মডেলের primary key-এর উপর ভিত্তি করে latest বা oldest সম্পর্কিত মডেল retrieve করবে, যা অবশ্যই sortable হতে হবে। যাইহোক, কখনও কখনও আপনি একটি ভিন্ন sorting criteria ব্যবহার করে একটি বড় relationship থেকে একটি single model retrieve করতে চাইতে পারেন।
/** * Get the user's most popular image. */ public function bestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->ofMany('likes', 'max'); }
এখন আপনি আপনার route এ web.php ফাইলে নিম্নোক্ত কোডের মাধ্যমে আপনার Most Liked Image গুলো সহজেই পেতে পারেন :
use App\Models\User; Route::get('/best-image',function(){ $user = User::find(1); // Retrieve the user instance $bestImage = $user->bestImage; // Access the latestImage relationship if ($bestImage) { // Access the image attributes echo $bestImage->url,"<br>"; echo $bestImage->imageable_id,"<br>"; echo $bestImage->imageable_type,"<br>"; // You can perform further operations with the image data // ... } else { // No image found for the user } });
এতক্ষনে আমরা যতগুলো উদাহরণ দেখলাম। আমাদের User মডেলে সবগুলো হবে নিম্নরুপঃ
<?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; /** * Get the latest post associated with the user. */ public function latestPost():HasOne { return $this->hasOne(Post::class)->latestOfMany(); } /** * Get the oldest post associated with the user. */ public function oldestPost():HasOne { return $this->hasOne(Post::class)->oldestOfMany(); } /** * Get the user's popular post. */ public function popularPost():HasOne { return $this->hasOne(Post::class)->ofMany('views', 'max'); } public function latestImage():MorphOne { return $this->MorphOne(Image::class,'imageable')->latestOfMany(); } }
Many To Many (Polymorphic)
Many-to-many polymorphic relations “morph one” এবং “morph many” relationships চেয়ে কিছুটা জটিল। উদাহরণস্বরূপ, একটি Post model এবং Video model একটি Tag model সাথে একটি polymorphic relation ভাগ করতে পারে। এই পরিস্থিতিতে many-to-many polymorphic relation ব্যবহার করা আপনার অ্যাপ্লিকেশনটিকে posts বা videos গুলির সাথে যুক্ত হতে পারে এমন unique tags একটি একক টেবিলের অনুমতি দেবে৷ প্রথমে, আসুন এই relationship তৈরি করার জন্য প্রয়োজনীয় table structure দেখা যাক:
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
Create Migration Files
Laravel Framework এ Laravel Many To Many Polymorphic Relationship বুঝার জন্য আমাদের posts, videos, tags এবং taggables নামে এই চারটি টেবিল তৈরি করতে হবে। তাই আমরা এখন নিম্নোক্ত artisan command রান করার মাধ্যমে এই চারটি table যথাক্রমে posts,videos,tags এবং taggables table এর জন্য Migration File তৈরি করব :
php artisan make:migration create_posts_table php artisan make:migration create_videos_table php artisan make:migration create_tags_table php artisan make:migration create_taggables _table
এবার সদ্য তৈরি হওয়া Migration File গুলোকে নিচের মতো করে আপডেট করে নিন :
create_posts_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('posts'); } };
create_videos_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('videos', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('videos'); } };
create_tags_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('tags', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('tags'); } };
create_taggables_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('taggables', function (Blueprint $table) { $table->id(); $table->foreignId('tag_id')->constrained('tags'); $table->unsignedBigInteger('taggable_id'); $table->string('taggable_type'); $table->timestamps(); $table->index(['taggable_id', 'taggable_type']); // Optional: If you want to cascade delete the taggables when a tag is deleted // $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('taggables'); } };
এবার উক্ত মাইগ্রেশন ফাইল গুলো ব্যবহার করে টেবিল তৈরির জন্য নিম্নোক্ত artisan command গুলো রান করুন। আর অবশ্যই নিম্নোক্ত কমান্ডে ব্যবহৃত ফাইল নামের পরিবর্তে আপনার সদ্য তৈরি হওয়া মাইগ্রেশন ফাইলের নাম ব্যবহার করুন :
php artisan migrate --path=/database/migrations/your_posts_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_videos_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_tags_table_migration_file_name.php php artisan migrate --path=/database/migrations/your_taggables_table_migration_file_name.php
table এবং Model গুলো তৈরির কাজ শেষ , এবার table গুলোতে কিছু স্যাম্পল ডেটা তৈরির জন্য আমরা তিনটি seed file তৈরি করব। seed file তিনটি তৈরির জন্য নিম্নোক্ত কমান্ড ব্যবহার করুন :
php artisan make:seed PostsTableSeeder php artisan make:seed VideosTableSeeder php artisan make:seed TagsTableSeeder php artisan make:seed TaggablesTableSeeder
এবার সদ্য তৈরি হওয়া Seed File গুলোকে নিচের মতো করে আপডেট করে নিন :
PostsTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class PostsTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { $posts = [ ['id' => 1, 'name' => 'Post 1'], ['id' => 2, 'name' => 'Post 2'], ['id' => 3, 'name' => 'Post 3'], ]; DB::table('posts')->insert($posts); } }
VideosTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class VideosTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { $videos = [ ['id' => 1, 'name' => 'Video 1'], ['id' => 2, 'name' => 'Video 2'], ['id' => 3, 'name' => 'Video 3'], ]; DB::table('videos')->insert($videos); } }
TagsTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class TagsTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { $tags = [ ['id' => 1, 'name' => 'Tag 1'], ['id' => 2, 'name' => 'Tag 2'], ['id' => 3, 'name' => 'Tag 3'], ]; DB::table('tags')->insert($tags); } }
TaggablesTableSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class TaggablesTableSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { $taggables = [ ['tag_id' => 1, 'taggable_id' => 1, 'taggable_type' => 'App\\Models\\Post'], ['tag_id' => 2, 'taggable_id' => 1, 'taggable_type' => 'App\\Models\\Post'], ['tag_id' => 2, 'taggable_id' => 2, 'taggable_type' => 'App\\Models\\Video'], ['tag_id' => 3, 'taggable_id' => 2, 'taggable_type' => 'App\\Models\\Video'], ['tag_id' => 1, 'taggable_id' => 3, 'taggable_type' => 'App\\Models\\Post'], ]; DB::table('taggables')->insert($taggables); } }
এবার নিম্নোক্ত artisan command ব্যবহার করে উপরোক্ত seed file গুলো রান করুন :
php artisan db:seed --class=PostsTableSeeder php artisan db:seed --class=VideosTableSeeder php artisan db:seed --class=TagsTableSeeder php artisan db:seed --class=TaggablesTableSeeder
Model Structure
এবার সদ্য তৈরি হওয়া টেবিল তিনটির জন্য নিম্নোক্ত artisan command এর মাধ্যমে তিনটি Model তৈরি করব।
php artisan make:model Post php artisan make:model Video php artisan make:model Tag php artisan make:model Taggable
অবশেষে, আমরা মডেলগুলিতে relationships গুলি ডিফাইন করতে রেডি। Post এবং Video মডেল উভয়েই একটি tags method থাকবে যা base Eloquent model class দ্বারা প্রদত্ত morphToMany method কে কল করবে।
morphToMany method টি related মডেলের নামের পাশাপাশি “relationship name” গ্রহণ করে। আমাদের মধ্যবর্তী টেবিলের নাম এবং এতে থাকা কীগুলির উপর ভিত্তি করে আমরা relationship টিকে “taggable” হিসাবে উল্লেখ করব:
Post Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; class Post extends Model { use HasFactory; /** * Get all of the tags for the post. */ public function tags():MorphToMany { return $this->morphToMany(Tag::class, 'taggable'); } }
Video Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; class Video extends Model { use HasFactory; /** * Get all of the tags for the post. */ public function tags(): MorphToMany { return $this->morphToMany(Tag::class, 'taggable'); } }
Defining The Inverse Of The Relationship
এর পরে, Tag মডেলে, আপনার প্রতিটি সম্ভাব্য প্যারেন্ট মডেলের জন্য একটি method নির্ধারণ করা উচিত। সুতরাং, এই উদাহরণে, আমরা একটি posts method এবং একটি videos method ডিফাইন করব। এই উভয় methods এ morphedByMany method এর মাধ্যমে ফলাফল রিটার্ন করবে।
morphedByMany method টি related মডেলের নামের পাশাপাশি “relationship name” গ্রহণ করে। আমাদের মধ্যবর্তী টেবিলের নাম এবং এতে থাকা কীগুলির উপর ভিত্তি করে আমরা relationship টিকে “taggable” হিসাবে উল্লেখ করব:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; class Tag extends Model { use HasFactory; /** * Get all of the posts that are assigned this tag. */ public function posts(): MorphToMany { return $this->morphedByMany(Post::class, 'taggable'); } /** * Get all of the videos that are assigned this tag. */ public function videos(): MorphToMany { return $this->morphedByMany(Video::class, 'taggable'); } }
Retrieving The Relationship
একবার আপনার ডাটাবেস টেবিল এবং মডেলগুলি ডিফাইন হয়ে গেলে, আপনি আপনার মডেলগুলির মাধ্যমে relationships গুলি অ্যাক্সেস করতে পারেন। উদাহরণস্বরূপ, একটি পোস্টের জন্য সমস্ত ট্যাগ অ্যাক্সেস করতে, আপনি ট্যাগ dynamic relationship property ব্যবহার করতে পারেন:
use App\Models\Post; use App\Models\Tag; Route::get('/post-tags',function(){ $post = Post::find(1); $tag = Tag::find(1); $tag2 = Tag::find(2); //dd($post->tags); //dd($tag->posts); dd($tag->videos); });