Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/tables/docs/02-columns/01-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,20 @@ public function table(Table $table): Table
}
```

You can also use the `splitIndividualSearchTerms()` method on a column to override the table's setting for that column's [individual search](#searching-individually):

```php
use Filament\Tables\Columns\TextColumn;

TextColumn::make('title')
->searchable(isIndividual: true)
->splitIndividualSearchTerms(false)
```

<Aside variant="info">
This method only affects the column's individual search. Search term splitting for the table's global search is controlled by the table's `splitSearchTerms()` method.
</Aside>

## Clickable cell content

When a cell is clicked, you may open a URL or trigger an "action".
Expand Down
14 changes: 14 additions & 0 deletions packages/tables/src/Columns/Concerns/CanBeSearchable.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ trait CanBeSearchable

protected bool | Closure | null $isSearchForcedCaseInsensitive = null;

protected bool | Closure | null $shouldSplitIndividualSearchTerms = null;

/**
* @param bool | array<string> | string | Closure $condition
*/
Expand Down Expand Up @@ -54,6 +56,13 @@ public function forceSearchCaseInsensitive(bool | Closure | null $condition = tr
return $this;
}

public function splitIndividualSearchTerms(bool | Closure | null $condition = true): static
{
$this->shouldSplitIndividualSearchTerms = $condition;

return $this;
}

/**
* @return array<string>
*/
Expand Down Expand Up @@ -82,6 +91,11 @@ public function isSearchForcedCaseInsensitive(): ?bool
return $this->evaluate($this->isSearchForcedCaseInsensitive);
}

public function shouldSplitIndividualSearchTerms(): ?bool
{
return $this->evaluate($this->shouldSplitIndividualSearchTerms);
}

/**
* @return array{0: string}
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/tables/src/Concerns/CanSearchRecords.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected function applySearchToTableQuery(Builder $query): Builder
protected function applyColumnSearchesToTableQuery(Builder $query): Builder
{
$table = $this->getTable();
$shouldSplitSearchTerms = $table->shouldSplitSearchTerms();
$shouldSplitSearchTermsByDefault = $table->shouldSplitSearchTerms();

foreach ($this->getTableColumnSearches() as $column => $search) {
if (blank($search)) {
Expand All @@ -96,7 +96,7 @@ protected function applyColumnSearchesToTableQuery(Builder $query): Builder
continue;
}

if (! $shouldSplitSearchTerms) {
if (! ($column->shouldSplitIndividualSearchTerms() ?? $shouldSplitSearchTermsByDefault)) {
$isFirst = true;

$column->applySearchConstraint(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Filament\Tests\Fixtures\Livewire;

use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Contracts\HasSchemas;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Filament\Tests\Fixtures\Models\Post;
use Illuminate\Contracts\View\View;
use Livewire\Component;

class PostsTableWithColumnIndividualSearchTermSplittingDisabled extends Component implements HasActions, HasSchemas, HasTable
{
use InteractsWithActions;
use InteractsWithSchemas;
use InteractsWithTable;

public function table(Table $table): Table
{
return $table
->query(Post::query())
->columns([
TextColumn::make('title')
->searchable(isIndividual: true, isGlobal: false),
TextColumn::make('content')
->searchable(isIndividual: true, isGlobal: false)
->splitIndividualSearchTerms(false),
]);
}

public function render(): View
{
return view('livewire.table');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Filament\Tests\Fixtures\Livewire;

use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Schemas\Concerns\InteractsWithSchemas;
use Filament\Schemas\Contracts\HasSchemas;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Filament\Tests\Fixtures\Models\Post;
use Illuminate\Contracts\View\View;
use Livewire\Component;

class PostsTableWithColumnIndividualSearchTermSplittingEnabled extends Component implements HasActions, HasSchemas, HasTable
{
use InteractsWithActions;
use InteractsWithSchemas;
use InteractsWithTable;

public function table(Table $table): Table
{
return $table
->query(Post::query())
->splitSearchTerms(false)
->columns([
TextColumn::make('title')
->searchable(isIndividual: true, isGlobal: false),
TextColumn::make('content')
->searchable(isIndividual: true, isGlobal: false)
->splitIndividualSearchTerms(),
]);
}

public function render(): View
{
return view('livewire.table');
}
}
40 changes: 40 additions & 0 deletions tests/src/Tables/ColumnTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
use Filament\Tables\Columns\TextColumn;
use Filament\Tests\Fixtures\Livewire\CustomDataTable;
use Filament\Tests\Fixtures\Livewire\PostsTable;
use Filament\Tests\Fixtures\Livewire\PostsTableWithColumnIndividualSearchTermSplittingDisabled;
use Filament\Tests\Fixtures\Livewire\PostsTableWithColumnIndividualSearchTermSplittingEnabled;
use Filament\Tests\Fixtures\Livewire\PostsTableWithQualifiedColumns;
use Filament\Tests\Fixtures\Livewire\PostsTableWithReservedJsPropertyColumnSearch;
use Filament\Tests\Fixtures\Livewire\PostsTableWithTableSearchableColumns;
Expand Down Expand Up @@ -356,6 +358,44 @@
->assertCanNotSeeTableRecords($posts->where('author.email', '!=', $authorEmail));
});

it('can use `splitIndividualSearchTerms(false)` on a column to disable search term splitting for its individual search', function (): void {
$exactPhrasePost = Post::factory()->create(['content' => 'ipsum dolor']);
$separateWordsPost = Post::factory()->create(['content' => 'ipsum sit dolor']);

livewire(PostsTableWithColumnIndividualSearchTermSplittingDisabled::class)
->searchTableColumns(['content' => 'ipsum dolor'])
->assertCanSeeTableRecords([$exactPhrasePost])
->assertCanNotSeeTableRecords([$separateWordsPost]);
});

it('splits search terms for an individual column search by default, when the column does not define `splitIndividualSearchTerms()`', function (): void {
$exactPhrasePost = Post::factory()->create(['title' => 'ipsum dolor']);
$separateWordsPost = Post::factory()->create(['title' => 'ipsum sit dolor']);

livewire(PostsTableWithColumnIndividualSearchTermSplittingDisabled::class)
->searchTableColumns(['title' => 'ipsum dolor'])
->assertCanSeeTableRecords([$exactPhrasePost, $separateWordsPost]);
});

it('can use `splitIndividualSearchTerms()` on a column to enable search term splitting for its individual search when the table uses `splitSearchTerms(false)`', function (): void {
$exactPhrasePost = Post::factory()->create(['content' => 'ipsum dolor']);
$separateWordsPost = Post::factory()->create(['content' => 'ipsum sit dolor']);

livewire(PostsTableWithColumnIndividualSearchTermSplittingEnabled::class)
->searchTableColumns(['content' => 'ipsum dolor'])
->assertCanSeeTableRecords([$exactPhrasePost, $separateWordsPost]);
});

it('does not split search terms for an individual column search when the table uses `splitSearchTerms(false)` and the column does not define `splitIndividualSearchTerms()`', function (): void {
$exactPhrasePost = Post::factory()->create(['title' => 'ipsum dolor']);
$separateWordsPost = Post::factory()->create(['title' => 'ipsum sit dolor']);

livewire(PostsTableWithColumnIndividualSearchTermSplittingEnabled::class)
->searchTableColumns(['title' => 'ipsum dolor'])
->assertCanSeeTableRecords([$exactPhrasePost])
->assertCanNotSeeTableRecords([$separateWordsPost]);
});

it('seeds individually searchable columns whose names collide with JS array properties on mount so `tableColumnSearches` serializes as a JSON object', function (): void {
livewire(PostsTableWithReservedJsPropertyColumnSearch::class)
->assertSet('tableColumnSearches', ['length' => '', 'sort' => '']);
Expand Down
Loading