defaultGroup set to attribute from parent relationship fractures group

Hi all, I have a Category model with a parent_id that can reference another category. This is only used for categories with a single level of subcategories below them. If I set defaultGroup('parent_id') it works as I'd expect, with the top level categories ungrouped at the top, followed by a group for each. However if I set defaultGroup('parent.title') the groups repeat themselves with only a couple of items under each level. There's no clear pattern to why they're grouped up separately, and in some cases it skips over a group until the next "cycle" Expected:
- Top Cat One
- Top Cat Two
- Top Cat Three
*Top Cat One*
- Sub cat one
- Sub cat two
- Sub cat three
*Top Cat Two*
- Sub cat four
- Sub cat five
- Sub cat six
*Top Cat Three*
- Sub cat seven
- Sub cat eight
- Sub cat nine
- Top Cat One
- Top Cat Two
- Top Cat Three
*Top Cat One*
- Sub cat one
- Sub cat two
- Sub cat three
*Top Cat Two*
- Sub cat four
- Sub cat five
- Sub cat six
*Top Cat Three*
- Sub cat seven
- Sub cat eight
- Sub cat nine
Actual:
- Top Cat One
- Top Cat Two
- Top Cat Three
*Top Cat One*
- Sub cat one
*Top Cat Two*
- Sub cat four
- Sub cat five
*Top Cat Three*
- Sub cat seven
*Top Cat One*
- Sub cat two
- Sub cat three
*Top Cat Three*
- Sub cat eight
- Sub cat nine
*Top Cat One*
- Sub cat three
*Top Cat Two*
- Sub cat six
- Top Cat One
- Top Cat Two
- Top Cat Three
*Top Cat One*
- Sub cat one
*Top Cat Two*
- Sub cat four
- Sub cat five
*Top Cat Three*
- Sub cat seven
*Top Cat One*
- Sub cat two
- Sub cat three
*Top Cat Three*
- Sub cat eight
- Sub cat nine
*Top Cat One*
- Sub cat three
*Top Cat Two*
- Sub cat six
7 Replies
Tetracyclic
Tetracyclic4mo ago
This behaviour is consistent with or without any sorting set, and whether or not the table includes a column for the parent.title. Using parent_id and rewriting the title using the record works as expected, but it lazy loads the parent relationship. Works as expected: ->defaultGroup('parent_id')
Group::make('parent_id')
->getTitleFromRecordUsing(fn (Category $record): string => $record->parent->title ?? '')
Group::make('parent_id')
->getTitleFromRecordUsing(fn (Category $record): string => $record->parent->title ?? '')
Fractures groups: ->defaultGroup('parent.title') Disabling pagination doesn't change the behaviour and the queries being run make sense:
select * from `categories` order by (select `categories`.`title` from `categories` as `laravel_reserved_0` where `laravel_reserved_0`.`id` = `categories`.`parent_id`) asc, `sort` asc limit 48 offset 0
select * from `categories` order by (select `categories`.`title` from `categories` as `laravel_reserved_0` where `laravel_reserved_0`.`id` = `categories`.`parent_id`) asc, `sort` asc limit 48 offset 0
select * from `categories` where `categories`.`id` in (1, 2, 3)
select * from `categories` where `categories`.`id` in (1, 2, 3)
Setting the key to the ID manually also doesn't change the behaviour:
Group::make('parent.title')
->getKeyFromRecordUsing(fn (Category $record): int => $record->parent_id ?? 0),
Group::make('parent.title')
->getKeyFromRecordUsing(fn (Category $record): int => $record->parent_id ?? 0),
Jordy
Jordy4mo ago
are your relations set up correctly?
Tetracyclic
Tetracyclic4mo ago
Yup, BelongsTo on parent()
Jordy
Jordy4mo ago
cant seem to replicate the issue you are facing so can't be of much help
Tetracyclic
Tetracyclic4mo ago
The groups shown are correct, and it works if I use getTitleFromRecordUsing(), but for some reason the default Filament behaviour is splitting them up , mostly, but not perfectly at letter boundaries. I assume it's related to it being grouped by a self-referential relationship. Possibly a collision on the order clause.
Tetracyclic
Tetracyclic4mo ago
It was as stupid as I thought. By default the query gets sorted by the grouping column, which is normalised using str($name)->afterLast('.'). But as this is a recursive relationship and we're sorting on the title, it ends up just sorting it by the title of the child and then applying the groups. Adding an orderQueryUsing call that sorts by the parent_id solves it, though it does mean the groups themselves won't be alphabetically sorted.
->defaultGroup(
Group::make('parent.title')
->orderQueryUsing(fn (Builder $query, string $direction) => $query->orderBy('parent_id', $direction)),
)
->defaultGroup(
Group::make('parent.title')
->orderQueryUsing(fn (Builder $query, string $direction) => $query->orderBy('parent_id', $direction)),
)