diff --git a/src/Concerns/Sorting.php b/src/Concerns/Sorting.php index 9fb46abc..5784b75b 100644 --- a/src/Concerns/Sorting.php +++ b/src/Concerns/Sorting.php @@ -116,6 +116,15 @@ public function updatedSortField(): void } } + public function resolveSortField(string $sortField): string + { + if (str_contains($sortField, '.') || $this->ignoreTablePrefix) { + return $sortField; + } + + return $this->currentTable.'.'.$sortField; + } + /** * Get the sort callback for a given field from the columns definition. * Returns null if no custom callback is defined. diff --git a/src/DataSource/Processors/Database/Pipelines/Sorting.php b/src/DataSource/Processors/Database/Pipelines/Sorting.php index da99480b..042f18d0 100644 --- a/src/DataSource/Processors/Database/Pipelines/Sorting.php +++ b/src/DataSource/Processors/Database/Pipelines/Sorting.php @@ -6,7 +6,6 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Database\Query\Builder as QueryBuilder; -use Illuminate\Support\Str; use PowerComponents\LivewirePowerGrid\PowerGridComponent; class Sorting @@ -40,7 +39,7 @@ private function applySingleSort(EloquentBuilder|MorphToMany|QueryBuilder $query return; } - $query->orderBy($this->makeSortField($sortField), $direction); + $query->orderBy($this->component->resolveSortField($sortField), $direction); } private function applyMultipleSort(EloquentBuilder|MorphToMany|QueryBuilder $results): void @@ -54,16 +53,7 @@ private function applyMultipleSort(EloquentBuilder|MorphToMany|QueryBuilder $res continue; } - $results->orderBy($this->makeSortField($sortField), $direction); + $results->orderBy($this->component->resolveSortField($sortField), $direction); } } - - private function makeSortField(string $sortField): string - { - if (Str::of($sortField)->contains('.') || $this->component->ignoreTablePrefix) { - return $sortField; - } - - return $this->component->currentTable.'.'.$sortField; - } } diff --git a/src/Traits/ExportableJob.php b/src/Traits/ExportableJob.php index 8fda8b8b..e289270e 100644 --- a/src/Traits/ExportableJob.php +++ b/src/Traits/ExportableJob.php @@ -53,6 +53,14 @@ private function prepareToExport(array $properties = []): Eloquent\Collection|Co $filtered = $processDataSource->component->filtered ?? []; $currentTable = $processDataSource->component->currentTable; + /** @var array{sortField?: string, sortDirection?: string} $queryOptions */ + $queryOptions = data_get($this->exportable, 'queryOptions', []); + + // data_get's default only applies when the key is missing, so guard against malformed query options. + if (! is_array($queryOptions)) { + $queryOptions = []; + } + $property = function (string $property) use ($processDataSource, $currentTable) { $property = $processDataSource->component->{$property}; @@ -61,6 +69,12 @@ private function prepareToExport(array $properties = []): Eloquent\Collection|Co : $currentTable.'.'.$property; }; + $sortField = $queryOptions['sortField'] + ?? $processDataSource->component->resolveSortField($processDataSource->component->sortField); + + $sortDirection = $queryOptions['sortDirection'] + ?? $processDataSource->component->sortDirection; + $results = $processDataSource->datasource ->where(function ($query) { app()->makeWith(SearchHandlerContract::class, [ @@ -73,7 +87,7 @@ private function prepareToExport(array $properties = []): Eloquent\Collection|Co }) ->offset($this->offset) ->limit($this->limit) - ->orderBy($property('sortField'), $processDataSource->component->sortDirection) + ->orderBy($sortField, $sortDirection) ->get(); $dataTransformer = new DataTransformer($processDataSource->component); diff --git a/src/Traits/WithExport.php b/src/Traits/WithExport.php index b8a0f02f..3faf15f2 100644 --- a/src/Traits/WithExport.php +++ b/src/Traits/WithExport.php @@ -205,8 +205,9 @@ public function prepareToExport(bool $selected = false): Eloquent\Collection|Col ->when($filtered, function ($query, $filtered) use ($property) { return $query->whereIn($property('primaryKey'), $filtered); }) - ->when($this->sortField, function ($query) use ($property, $processDataSource, $queryOptions) { - $sortField = $queryOptions['sortField'] ?? $property('sortField'); + ->when($this->sortField, function ($query) use ($processDataSource, $queryOptions) { + $sortField = $queryOptions['sortField'] + ?? $processDataSource->component->resolveSortField($processDataSource->component->sortField); $sortDirection = $queryOptions['sortDirection'] ?? $processDataSource->component->sortDirection; return $query->orderBy($sortField, $sortDirection); diff --git a/tests/Feature/ExportTest.php b/tests/Feature/ExportTest.php index ed11d533..253fa190 100644 --- a/tests/Feature/ExportTest.php +++ b/tests/Feature/ExportTest.php @@ -1,5 +1,7 @@ [$exportWithHtml::class], ]); +$exportWithJoinedAliasSort = new class() extends ExportTable +{ + public function datasource(): Builder + { + return parent::datasource() + ->join('categories', function ($categories) { + $categories->on('dishes.category_id', '=', 'categories.id'); + }) + ->select('dishes.*', DB::raw('categories.name as category_name')); + } + + public function fields(): PowerGridFields + { + return PowerGrid::fields() + ->add('category_name'); + } + + public function columns(): array + { + return [ + Column::add() + ->title('Category') + ->field('category_name') + ->sortable(), + ]; + } +}; + +it('properly prepares export data sorted by a joined alias column', function (string $component) { + $component = livewire($component) + ->set('checkboxValues', [ + 0 => '1', + 1 => '3', + ]) + ->call('sortBy', 'category_name'); + + expect($component->instance()->prepareToExport(true)->pluck('category_name')->values()->all()) + ->toBe(['Carnes', 'Sobremesas']); +})->with('export_with_joined_alias_sort'); + +dataset('export_with_joined_alias_sort', [ + 'joined alias' => [$exportWithJoinedAliasSort::class], +]); + $exportWithQueryOptions = new class() extends ExportTable { public string $testSortField = ''; @@ -302,7 +348,7 @@ public function columns(): array data_get($downloadEffect, 'name') ); - $content = str_replace(PHP_EOL, '', base64_decode(data_get($downloadEffect, 'content'))); + $content = str_replace(["\r\n", "\n", "\r"], '', base64_decode(data_get($downloadEffect, 'content'))); $expected = collect(array_merge([$headings], $rows)) ->transform(function ($heading) use ($delimiter, $separator) {