From 365bfa3d9ac497a4a022135c5561a860273eeab6 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Mon, 16 Jun 2025 13:27:23 +0200 Subject: [PATCH 1/5] Make stablesort configurable --- .../tables/src/Concerns/CanPaginateRecords.php | 5 +++++ .../src/Table/Concerns/CanPaginateRecords.php | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/tables/src/Concerns/CanPaginateRecords.php b/packages/tables/src/Concerns/CanPaginateRecords.php index d16e6a532e..ea8691ed70 100644 --- a/packages/tables/src/Concerns/CanPaginateRecords.php +++ b/packages/tables/src/Concerns/CanPaginateRecords.php @@ -30,6 +30,11 @@ trait CanPaginateRecords { $perPage = $this->getTableRecordsPerPage(); + if ($this->getTable()->getStableSort()) { + // Add orderBy key to ensure stable order results + $query->orderBy($query->getModel()->getQualifiedKeyName()); + } + if (version_compare(App::version(), '11.0', '>=')) { $total = $query->toBase()->getCountForPagination(); diff --git a/packages/tables/src/Table/Concerns/CanPaginateRecords.php b/packages/tables/src/Table/Concerns/CanPaginateRecords.php index ba92f0566f..81b031bf7f 100644 --- a/packages/tables/src/Table/Concerns/CanPaginateRecords.php +++ b/packages/tables/src/Table/Concerns/CanPaginateRecords.php @@ -20,6 +20,8 @@ trait CanPaginateRecords protected bool | Closure $hasExtremePaginationLinks = false; + protected bool $stableSort = false; + public function defaultPaginationPageOption(int | string | Closure | null $option): static { $this->defaultPaginationPageOption = $option; @@ -66,6 +68,13 @@ trait CanPaginateRecords return $this; } + public function stableSort(?bool $value = true): static + { + $this->stableSort = $value; + + return $this; + } + public function getDefaultPaginationPageOption(): int | string | null { $option = $this->evaluate($this->defaultPaginationPageOption); @@ -91,6 +100,11 @@ trait CanPaginateRecords return $this->evaluate($this->paginationPageOptions) ?? [5, 10, 25, 50, 'all']; } + public function getStableSort(): bool + { + return $this->stableSort; + } + public function isPaginated(): bool { return $this->evaluate($this->isPaginated) && (! $this->isGroupsOnly()); From 4e01d235c7db31e9331e9a9415210513b95bb8cd Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Wed, 18 Jun 2025 15:54:11 +0200 Subject: [PATCH 2/5] Rename to defaultKeySort --- .../src/Concerns/CanPaginateRecords.php | 5 --- .../tables/src/Concerns/CanSortRecords.php | 44 ++++++++++++++++--- .../src/Table/Concerns/CanPaginateRecords.php | 14 ------ .../src/Table/Concerns/CanSortRecords.php | 14 ++++++ .../Resources/Pages/ListRecordsTest.php | 17 +++++++ 5 files changed, 68 insertions(+), 26 deletions(-) diff --git a/packages/tables/src/Concerns/CanPaginateRecords.php b/packages/tables/src/Concerns/CanPaginateRecords.php index ea8691ed70..d16e6a532e 100644 --- a/packages/tables/src/Concerns/CanPaginateRecords.php +++ b/packages/tables/src/Concerns/CanPaginateRecords.php @@ -30,11 +30,6 @@ trait CanPaginateRecords { $perPage = $this->getTableRecordsPerPage(); - if ($this->getTable()->getStableSort()) { - // Add orderBy key to ensure stable order results - $query->orderBy($query->getModel()->getQualifiedKeyName()); - } - if (version_compare(App::version(), '11.0', '>=')) { $total = $query->toBase()->getCountForPagination(); diff --git a/packages/tables/src/Concerns/CanSortRecords.php b/packages/tables/src/Concerns/CanSortRecords.php index 123afce35f..740501036f 100644 --- a/packages/tables/src/Concerns/CanSortRecords.php +++ b/packages/tables/src/Concerns/CanSortRecords.php @@ -92,6 +92,8 @@ trait CanSortRecords $column->applySort($query, $sortDirection); + $this->applyDefaultKeySortToTableQuery($query); + return $query; } @@ -105,25 +107,53 @@ trait CanSortRecords ($sortColumn = $this->getTable()->getSortableVisibleColumn($defaultSort)) ) { $sortColumn->applySort($query, $sortDirection); - - return $query; - } - - if (is_string($defaultSort)) { - return $query->orderBy($defaultSort, $sortDirection); + $this->applyDefaultKeySortToTableQuery($query); + } elseif (is_string($defaultSort)) { + $query->orderBy($defaultSort, $sortDirection); } if ($defaultSort instanceof Builder) { - return $defaultSort; + $query = $defaultSort; } if (filled($query->toBase()->orders)) { + $this->applyDefaultKeySortToTableQuery($query); + return $query; } return $query->orderBy($query->getModel()->getQualifiedKeyName()); } + protected function applyDefaultKeySortToTableQuery(Builder $query): Builder + { + if (! $this->getTable()->hasDefaultKeySort()) { + return $query; + } + + $qualifiedKeyName = $query->getModel()->getQualifiedKeyName(); + + foreach ($query->toBase()->orders ?? [] as $order) { + if (($order['column'] ?? null) === $qualifiedKeyName) { + return $query; + } + + if ( + is_string($order['column'] ?? null) && + str($order['column'] ?? null)->contains('.') && + str($order['column'] ?? null)->afterLast('.')->is( + str($qualifiedKeyName)->afterLast('.') + ) + ) { + return $query; + } + } + + $query->orderBy($qualifiedKeyName); + + return $query; + } + /** * @deprecated Override the `table()` method to configure the table. */ diff --git a/packages/tables/src/Table/Concerns/CanPaginateRecords.php b/packages/tables/src/Table/Concerns/CanPaginateRecords.php index 81b031bf7f..ba92f0566f 100644 --- a/packages/tables/src/Table/Concerns/CanPaginateRecords.php +++ b/packages/tables/src/Table/Concerns/CanPaginateRecords.php @@ -20,8 +20,6 @@ trait CanPaginateRecords protected bool | Closure $hasExtremePaginationLinks = false; - protected bool $stableSort = false; - public function defaultPaginationPageOption(int | string | Closure | null $option): static { $this->defaultPaginationPageOption = $option; @@ -68,13 +66,6 @@ trait CanPaginateRecords return $this; } - public function stableSort(?bool $value = true): static - { - $this->stableSort = $value; - - return $this; - } - public function getDefaultPaginationPageOption(): int | string | null { $option = $this->evaluate($this->defaultPaginationPageOption); @@ -100,11 +91,6 @@ trait CanPaginateRecords return $this->evaluate($this->paginationPageOptions) ?? [5, 10, 25, 50, 'all']; } - public function getStableSort(): bool - { - return $this->stableSort; - } - public function isPaginated(): bool { return $this->evaluate($this->isPaginated) && (! $this->isGroupsOnly()); diff --git a/packages/tables/src/Table/Concerns/CanSortRecords.php b/packages/tables/src/Table/Concerns/CanSortRecords.php index 4c364c1896..798e555e61 100644 --- a/packages/tables/src/Table/Concerns/CanSortRecords.php +++ b/packages/tables/src/Table/Concerns/CanSortRecords.php @@ -18,6 +18,8 @@ trait CanSortRecords protected string | Htmlable | Closure | null $defaultSortOptionLabel = null; + protected bool | Closure $hasDefaultKeySort = false; + public function defaultSort(string | Closure | null $column, string | Closure | null $direction = 'asc'): static { $this->defaultSort = $column; @@ -40,6 +42,13 @@ trait CanSortRecords return $this; } + public function defaultKeySort(bool | Closure $condition = true): static + { + $this->hasDefaultKeySort = $condition; + + return $this; + } + public function getSortableVisibleColumn(string $name): ?Column { $column = $this->getColumn($name); @@ -121,4 +130,9 @@ trait CanSortRecords { return $this->evaluate($this->defaultSortOptionLabel) ?? '-'; } + + public function hasDefaultKeySort(): bool + { + return (bool) $this->evaluate($this->hasDefaultKeySort); + } } diff --git a/tests/src/Panels/Resources/Pages/ListRecordsTest.php b/tests/src/Panels/Resources/Pages/ListRecordsTest.php index c7ecc24b4e..26e743007d 100644 --- a/tests/src/Panels/Resources/Pages/ListRecordsTest.php +++ b/tests/src/Panels/Resources/Pages/ListRecordsTest.php @@ -65,6 +65,23 @@ it('can sort posts by author', function () { ->assertCanSeeTableRecords($posts->sortByDesc('author.name'), inOrder: true); }); +it('can sort posts with default sort key', function () { + + $faker = fake()->unique(); + $posts = Post::factory()->count(10)->state(function () use ($faker) { + return [ + 'id' => $faker->randomDigit(), + 'title' => 'Lorem Ipsum', + ]; + })->create(); + + livewire(ListPosts::class) + ->sortTable('title') + ->assertCanSeeTableRecords($posts->sortBy([['title', 'asc'], ['id', 'asc']]), inOrder: true) + ->sortTable('title', 'desc') + ->assertCanSeeTableRecords($posts->sortBy([['title', 'desc'], ['id', 'asc']]), inOrder: true); +}); + it('can search posts by title', function () { $posts = Post::factory()->count(10)->create(); From 150f1544d5e4bb81464fa6c396d11e3dbb7b6b03 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Wed, 18 Jun 2025 15:56:59 +0200 Subject: [PATCH 3/5] Cleanup duplicate --- packages/tables/src/Concerns/CanSortRecords.php | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tables/src/Concerns/CanSortRecords.php b/packages/tables/src/Concerns/CanSortRecords.php index 740501036f..2db16849f2 100644 --- a/packages/tables/src/Concerns/CanSortRecords.php +++ b/packages/tables/src/Concerns/CanSortRecords.php @@ -107,7 +107,6 @@ trait CanSortRecords ($sortColumn = $this->getTable()->getSortableVisibleColumn($defaultSort)) ) { $sortColumn->applySort($query, $sortDirection); - $this->applyDefaultKeySortToTableQuery($query); } elseif (is_string($defaultSort)) { $query->orderBy($defaultSort, $sortDirection); } From 743eec2143a988c115cf1e5f2edefe0a69e350d3 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 26 Jun 2025 11:09:16 +0100 Subject: [PATCH 4/5] Update CanSortRecords.php --- packages/tables/src/Concerns/CanSortRecords.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tables/src/Concerns/CanSortRecords.php b/packages/tables/src/Concerns/CanSortRecords.php index 2db16849f2..989a6183a0 100644 --- a/packages/tables/src/Concerns/CanSortRecords.php +++ b/packages/tables/src/Concerns/CanSortRecords.php @@ -132,7 +132,7 @@ trait CanSortRecords $qualifiedKeyName = $query->getModel()->getQualifiedKeyName(); - foreach ($query->toBase()->orders ?? [] as $order) { + foreach ($query->toBase()->orders ?? [] as $order) { /** @phpstan-ignore */ if (($order['column'] ?? null) === $qualifiedKeyName) { return $query; } From c70e3f80ec6f61bbcd0a1665b932a4eb926bb8d7 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 26 Jun 2025 11:11:57 +0100 Subject: [PATCH 5/5] Update CanSortRecords.php --- packages/tables/src/Concerns/CanSortRecords.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tables/src/Concerns/CanSortRecords.php b/packages/tables/src/Concerns/CanSortRecords.php index 989a6183a0..b21fb52d82 100644 --- a/packages/tables/src/Concerns/CanSortRecords.php +++ b/packages/tables/src/Concerns/CanSortRecords.php @@ -132,7 +132,7 @@ trait CanSortRecords $qualifiedKeyName = $query->getModel()->getQualifiedKeyName(); - foreach ($query->toBase()->orders ?? [] as $order) { /** @phpstan-ignore */ + foreach ($query->toBase()->orders ?? [] as $order) { /** @phpstan-ignore nullCoalesce.property */ if (($order['column'] ?? null) === $qualifiedKeyName) { return $query; }