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

dmytroshved's avatar

Filament Repeater belongsToMany

Hey everyone, I need to be able to handle creation process after submitting my Wizard Form to create Recipe.

Wizard steps:

  1. Recipe Info
  2. Ingredients
  3. Guide

I need to be able to save data in that particular order:

  1. Prepare an array of ingredients that, in its format, will be suitable for saving in a pivot table.
  2. Update/Create Recipe instance using ingredients array to save into pivot table
  3. Store/Update group of steps into GuideStep model

Filament has a lot of automated processes and I'm unclear where and how I can intercept that and apply my own save logic. I’ve seen that mutateFormDataBeforeCreate() and afterCreate() hooks exist — but I’m not sure:

  • Which is the proper place to run this logic?
  • Should I avoid using ->relationship() inside the Repeater to disable automatic persistence?
  • How can I fully bypass Filament’s auto-saving of related data and take control manually?

Recipe.php

class Recipe extends Model
{
    public function ingredients(): BelongsToMany
    {
        return $this->belongsToMany(Ingredient::class)
            ->using(IngredientRecipe::class)
            ->withTimestamps()
            ->withPivot(['quantity', 'unit_id']);
    }
}

IngredientRecipe (pivot model with relationship into another table)

class IngredientRecipe extends Pivot
{
    protected $table = 'ingredient_recipe';

    public function unit(): BelongsTo
    {
        return $this->belongsTo(Unit::class);
    }
}

Ingredient

class Ingredient extends Model
{
    use EagerLoadPivotTrait;

    protected $fillable = ['name'];

    public function recipes(): BelongsToMany
    {
        return $this->belongsToMany(Recipe::class);
    }
}

Would be grateful for your advices and help

Best regards

1 like
4 replies
AddWebContribution's avatar

If you're using Repeater::make()->relationship('ingredients'), Filament will automatically persist those records

Use the mutateFormDataBeforeCreate() to clean or prepare the data

Use afterCreate() or afterSave() to do the actual persistence logic.

But for most manual saving, afterCreate() (or afterSave() for update too) is best.

To handle updating the same way, just override the same logic in EditRecipe.php using:

  • mutateFormDataBeforeSave()

  • afterSave()

1 like
dmytroshved's avatar

@AddWebContribution

To handle updating the same way, just override the same logic in EditRecipe.php using: mutateFormDataBeforeSave() and afterSave() <

But then the code in mutateFormDataBeforeCreate() and mutateFormDataBeforeSave() will be duplicated, right? What can I do to avoid code duplication in these places?

AddWebContribution's avatar

@Dmytro_Shved To avoid duplication, you can extract shared logic into private helper methods inside your CreateRecipe and EditRecipe classes or better yet, into a trait or service class if shared across both.

1 like
dmytroshved's avatar

Wanna to leave here some useful links and things I got while researching:

Below I've added example of my own implementation


Relations

Recipe.php model

    // Relation for the Filament Repeater
    public function ingredientRecipe(): HasMany
    {
        return $this->hasMany(IngredientRecipe::class);
    }

    // Regular relation belongsToMany
    public function ingredients(): BelongsToMany
    {
        return $this->belongsToMany(Ingredient::class)
            ->using(IngredientRecipe::class)
            ->withTimestamps()
            ->withPivot(['quantity', 'unit_id']);
    }

IngredientRecipe.php pivot model

    // Set relationships as in the docs (link above)

    public function recipe(): BelongsTo
    {
        return $this->belongsTo(Recipe::class);
    }

    public function ingredient(): BelongsTo
    {
        return $this->belongsTo(Ingredient::class);
    }

Ingredient.php

    public function recipes(): BelongsToMany
    {
        return $this->belongsToMany(Recipe::class);
    }

Filament Code

And then in the Filament Repeater:

Have a good coding

Please or to participate in this conversation.