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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs