PHP

Implementing Laravel Eloquent Polymorphic One-to-Many Relationships

Connect a single model to multiple other models using a polymorphic one-to-many relationship in Laravel Eloquent, ideal for versatile associations like comments or notifications.

// In App\Models\Comment.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;

class Comment extends Model
{
    protected $fillable = ['body'];

    /**
     * Get the parent model (post or video) that owns the comment.
     */
    public function commentable(): MorphTo
    {
        return $this->morphTo();
    }
}

// In App\Models\Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphMany;

class Post extends Model
{
    protected $fillable = ['title', 'body'];

    /**
     * Get all of the post's comments.
     */
    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

// In App\Models\Video.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphMany;

class Video extends Model
{
    protected $fillable = ['title', 'url'];

    /**
     * Get all of the video's comments.
     */
    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

// Usage example
use App\Models\Post;
use App\Models\Video;
use App\Models\Comment;

// Create a post and a video
$post = Post::create(['title' => 'My First Post', 'body' => 'Content of the post.']);
$video = Video::create(['title' => 'Laravel Tutorial', 'url' => 'https://example.com/video']);

// Add comments to the post
$post->comments()->create(['body' => 'Great post!']);
$post->comments()->create(['body' => 'Very informative.']);

// Add comments to the video
$video->comments()->create(['body' => 'Awesome video!']);
$video->comments()->create(['body' => 'Helped me a lot.']);

// Retrieve comments for the post
$postComments = $post->comments;
echo "Comments for Post '{$post->title}':
";
foreach ($postComments as $comment) {
    echo "- {$comment->body}
";
}

// Retrieve comments for the video
$videoComments = $video->comments;
echo "
Comments for Video '{$video->title}':
";
foreach ($videoComments as $comment) {
    echo "- {$comment->body}
";
}

// Retrieve a comment and its parent
$firstComment = Comment::first();
if ($firstComment) {
    echo "
First comment body: {$firstComment->body}
";
    echo "It belongs to type: " . $firstComment->commentable_type . " with ID: " . $firstComment->commentable_id . "
";
    echo "Parent Title: " . $firstComment->commentable->title . "
";
}

// Database migration structure (example for 'comments' table)
// Schema::create('comments', function (Blueprint $table) {
//     $table->id();
//     $table->text('body');
//     $table->morphs('commentable'); // Adds commentable_id (INT) and commentable_type (VARCHAR)
//     $table->timestamps();
// });
How it works: Polymorphic relationships in Laravel Eloquent allow a model to belong to more than one other model on a single association. This snippet demonstrates a one-to-many polymorphic relationship where a `Comment` model can belong to either a `Post` or a `Video` model. The `Comment` model defines a `commentable()` method using `morphTo()`, and both `Post` and `Video` models define a `comments()` method using `morphMany()`, pointing to the `commentable` relationship. This structure uses two special columns in the `comments` table (`commentable_id` and `commentable_type`) to store the ID of the parent model and its class name, respectively, making the association highly flexible without adding redundant columns.

Need help integrating this into your project?

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

Hire DigitalCodeLabs