Eloquent Polymorphic One Of Many

Jim O'Halloran • September 28, 2021

laravel php

Eloquent in Laravel received a new "one of many" relationship type in Laravel 8.42. Laravel News explains this comparatively recent feature here.

It seems like the ideal use case for this is a one to many relationship, where one of the relations is a bit "special".

The examples in the linked Laravel News post are helpful, and include the case where a User has manu login sessions, but you use and want to access efficiently the "latest" login session.

The feature's PR shows this implemented as follows (and has other good info on the use case for this relation):

public function latest_login()
{
    $this->hasOne(Login::class)->orderByDesc('id');
}

The feature's original author (Lennart Carstens-Behrens) also provides this helpful repo with models containing additional examples.

Use With Polymorphic Relationships

My application has a generic "address" entity, which can be related to a bunch of different things via a polymorphic relationship. Addresses can be attached to either Customers or Contacts for example. I call this relationship adressable. Each adressable can have a bunch of different addresses, one of which is the "primary" address. Rather than iterating the entire address book collection all the time, I wanted to see if "One Of Many" could be used with a polymorphic relationship to get the primary address.

Here's what I came up with:

public function primaryAddress()
{
    return $this->morphOne(Address::class, 'addressable')
        ->ofMany(
            ['id' => 'max'],
            function ($q) {
                $q->where('primary', true);
            }
        );
}

This gets the last address (MAX(id)) where the primary field is set to true. The "last address" part is a bit redundant since in my case there should only ever be a single primary address, but it's nice that the edge case is handled in a consistent way.

All in all, this is a feature I see myself using a lot. The ability to put any arbitrary where conditions into the query builder makes it super versatile, and the fact that it plays nice with polymorphic relationships is just awesome!