Last active
February 9, 2022 16:26
-
-
Save rogercbe/ccb6f29678469050057a08172736415c to your computer and use it in GitHub Desktop.
Sortable trait for sorting tables with relationships in Laravel with a table helper class for displaying the links as an extension of the Laravel Paginator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <thead> | |
| <tr> | |
| @foreach($headers as $key => $header) | |
| <th> | |
| @if(! $header['sortable']) | |
| {{ $header['title'] }} | |
| @else | |
| @if(request('sort') == $key) | |
| {{ $header['title'] }} | |
| @if(request('direction') == 'asc') | |
| <span> | |
| <a href="?sort={{ $key }}&direction=desc"> | |
| ▲ | |
| </a> | |
| </span> | |
| @else | |
| <span> | |
| <a href="?sort={{ $key }}&direction=asc"> | |
| ▼ | |
| </a> | |
| </span> | |
| @endif | |
| @else | |
| <a href="?sort={{ $key }}&direction=asc"> | |
| {{ $header['title'] }} | |
| </a> | |
| @endif | |
| @endif | |
| </th> | |
| @endforeach | |
| </tr> | |
| </thead> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\Support; | |
| use Illuminate\Database\Eloquent\Relations\HasOne; | |
| trait Sortable | |
| { | |
| public function scopeSortable($query, $defaultSort = null, $direction = 'asc') | |
| { | |
| if ($this->sortingIsActive()) { | |
| return $this->buildQuery( | |
| $query, | |
| collect(request()->only(['sort', 'direction'])) | |
| ); | |
| } | |
| if (! is_null($defaultSort)) { | |
| return $query->orderBy($defaultSort, $direction); | |
| } | |
| return $query; | |
| } | |
| private function buildQuery($query, $sortParams) | |
| { | |
| $column = $sortParams->get('sort'); | |
| $direction = $sortParams->get('direction'); | |
| if ($this->columnIsRelated($column)) { | |
| $relatedModel = $this->getRelatedModel($column); | |
| $parameters = collect([ | |
| 'column' => $this->getRelatedSortColumn($column), | |
| 'direction' => $direction | |
| ]); | |
| $relation = $query->getRelation($relatedModel); | |
| return $query->join( | |
| $this->relatedTable($relation), | |
| $this->parentPrimaryKey($relation), | |
| '=', | |
| $this->relatedPrimaryKey($relation) | |
| ) | |
| ->select( | |
| $this->parentTable($relation) . '.*', | |
| $this->getRelatedSelectAttribute($relation, $column) | |
| ) | |
| ->orderBy( | |
| $parameters->get('column'), | |
| $parameters->get('direction') | |
| ); | |
| } | |
| return $query->orderBy($column, $direction); | |
| } | |
| private function getRelatedSelectAttribute($relation, $column) | |
| { | |
| return implode('.', [ | |
| $this->relatedTable($relation), | |
| $this->getSortColumn($column) | |
| ]) . ' as ' . $this->getRelatedSortColumn($column); | |
| } | |
| private function parentTable($relation) | |
| { | |
| return $relation->getParent()->getTable(); | |
| } | |
| private function relatedTable($relation) | |
| { | |
| return $relation->getRelated()->getTable(); | |
| } | |
| private function relatedPrimaryKey($relation) | |
| { | |
| if ($relation instanceof HasOne) { | |
| return $relation->getQualifiedForeignKeyName(); | |
| } | |
| return $relation->getQualifiedOwnerKeyName(); | |
| } | |
| private function parentPrimaryKey($relation) | |
| { | |
| if ($relation instanceof HasOne) { | |
| return $relation->getQualifiedParentKeyName(); | |
| } | |
| return $relation->getQualifiedForeignKey(); | |
| } | |
| private function sortingIsActive() | |
| { | |
| return request()->has('sort') && request()->has('direction'); | |
| } | |
| private function getSortColumn($column) | |
| { | |
| return $this->parseRelation($column)->last(); | |
| } | |
| private function getRelatedSortColumn($column) | |
| { | |
| return implode('_', [ | |
| $this->parseRelation($column)->first(), | |
| $this->parseRelation($column)->last() | |
| ]); | |
| } | |
| private function getRelatedModel($column) | |
| { | |
| return $this->parseRelation($column) | |
| ->first(); | |
| } | |
| private function parseRelation($column) | |
| { | |
| return collect( | |
| explode('.', $column) | |
| ); | |
| } | |
| private function columnIsRelated($column) | |
| { | |
| return strpos($column, '.'); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App; | |
| use Illuminate\Pagination\LengthAwarePaginator; | |
| use Illuminate\Support\HtmlString; | |
| class Table extends LengthAwarePaginator | |
| { | |
| public function __construct($paginator) | |
| { | |
| $this->total = $paginator->total; | |
| $this->perPage = $paginator->perPage; | |
| $this->lastPage = $paginator->lastPage; | |
| $this->path = $paginator->path; | |
| $this->currentPage = $paginator->currentPage; | |
| $this->items = $paginator->items; | |
| } | |
| public function headers($viewPath = 'headers') | |
| { | |
| return new HtmlString(view($viewPath, [ | |
| 'headers' => $this->headers | |
| ])->render()); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <html lang="{{ app()->getLocale() }}"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <link rel="stylesheet" href="{{ asset('css/app.css') }}"> | |
| <title>Laravel</title> | |
| <meta name="csrf-token" content="{{ csrf_token() }}"> | |
| </head> | |
| <body class="container"> | |
| <div id="app"> | |
| <div class="page-header"> | |
| <h1>Users List</h1> | |
| </div> | |
| <div class="panel panel-default"> | |
| <div class="panel-body"> | |
| <table class="table"> | |
| {{ $users->headers() }} | |
| <tbody> | |
| @foreach($users as $user) | |
| <tr> | |
| <td>{{ $user->company->name }}</td> | |
| <td>{{ $user->name }}</td> | |
| <td>{{ $user->email }}</td> | |
| <td>{{ $user->created_at }}</td> | |
| <td> | |
| <edit-user-button :id="{{ $user->id }}"></edit-user-button> | |
| </td> | |
| </tr> | |
| @endforeach | |
| </tbody> | |
| </table> | |
| {{ $users->appends(['sort' => request('sort'), 'direction' => request('direction')])->links() }} | |
| </div> | |
| </div> | |
| </div> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\Http\Controllers; | |
| use App\User; | |
| use App\UserTable; | |
| class UsersController extends Controller | |
| { | |
| public function index() | |
| { | |
| $usersPaginate = User::with('company') | |
| ->sortable() | |
| ->paginate(5); | |
| $users = new UserTable($usersPaginate); | |
| return view('test', compact('users')); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App; | |
| class UserTable extends Table | |
| { | |
| protected $headers = [ | |
| 'company.name' => [ | |
| 'sortable' => true, | |
| 'title' => 'Company' | |
| ], | |
| 'name' => [ | |
| 'sortable' => true, | |
| 'title' => 'Name' | |
| ], | |
| 'email' => [ | |
| 'sortable' => true, | |
| 'title' => 'Email' | |
| ], | |
| 'created_at' => [ | |
| 'sortable' => true, | |
| 'title' => 'Created at' | |
| ], | |
| 'options' => [ | |
| 'sortable' => false, | |
| 'title' => 'Options' | |
| ], | |
| ]; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment