PHP
Build Flexible Data Models with Eloquent Polymorphic Relationships
Understand how to implement polymorphic relationships in Laravel Eloquent, enabling a single model to belong to multiple different models using a single association column set for flexibility.
// In your database migrations, for the 'comments' table, use morphs():
// Schema::create('comments', function (Blueprint $table) {
// $table->id();
// $table->text('body');
// $table->foreignId('user_id')->constrained();
// $table->morphs('commentable'); // This adds commentable_id (INT) and commentable_type (VARCHAR)
// $table->timestamps();
// });
// 1. Define the 'morphTo' relationship on the 'Comment' model:
class Comment extends Model
{
protected $fillable = ['body', 'user_id'];
public function commentable()
{
return $this->morphTo();
}
}
// 2. Define the 'morphMany' relationship on the 'Post' model:
class Post extends Model
{
protected $fillable = ['title', 'content'];
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
// 3. Define the 'morphMany' relationship on the 'Video' model:
class Video extends Model
{
protected $fillable = ['title', 'url'];
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
// Usage examples:
// Create dummy users (for foreign key constraint)
// $user1 = App\Models\User::firstOrCreate(['name' => 'Alice', 'email' => '[email protected]', 'password' => 'secret']);
// $user2 = App\Models\User::firstOrCreate(['name' => 'Bob', 'email' => '[email protected]', 'password' => 'secret']);
// Add a comment to a post
$post = App\Models\Post::firstOrCreate(['title' => 'My First Post', 'content' => 'Content of the post.']);
$post->comments()->create([
'body' => 'Great post!',
'user_id' => 1
]);
// Add a comment to a video
$video = App\Models\Video::firstOrCreate(['title' => 'My First Video', 'url' => 'https://example.com/video1.mp4']);
$video->comments()->create([
'body' => 'Awesome video!',
'user_id' => 2
]);
// Retrieve comments for a post
$postComments = App\Models\Post::find($post->id)->comments;
foreach ($postComments as $comment) {
echo "Post Comment: " . $comment->body . "
";
}
// Retrieve comments for a video
$videoComments = App\Models\Video::find($video->id)->comments;
foreach ($videoComments as $comment) {
echo "Video Comment: " . $comment->body . "
";
}
// Retrieve the parent of a comment (can be Post or Video)
$comment = App\Models\Comment::find(1); // Assuming this comment exists
if ($comment) {
echo "Comment parent type: " . $comment->commentable_type . "
"; // e.g., App\\Models\\Post
echo "Comment parent ID: " . $comment->commentable_id . "
"; // e.g., 1
echo "Comment belongs to: " . ($comment->commentable->title ?? 'N/A') . "
";
}
How it works: Polymorphic relationships in Laravel Eloquent allow a single model to belong to more than one other model on a single association. For instance, a `Comment` model might belong to either a `Post` or a `Video` model. This is achieved by adding two columns (`commentable_id` and `commentable_type`) to the `comments` table using `$table->morphs('commentable')`. `morphTo()` is used on the child model (`Comment`) to define the generic relationship, while `morphMany()` (or `morphOne()`) is used on the parent models (`Post`, `Video`) to define the inverse relationship, enabling highly flexible and reusable data structures.