0
votes

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

1
I would think again about ditching the belongsTo relationship. The advantage of belongsToMany is that it's flexible and allows a relationship of 0, 1, or many records to relate. The drawback is you need an extra table (pivot table) to manage it. You need that pivot table anyway so just stick with belongsToMany and save yourself the confusion. If you are set on both, I think I've figured out how to do what you wish to do.user1669496
You're probably right, but what puts me off is that the context of the belongsTo relationship is such that there must only ever be one. Using the pivot table approach with a boolean column to mark one of the belongsToMany relations as a special one seems instinctively wrong because there is nothing to stop multiple records being marked as special. Only feels a bit wrong though, so maybe will do that as I imagine the only way to do it 'my way' would be many additions to Eloquent and seeing as I don't anticipate needing this elsewhere in the app, it's probably not worth the added complexity.Geoff Clayton
If there should only ever be 1, it does sound more like a belongsTo. I'll post a quick answer that I think should work.user1669496
Sorry to bring this back from the dead, but you could use a UNIQUE index on MySQL to enforce there only ever been 1 model marked as "special".Jim Rubenstein
Be careful about using unique indexes if using soft deletes. They can catch you out if you are not careful, since the uniqueness does not distinguish between soft-deleted and non-deleted rows.Jason

1 Answers

1
votes

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.