filament icon indicating copy to clipboard operation
filament copied to clipboard

Table records are duplicated when using HasManyThrough

Open Iilun opened this issue 5 months ago • 2 comments

Package

filament/tables

Package Version

v4.0.0-beta19

Laravel Version

v12.21.0

Livewire Version

v3.6.4

PHP Version

PHP 8.4.8

Problem description

When a model contains a HasManyThrough relationship and it is used when overriding a resource getEloquentQuery(), items are duplicated based on the Through table id.

For example if i want to filter records by user on the list page using a HasManyThrough relationship.

Users -> Throughs -> Items 

The two main changes to the default app are the HasManyThrough relation in App\Models\User.php

public function items(): HasManyThrough 
{
    return $this->hasManyThrough(Item::class, Through::class);
}

And the override of getEloquentQuery in the resource

public static function getEloquentQuery(): Builder
{
    return Auth::user()->items()->getQuery();
}

Expected behavior

Items are not duplicated. It is a regression from v3, where this was working properly.

V3:

Image

V4:

Image

Steps to reproduce

I have provided a repository with a relevant README to reproduce.

Reproduction repository (issue will be closed if this is not valid)

https://github.com/Iilun/filament-v4-has-many-through

Relevant log output

When running tinker queries, we can find the root cause. When using HasManyThrough->getQuery()->get(), the `id` field from the model is indeed the same as `trough_id`.
What's interesting is that this is NOT the case when querying the relation directly (without getQuery)


> User::first()->items()->getQuery()->limit(2)->get()
= Illuminate\Database\Eloquent\Collection {#7082
    all: [
      App\Models\Item {#7072
        id: 1,
        through_id: 1,
        name: "Harley Davis",
        created_at: "2025-07-26 20:40:21",
        updated_at: "2025-07-26 20:40:21",
        user_id: 1,
      },
      App\Models\Item {#7083
        id: 1,
        through_id: 1,
        name: "Connie Carter",
        created_at: "2025-07-26 20:40:21",
        updated_at: "2025-07-26 20:40:21",
        user_id: 1,
      },
    ],
  }
> User::first()->items()->limit(2)->get()
= Illuminate\Database\Eloquent\Collection {#7056
    all: [
      App\Models\Item {#7057
        id: 1,
        through_id: 1,
        name: "Harley Davis",
        created_at: "2025-07-26 20:40:21",
        updated_at: "2025-07-26 20:40:21",
        laravel_through_key: 1,
      },
      App\Models\Item {#7103
        id: 2,
        through_id: 1,
        name: "Connie Carter",
        created_at: "2025-07-26 20:40:21",
        updated_at: "2025-07-26 20:40:21",
        laravel_through_key: 1,
      },
    ],
  }

Update: It turns out this also induces a bug in v3, where the generated record link is for the through_id instead of item_id, even though the display is correct (the first three items all open page for id = 1)

Iilun avatar Jul 26 '25 21:07 Iilun

I think this issue occurs because, as the ID remains the same, the state is retrieved from the cache instead of fetching the state again from data. This seems related to the behavior discussed here: https://github.com/filamentphp/filament/issues/17275#issuecomment-3446915426

rohanAdhikari1 avatar Nov 03 '25 11:11 rohanAdhikari1

@Iilun I tried your repository, but I do not see any duplicate.

giacomomasseron avatar Nov 30 '25 11:11 giacomomasseron