Skip to content

Add whenRelation to Eloquent relations#60306

Open
mashirou1234 wants to merge 1 commit into
laravel:13.xfrom
mashirou1234:fix/53292-relation-when-preserves-relation
Open

Add whenRelation to Eloquent relations#60306
mashirou1234 wants to merge 1 commit into
laravel:13.xfrom
mashirou1234:fix/53292-relation-when-preserves-relation

Conversation

@mashirou1234
Copy link
Copy Markdown

@mashirou1234 mashirou1234 commented May 28, 2026

Summary

This adds whenRelation() to Eloquent relations.

This addresses #53292, where calling when() on a relationship forwards the call
to the underlying Eloquent builder instead of passing the relationship instance
to the callback.

$user->posts()
    ->whenRelation($condition, function (BelongsToMany $relation) {
        return $relation->wherePivotIn('post_id', [1, 2]);
    });

The existing when() behavior is left unchanged so callbacks typed as
Illuminate\Database\Eloquent\Builder continue to work.

Fixes #53292.

Tests

  • Added coverage for whenRelation() callbacks receiving the relation instance.
  • Added coverage that when() continues to receive the underlying builder.

Add Relation::whenRelation() as a non-breaking alternative to when() for cases
where the conditional callback needs the relation instance instead of the
forwarded Eloquent builder.

The existing when() behavior is preserved so typed callbacks that expect an
Illuminate\Database\Eloquent\Builder continue to work. Tests cover the new
relation-aware callbacks and the existing forwarded when() callback behavior.
@shaedrich
Copy link
Copy Markdown
Contributor

First things first, it would have helped me understand this if there was an example in the PR description

The existing when() call is forwarded to the underlying Eloquent builder, so changing it would be a breaking change for callbacks typed as Illuminate\Database\Eloquent\Builder.

Okay, so

User::query()->posts()->when(...);

doesn't work, right?

And now we can do

User::query()->posts()->whenRelation(...);

as if it was when(), correct?

Without this context and by just seeing the method name, I would assume, I would have to write

User::query()->whenRelation('posts', ...);

@mashirou1234
Copy link
Copy Markdown
Author

Sorry about that, and thanks for pointing it out.

I've updated the description to show that whenRelation() is intended to be
called on the relationship instance, not as
User::query()->whenRelation('posts', ...).

@shaedrich
Copy link
Copy Markdown
Contributor

Thanks for updating to prevent misunderstandings. However, I would find whenRelation('posts', ...) more intuitive

@mashirou1234
Copy link
Copy Markdown
Author

That makes sense. I see how whenRelation() can suggest something closer to
whereRelation(), where the relation name is passed as the first argument.

The intent here is narrower: an opt-in when()-style helper for an already
created relationship instance, without changing the existing forwarded when()
behavior.

Given that, I agree the current name may be misleading. I'm open to renaming it
if there is a better fit for Laravel's API conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Conditional (when helper) gives back Eloquent Builder instance inside the closure instead of the relationship instance

2 participants