Skip to content

[12.x] Add *OrFail transaction methods to BelongsToMany#59153

Merged
taylorotwell merged 2 commits intolaravel:12.xfrom
SanderMuller:feature/belongs-to-many-or-fail
Mar 11, 2026
Merged

[12.x] Add *OrFail transaction methods to BelongsToMany#59153
taylorotwell merged 2 commits intolaravel:12.xfrom
SanderMuller:feature/belongs-to-many-or-fail

Conversation

@SanderMuller
Copy link
Contributor

Adds syncOrFail(), syncWithoutDetachingOrFail(), attachOrFail(), detachOrFail(), and toggleOrFail() to the BelongsToMany relationship, wrapping each operation in a database transaction.

This follows the existing saveOrFail() / deleteOrFail() / updateOrFail() convention on Model. While single-query operations like attach(1) are already atomic, multi-query operations like sync() and toggle() perform detaches and attaches in sequence. If one fails partway through, the pivot table is left in a partial state. These methods guarantee all-or-nothing behavior.

New methods

Method Wraps
syncOrFail($ids, $detaching) sync()
syncWithoutDetachingOrFail($ids) syncWithoutDetaching()
attachOrFail($id, $attributes, $touch) attach()
detachOrFail($ids, $touch) detach()
toggleOrFail($ids, $touch) toggle()

Each method is placed directly after its base counterpart in the InteractsWithPivotTable trait.

Usage

  // Sync roles atomically — rolls back if any query fails
  $user->roles()->syncOrFail([1, 2, 3]);

  // Attach within a transaction (useful with custom pivot classes)
  $user->roles()->attachOrFail($roleId, ['expires_at' => now()->addYear()]);

Test plan

  • testSyncOrFail — verifies sync returns correct attached/detached/updated arrays
  • testSyncWithoutDetachingOrFail — verifies existing attachments are preserved
  • testAttachOrFail — verifies basic attach
  • testAttachOrFailWithAttributes — verifies pivot attributes are set
  • testDetachOrFail — verifies partial detach returns correct count
  • testDetachOrFailAll — verifies detach with no args removes all
  • testToggleOrFail — verifies toggle attaches/detaches correctly

@taylorotwell taylorotwell merged commit abe37f5 into laravel:12.x Mar 11, 2026
72 checks passed
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.

2 participants