laravelmastery
SnippetsArticlesSeriesNews

Eloquent, properly · Lesson 2 of 3

Eloquent, properly · Lesson 2

Belongs-to and whereBelongsTo

Connect itEloquentQueries

Creating a line through the invoice set invoice_id for you. belongsTo is the other direction: a line knows its invoice, an invoice knows its team. The method name is the relationship, singular. The foreign key still lives on the model that points, which is the invoice for team_id and the line for invoice_id.

Video

01 Filter by the parent you already have

whereBelongsTo() reads cleaner than where('team_id', $team->id), and it stays correct if the foreign key is ever renamed. The helper reads the key from the relationship. The controller stops naming the column. A rename of team_id on the relationship is then a change in one method, not a search through every query.

Example.phpPHP
class Example
{
    public function team(): BelongsTo
    {
        return $this->belongsTo(Team::class);
    }
}

$invoices = Invoice::query()
    ->whereBelongsTo($team)
    ->where('status', 'issued')
    ->latest('issued_on')
    ->get();

The same idea is the whole of the snippet on querying by a relationship. That page is the short version of this lesson. It also shows a collection of teams, which is the next case once a person can see more than one.

Query by a relationship.

When you already have the parent and want its children, prefer $team->invoices() over a fresh query. The relationship is the constraint. A new query is how the team id gets forgotten. whereBelongsTo() is the tool for a query that started on Invoice. The relationship method is the tool when you started on the team. Both keep the column off the call site.

02 Point an existing invoice at a team, then save it

whereBelongsTo() filters. associate() writes. You already have the invoice, the user has chosen a team they are allowed to move it to, and you need the foreign key updated without putting team_id in $fillable. associate() sets the key on the model and does not touch the database until you save().

PHP
$invoice->team()->associate($team);
$invoice->save();

Forget the save() and the in-memory invoice looks moved while the row still has the old team_id. The next request loads the old team. dissociate() clears the key the same way, and it also waits for save(). An invoice in this app should not be dissociated: the migration made team_id required, and a null team is not a draft. Use associate() when the product allows a move. Keep creating new invoices through $team->invoices()->create(), so a form still cannot pick a tenant by posting a hidden field.

whereBelongsTo() accepts a collection when the reader may see several teams. The query becomes where team_id is in that set. A global scope on Invoice still applies. whereBelongsTo() does not turn it off, and associate() does not either. If a scope already limits the team, a move that the scope forbids will not be visible on the next read, which is a reason to keep the team filter local and obvious until you mean it to be global.

A line uses the same pair of ideas, with the names swapped. invoice() is the belongsTo. $invoice->lines() is how you already created the row. whereBelongsTo($invoice) is how you find lines when the query did not start from that invoice. One parent, singular method, foreign key on the child.

Recap

You can list a team's invoices with whereBelongsTo(), and move an existing invoice with associate() plus save().

  • belongsTo is the singular side: a line's invoice, an invoice's team.
  • When you already hold the team, $team->invoices() is the constraint.
  • A fresh query is how the team id gets forgotten.
  • associate() changes the model. save() writes the row.

Check yourself · 3 questions

Question 1 of 3You have the team model and want its invoices. Which call keeps the foreign key on the relationship?

The invoice knows its team. Next, a tag that can sit on many invoices.

← PreviousOne to many, without the surprises

On this page

  • Filter by the parent you already have
  • Point an existing invoice at a team, then save it
  • Recap
  • Check yourself

Eloquent, properly

  • 1 Overview

Shape the data

  • 2 Models that match the domain
  • 3 Migrations you can still read next year
  • 4 Casts, enums and custom casters

Connect it

  • 5 One to many, without the surprises
  • 6 Belongs-to and whereBelongsTo
  • 7 Many to many and pivot data
  • 8 Has many through

Query it safely and fast

  • 9 Local and global scopes
  • 10 Eager loading on purpose
  • 11 Catching N+1 queries
  • 12 Indexes, select and chunking
  • 13 API resources without leaking attributes

Eloquent, properly

Lessons

  1. 01Overview

Shape the data

  1. 02Models that match the domain
  2. 03Migrations you can still read next year
  3. 04Casts, enums and custom casters

Connect it

  1. 05One to many, without the surprises
  2. 06Belongs-to and whereBelongsTo
  3. 07Many to many and pivot data
  4. 08Has many through

Query it safely and fast

  1. 09Local and global scopes
  2. 10Eager loading on purpose
  3. 11Catching N+1 queries
  4. 12Indexes, select and chunking
  5. 13API resources without leaking attributes

Get the Friday email

One snippet and the week’s Laravel news, in your inbox every Friday morning. Unsubscribe whenever you like.

laravelmastery

Practical Laravel learning for working developers, made in the UK.

Learn

  • Snippets
  • Articles
  • Series

Stay current

  • News
  • Friday email
  • RSS feed

Company

  • About
  • Privacy
  • Terms
© 2026 Laravel Mastery. Independent and not affiliated with Laravel Holdings Inc.Designed and built by Half Shell Studios

We remember the videos you watch, where you left off, and which series lessons you mark as read, against this connection’s address. Nothing is stored until you agree.