Search code examples
laraveleloquentrelationbelongs-to

Laravel / Eloquent - custom relation method


I have a class Report which has a belongsToMany relation to Metric. Report also additionally has a belongsTo relation to Metric.

Normally, the model returned by the belongsTo relation is the same as one of the models in the belongsToMany relation. When this is true I'd like it to be the case that each of the two relations actually looks at the same object instance (this also saves an extra trip to the db).

So, in basic terms - is there a way to get one relation to check another first, to see if a model has already been loaded, and if so, point to that object rather than creating a new one.

I tried putting some code in the belongsTo relation method for Metric but I can't get round the fact it needs to return an instance of belongsTo, which needs various things passed as constructor arguments (ie. a query object), which aren't relevant in that case that the model has already been loaded in the belongsToMany relation.

I thought of ditching the belongsTo relation and adding data horizontally in the pivot table for the belongsToMany relation, but it isn't a many-to-many relation required so that seems a bit wrong.

Thanks!

Geoff


Solution

  • The idea here is to write a function which would check if a relationship is loaded and return that relationship, otherwise it will return the belongsToMany. This would go in your Report class. This is also for Laravel 5. If you have 4, just remove the namespaces from the model names.

    public function metric()
    {
        return $this->belongsTo('App\Metric');
    }
    
    public function metrics()
    {
        return $this->belongsToMany('App\Metric');
    }
    
    public function getMetric()
    {
        if(array_key_exists('metric', $this->getRelations())) {
            return $this->metric;
        }
    
        return $this->metrics()->first();
    }
    

    If you do decide to just go with a belongsToMany only, I'd suggest putting a unique key on your pivot table for both ID's to keep from getting any duplicates in the pivot table.