laravelmastery
SnippetsArticlesSeriesNews

All series

Series · Overview

Eloquent, properly

13 lessons2 hr 10 minIntermediateFreeEloquentQueries

Relationships, scopes, casts and query performance, built up from a real app rather than toy examples.

By the end, a team's invoices are modelled, related, scoped and listed in two queries, and served through an API that shows only the fields you chose.

Video

This series follows one invoice in a multi-tenant app. A team owns invoices. An invoice has lines. That is enough to show relationships, scopes and the queries that get expensive.

Each lesson is a page, with a short video and the code the video is about. Mark a lesson as read when you have tried the idea, then use Next. The last lesson points at the next series, and this overview stays one link away.

It is for a developer who already has a team and its invoices, and wants that model to be safe to query. You build the invoice, its lines and its tags, then a team-scoped list in two queries, then an API that shows only the fields you chose.

01 The model the lessons share

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

    public function lines(): HasMany
    {
        return $this->hasMany(InvoiceLine::class);
    }
}

Create the invoice from the team, so the foreign key is set by the relationship rather than by the request. The later lessons come back to this model: how a column is stored, how a list is queried, and what an API is allowed to show.

02 The lessons

  • Models that match the domain. Name the model and its methods for the words the team already uses, and leave the team id off the fillable list.
  • Migrations you can still read next year. Constrain the foreign key in the same migration, and keep an invoice number unique to its team.
  • Casts, enums and custom casters. Bring dates back as dates and a status back as an enum, so a typo never lands in the column.
  • One to many, without the surprises. Create an invoice's lines through the relationship, so the foreign key is set for you.
  • Belongs-to and whereBelongsTo. Query a team's invoices through the relationship instead of a hand-written team id.
  • Many to many and pivot data. Let a tag sit on many invoices, and keep the extra pivot column when you need it.
  • Has many through. Reach a team's invoice lines without loading every invoice in PHP first.
  • Local and global scopes. Name the constraints you mean, and keep a team filter local until a missed one has actually shipped a bug.
  • Eager loading on purpose. Load the relationships a page will touch, and leave the rest alone.
  • Catching N+1 queries. Turn a forgotten eager load into an exception outside production.
  • Indexes, select and chunking. Match the index to the list you actually run, and walk a large table without loading it.
  • API resources without leaking attributes. Decide the fields a client may see, so a new column does not become public by accident.

Part 1 of 3 · Shape the data

Models, migrations, casts.

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

Part 2 of 3 · Connect it

One to many, belongs-to, many to many, has many through.

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

Part 3 of 3 · Query it safely and fast

Scopes, eager loading, catching N+1, indexes, API resources.

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

Where the series leaves you

The invoice now has a path through the series.

  • The model and the fillable list.
  • The constrained foreign keys.
  • The relationships, and the forTeam() scope.
  • The two-query list behind the InvoiceResource.

Test-driven Laravel is how you prove all of it.

On this page

  • The model the lessons share
  • The lessons
  • Shape the data
  • Connect it
  • Query it safely and fast
  • Where the series leaves you

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.