Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ounos's avatar

Model: many-to-many relationship

I have 3 tables. Lets say Person that has a many-to-many relationship with Department that has a many-to-many relationship with Function.

So, I want to get the functions for every department that a person belongs.

I am a bit confused how I can achieve that with Eloquent and how I should create my models.

Thank you in advance!

0 likes
9 replies
pmall's avatar

@RachidLaasri doesn't work with many to many.

@ounos There is no way to do it easily with eloquent. Except a many to many between users and functions.

DMA's avatar

To get a Person's departments, and each of those departments' functions:

Person::all()->with('department.function')->get()

This assumes you have the necessary relationships 'department' set up in the Person model, and a 'function' relationship in the Department model.

1 like
pmall's avatar

@DMA I think he wants something like $person->functions to loop through for example.

ounos's avatar

@pmall exactly! I need all functions, for every department that a person belongs to.

JarekTkaczyk's avatar

There is a little bit of my eloquent trickery that easily does the job:

// Assuming you want all Functions of User id = 1
$user = User::find(1);
$user->load(['departments.functions' => function ($q) use ( &$functions ) {
  $functions = $q->get()->unique();
});

// or
// User::with(['departments.functions' => function ($q) use ( &$functions ) {
//  $functions = $q->get()->unique();
// })->find(1);

// now
$functions; // collection of all functions of the user through his departments

Notice & - $functions is passed by reference and the query in the closure is executed instantly with get()

Doing so doesn't affect lazy/eager loading in any way - it runs additional query, but keeps the rresult before it's matched to the relation parents (departments in this case). Downside is this additional query, but it's really convenient to do it with this one-liner instead of loops. Additionally it will work for any level of nesting, ie. even if you have user >< department >< function >< somethingelse >< yetanotherlevel - you can get yetanotherlevel exactly the same - imagine how many foreach loops you would need otherwise...

Ozan's avatar

@ounos I think @DMA was right you need to use . while skipping from one segment deeper in relationships. This way you can get:

foreach($departments as $department)
{
    foreach($department->users as $user)
    {
        foreach($user->functions as $function)
        {
            //
        }
    }
}

I also use a function like that: Here is the query:

Category::with(['subCategories.products'])->get()->toArray();

Here is my blade:

@foreach($categories as $category)
    @foreach($category['sub_categories'] as $subCategory)
        <div class="nav-content-col">
            <h3>{{ $subCategory['name'] }}</h3>
            <ul>
                @foreach($subCategory['products'] as $product)
                <li>
                    {!! link_to_route('product', $product['name'], [$product['slug']]) !!}
                </li>
                @endforeach
            </ul>
        </div>
    @endforeach
@endforeach

Please or to participate in this conversation.