Skip to content

Commit a33e3a3

Browse files
fix: match record filter values against json storage regardless of cardinality (#202)
Record fields always persist to json_value because RecordFieldType is declared as a multiChoice schema, but the filter branched on allow_multiple and queried string_value for single-value fields. That column is never populated, so filtering a single-value record field returned no rows. Also renders option labels as HTML. formatOptionWithAvatar() returns avatar markup, which SelectFilter escaped by default, printing the raw div in the dropdown.
1 parent 9700a91 commit a33e3a3

2 files changed

Lines changed: 50 additions & 14 deletions

File tree

src/Filament/Integration/Components/Tables/Filters/RecordFilter.php

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Relaticle\CustomFields\Filament\Integration\Components\Tables\Filters;
66

7+
use Filament\Forms\Components\Select;
78
use Filament\Tables\Filters\SelectFilter as FilamentSelectFilter;
89
use Illuminate\Database\Eloquent\Builder;
910
use Illuminate\Database\Eloquent\Model;
@@ -23,33 +24,28 @@ final class RecordFilter extends AbstractTableFilter
2324
*/
2425
public function make(CustomField $customField): FilamentSelectFilter
2526
{
26-
$isMultiSelect = $customField->settings->allow_multiple ?? false;
27-
2827
$filter = FilamentSelectFilter::make($customField->getFieldName())
2928
->multiple()
3029
->label($customField->name)
3130
->searchable()
32-
->native(false);
31+
->native(false)
32+
->modifyFormFieldUsing(fn (Select $field): Select => $field->allowHtml());
3333

3434
$filter = $this->configureLookup($filter, $customField->lookup_type);
3535

36-
$filter->query(function (array $data, Builder $query) use ($customField, $isMultiSelect): Builder {
36+
$filter->query(function (array $data, Builder $query) use ($customField): Builder {
3737
if (empty($data['values'])) {
3838
return $query;
3939
}
4040

41-
return $query->whereHas('customFieldValues', function (Builder $q) use ($customField, $data, $isMultiSelect): void {
41+
return $query->whereHas('customFieldValues', function (Builder $q) use ($customField, $data): void {
4242
$q->where('custom_field_id', $customField->id);
4343

44-
if ($isMultiSelect) {
45-
$q->where(function (Builder $subQuery) use ($data): void {
46-
foreach ($data['values'] as $value) {
47-
$subQuery->orWhereJsonContains('json_value', $value);
48-
}
49-
});
50-
} else {
51-
$q->whereIn('string_value', $data['values']);
52-
}
44+
$q->where(function (Builder $subQuery) use ($data): void {
45+
foreach ($data['values'] as $value) {
46+
$subQuery->orWhereJsonContains('json_value', $value);
47+
}
48+
});
5349
});
5450
});
5551

tests/Feature/Integration/Resources/Pages/ListRecordsTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,43 @@
411411
->assertTableColumnStateSet('custom_fields.internal_notes', 'Internal review needed', $draftPost);
412412
});
413413
});
414+
415+
describe('Record Field Filtering', function (): void {
416+
beforeEach(function (): void {
417+
$this->section = CustomFieldSection::factory()->create([
418+
'name' => 'Post Relations',
419+
'entity_type' => Post::class,
420+
'active' => true,
421+
]);
422+
});
423+
424+
it('filters by a record field regardless of cardinality', function (bool $allowMultiple, string $code): void {
425+
$field = CustomField::factory()->create([
426+
'custom_field_section_id' => $this->section->id,
427+
'name' => 'Related Post',
428+
'code' => $code,
429+
'type' => 'record',
430+
'entity_type' => Post::class,
431+
'lookup_type' => Post::class,
432+
'settings' => new CustomFieldSettingsData(
433+
visible_in_list: true,
434+
list_toggleable_hidden: false,
435+
allow_multiple: $allowMultiple,
436+
),
437+
]);
438+
439+
$target = Post::factory()->create();
440+
$linked = Post::factory()->create();
441+
$unlinked = Post::factory()->create();
442+
443+
$linked->saveCustomFieldValue($field, [$target->getKey()]);
444+
445+
livewire(ListPosts::class)
446+
->set(sprintf('tableFilters.custom_fields.%s.values', $code), [$target->getKey()])
447+
->assertCanSeeTableRecords([$linked])
448+
->assertCanNotSeeTableRecords([$unlinked]);
449+
})->with([
450+
'single-value' => [false, 'related_post_single'],
451+
'multi-value' => [true, 'related_post_multi'],
452+
]);
453+
});

0 commit comments

Comments
 (0)