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

split19's avatar

nested relationship query

I have 3 tables: projects, entries and submissions

relationships:

Project hasMany(Entry:class)

Entry belongsTo(Project:class) and hasMany(Submissions:class) belongsTo(User:class)

Submission belongsTo(Entry:class)

submissions table has a round field (value is 1, 2 or 3)

How can I get a list of all submissions for a given Project, grouped by round and also grouped by user? Ie, I want to output a list like this:

Round 1

User 1: Submission 1

User 1: Submission 2

User 2: Submission 1

User 2: Submission 2

User 3: Submission 1

User 3: Submission 2

Round 2

User 1: Submission 1

User 1: Submission 2

User 2: Submission 1

User 2: Submission 2

User 3: Submission 1

User 3: Submission 2

Round 3

User 1: Submission 1

User 1: Submission 2

User 2: Submission 1

User 2: Submission 2

User 3: Submission 1

User 3: Submission 2

I tried the following, but it's not working. If I do a dd($allSubmissions) I get an error: Property [submissions] does not exist on this collection instance. I think I understand why this error is popping up, but not really. Can you explain?

$project = Project::with('entries.submissions')->findOrFail($id);
        
$allSubmissions = $project->entries->submissions;
dd($allSubmissions) 

// filter submissions
$submissions['r1'] = $allSubmissions->where('round',1)->filter(function ($submission, $key) use ($id) {
    return $submission->entry->project_id == $id;
});
$submissions['r2'] = $allSubmissions->where('round',2)->filter(function ($submission, $key) use ($id) {
    return $submission->entry->project_id == $id;
});
$submissions['r3'] = $allSubmissions->where('round',3)->filter(function ($submission, $key) use ($id) {
    return $submission->entry->project_id == $id;
});

How can I better write this query?

Does my db design need improvement?

Thank you very much!

0 likes
2 replies
split19's avatar
split19
OP
Best Answer
Level 3

I worked out the solution. Laravel has of course provided a simple way to do this: the hasManyThrough() relationship

Project model:

public function submissions()
{
    return $this->hasManyThrough(Submission::class, Entry::class);
}

Get all submissions on a Project through Entry

$project = Project::findOrFail($id);

$allSubmissions = $project->submissions()->with('entry')->get();

// group by round # and name key with round #
$rounds = $allSubmissions->groupBy(function ($submission, $key) {
    return $submission['round'];
});

// group submissions in each round by username and name key by username
foreach($rounds as $key => $submissionsInRound)
{
    $rounds[$key] = $submissionsInRound->groupBy(function ($submission, $key) {
        return $submission->entry->user->profile->username;
    });
    // or just $rounds[$key] = $submissionsInRound->groupBy('username')
}

Please or to participate in this conversation.