kyslik/column-sortable
Add sortable table columns to Laravel 5.5–8. Generate clickable links in Blade, configure sortable fields and icons, and sort by related hasOne/belongsTo attributes or withCount(). Works seamlessly with pagination and query building.
Installation:
composer require kyslik/column-sortable
For Laravel ≥5.5, auto-discovery handles registration. For older versions, manually add Kyslik\ColumnSortable\ColumnSortableServiceProvider to config/app.php.
Publish Config:
php artisan vendor:publish --provider="Kyslik\ColumnSortable\ColumnSortableServiceProvider" --tag="config"
First Use Case:
Sortable trait to your Eloquent model:
use Kyslik\ColumnSortable\Sortable;
class User extends Model {
use Sortable;
public $sortable = ['id', 'name', 'email'];
}
sortable() method in your controller:
$users = User::sortable()->paginate(10);
@sortablelink('name', 'Username')
Model Setup:
Define $sortable array in your model to specify sortable columns. This avoids runtime database checks for column existence.
Controller Integration:
// Default sorting (ascending)
$users = User::sortable()->paginate(10);
// Explicit sorting
$users = User::sortable('name')->paginate(10);
$users = User::sortable(['name' => 'desc'])->paginate(10);
Blade Integration:
Use @sortablelink() directive to generate clickable sort links:
@sortablelink('name', 'Username', ['filter' => 'active'], ['class' => 'sort-link'])
rel).Pagination Handling:
Preserve query parameters (except page) when rendering pagination:
{!! $users->appends(\Request::except('page'))->render() !!}
Define Relations:
// User model
public function detail() {
return $this->hasOne(UserDetail::class);
}
Configure $sortable:
// UserDetail model
public $sortable = ['phone_number'];
Sort via Relation:
@sortablelink('detail.phone_number', 'Phone')
Custom Relation Queries:
Override addressSortable() in your model for complex joins:
public function addressSortable($query, $direction) {
return $query->join('user_details', 'users.id', '=', 'user_details.user_id')
->orderBy('address', $direction)
->select('users.*');
}
Model Setup:
public $sortableAs = ['nick_name'];
Controller:
$users = User::select(['name as nick_name'])->sortable(['nick_name'])->paginate(10);
Blade:
@sortablelink('nick_name', 'Nickname')
Set default sorting in config/columnsortable.php:
'default' => [
'column' => 'name',
'direction' => 'asc',
],
Invalid Relation Names:
ColumnSortableException with code 1 if the relation doesn’t exist.hasOne, belongsTo) are correctly defined in the model.Malformed Sort URLs:
ColumnSortableException with code 0 if the sort parameter is malformed (e.g., sort=column..subcolumn).sort parameter in the controller.Column Existence Checks:
Schema::hasColumn() if $sortable isn’t defined, adding overhead.$sortable in your model to avoid runtime checks.Font Awesome Mismatch:
asc_suffix and desc_suffix in config/columnsortable.php:
'asc_suffix' => '-up',
'desc_suffix' => '-down',
Pagination Conflicts:
appends() doesn’t preserve all query parameters.\Request::except('page') to exclude only the page parameter:
{!! $users->appends(\Request::except('page'))->render() !!}
Log Sortable Queries:
Temporarily add ->toSql() to debug generated queries:
$query = User::sortable('name')->toSql();
Check Config Values:
Verify config/columnsortable.php for custom separators or icon classes:
'uri_relation_column_separator' => '.',
Test Relation Sorting: Ensure relations are eager-loaded to avoid N+1 queries:
$users = User::with('detail')->sortable()->paginate(10);
Custom Sortable Logic:
Override the sortable() method in your model for bespoke behavior:
public function sortable($columns = null) {
return $this->orderBy('custom_logic', 'asc')->getQuery();
}
Dynamic $sortable:
Populate $sortable dynamically based on user roles or permissions:
public $sortable = function() {
return auth()->user()->can('admin') ? ['id', 'name', 'email', 'deleted_at'] : ['id', 'name'];
};
Global Middleware: Add middleware to validate or transform sort parameters:
public function handle($request, Closure $next) {
$request->merge(['sort' => $this->sanitizeSort($request->sort)]);
return $next($request);
}
Localization:
Customize the @sortablelink title formatting by extending the Blade directive:
Blade::extend(function($view) {
$view->share('sortableTitle', function($title) {
return trans('labels.' . $title);
});
});
Avoid Schema::hasColumn:
Define $sortable statically to skip runtime checks.
Select Specific Columns: Reduce query size by selecting only needed columns:
$users = User::select(['id', 'name', 'email'])->sortable()->paginate(10);
Cache Config: Publish and cache the config to avoid repeated file reads:
php artisan config:cache
Use withCount Efficiently:
For withCount() sorting, alias columns to avoid ambiguity:
$users = User::withCount('posts')->select(['id', 'name', 'posts_count'])->sortable(['posts_count'])->paginate(10);
How can I help you explore Laravel packages today?