CJ Thompson
CJ Thompson

Reputation: 2869

Access multiple pivot tables with one eloquent model

Contrived example: go!

Say I have a Dog.

This Dog can be owned by Users and Companys, any number of each. (It's a lovable dog).

So we're working with 5 tables so far:

Now, to complicate things, each pivot table has an extra field or two. Let's say the the Companies track the dog's shot records is_shotted and the Users track his feeding is_fed.

Assuming I have the relationships set up properly on User, Company, and Dog, I can do:

$users->dogs()->first()->pivot->is_fed

to access one pivot table and

$companies->dogs()->first()->pivot->is_shotted

to access the other.

But how do I access both? I want a way to retroactively "activate" a relationship. Something like this only better:

$dog = $users->dogs->first();
$is_fed = $dog->pivot->is_fed;
$dog->addPivot( $company );
$is_shotted = $dog->pivot->is_shotted;

Is there any way to do this without doing raw DB queries on the pivot table? I really want to avoid that, it makes things very messy sometimes.

As an consolation alternative: is there a "right" way to add data onto a model, properties that aren't on the table, that will persist through the request and will still be toArray()ed? (I can modify the accessor if needed.)

Upvotes: 0

Views: 1023

Answers (1)

damiani
damiani

Reputation: 7371

Once you have the $dog object, call your dog_company inverse relation, i.e. $dog->companies()->first()->pivot->is_shotted to work backwards from dog up to company. Or if the dog can belong to multiple companies, $dog->companies would retrieve them all, and you would need to decide which company to check is_shotted on.


If you need to retrieve is_shotted and is_walked as part of one result collection, you could use an accessor and merge the two relations. So, for instance, starting from the dog model, you could:

public function getOwnersAttribute($value)
{
    $ownerUser = $this->users;
    $ownerCompany = $this->company;

    // Return a single collection result
    return $ownerUser->merge($ownerCompany);
}

or, tacking additional methods on to the relations:

public function getOwnersAttribute($value)
{
    $ownerUser = $this->users()->latest()->get();
    $ownerCompany = $this->company()->latest()->get();

    // Return a single collection result
    return $ownerUser->merge($ownerCompany);
}

I would imagine you could modify this accessor to go from user -> dog -> company and merge the result into a single collection, but I haven't tested that.

Upvotes: 1

Related Questions