Home > OS >  Laravel 8 - define relationships dynamically
Laravel 8 - define relationships dynamically

Time:12-06

So I'm trying to build out functionality to allow users to comment on different types of data. Blog posts, videos, images, documents, comments (reply to), etc. So each of those is going to need to define a relationship to the Comments model. So basically

public function comments()
{
  return $this->morphMany(Comment::class, 'commentable')->whereNull('parent_id');
}

Aside: (parent_id) is in there to allow for replying to comments.

Anyway, to reduce code duplication I can just create a Trait called, say, CommentsTrait which has the method above and just use it by the relevant models. Easy-peasy. The problem, though, is that in the Comment class I am going to have to hard code a method to define the relationship to blog posts, videos, images, documents, etc. So basically if I wanted another model to use comments, I would need to import the trait into that model and also add a method to Comment setting up the relationship. Not necessarily a bad thing but I would like to make that process a bit more dynamic. That way I can turn comments on/off only from the model using the trait (by including it or not) and that's that.

So is there a way to make it so the Comment model can dynamically determine (either internally or externally, say using a provider) which models are using the trait and set up the relationship that way?

thnx,
Christoph

CodePudding user response:

You only need one relationship method on Comment that would return what ever it belongs to. There should be a commentable_id and a commentable_type field on the comments table. The morphTo relationship would know what model it belongs to from the commentable_type field. You should only need this method on Comment:

public function commentable()
{
    return $this->morphTo();
}

Laravel 8.x Docs - Eloquent - Relationships - Polymorphic Relationships - One to Many morphTo

CodePudding user response:

Dynamic relationships are included in this way.

    Comment::resolveRelationUsing ('video', function ($commentModel) {

         return $commentModel->belongsTo(Video::class, 'commentable_id')
                             ->where('commentable_type', Video::class);
           //or simple 
           $commentModel->morphTo()->where(/*... */); // your custom logic
    });

You can place this in boot traits or in the service provider with your own conditions and logic.

  • Related