Add search, sort, filters & more with a typehint in your controller like Laravel's FormRequest.
Remove all that logic from your models / controllers, and auto-validate query parameters!
This package handles many common scenarios and is setup in a minimal Laravel way.
- ✅ Search columns
- ✅ Search relationships columns
- ✅ Sort by columns
- ✅ Sort by relationship columns
- ✅ Sort by relationship counts
- ✅ Filter by dates
- ✅ Filter by date ranges
- ✅ Filter by relationships
- ✅ Filter by relationship counts
- ✅ Filter by latitude & longitude
- ✅ Filter by radius
- ✅ Filter by soft deleted
- ✅ Filter by within scope
- ✅ Filter by outside scope
- ✅ Filter by muliple values
- ✅ And so much more!
Install | Search | Sort | Filters | Helpers
Add to a Laravel project using composer:
composer require dillingham/formation
Create a formation class using artisan:
php artisan make:formation ArticleFormation
<?php
namespace App\Formations;
use Dillingham\Formation\Filter;
use Dillingham\Formation\Formation;
class ArticleFormation extends Formation
{
/**
* The model class,
*
* @var array
*/
public $model = \App\Models\Article::class;
/**
* The column to use for select options,
*
* @var array
*/
public $display = 'title';
/**
* The searchable columns,
*
* @var array
*/
public $search = ['title', 'comments.body'];
/**
* The sortable columns.
*
* @var array
*/
public $sort = ['created_at', 'comments'];
/**
* Define the filters.
*
* @return array
*/
public function filters():array
{
return [
Filter::make('author')->related(),
Filter::make('published_at')->dateRange(),
Filter::make('comments')->countRange(),
];
}
}
All results are paginated and nested within data
.
Simply typehint in your controller and call ->results()
to execute.
<?php
class ArticleController
{
public function index(ArticleFormation $request)
{
return view('articles.index', [
'articles' => $request->results()
]);
}
}
The URL controls the results
depending on the settings below.
Define columns or relationship columns to search:
public $search = ['title', 'comments.body'];
/articles?search=laravel
Define which columns are sortable:
public $sort = ['name', 'created_at'];
/articles?sort=created_at
Change sort
to sort-desc
changes it's direction.
/articles?sort-desc=created_at
Sort relationship counts, relationship columns and or alias them:
public $sort = [
'comments',
'comments.upvotes',
'comments.downvotes as disliked',
];
sort=comments
sort=upvotes
sort=disliked
Enable query parameters by adding to filters()
:
public function filters()
{
return [
Filter::make('active')->boolean(),
];
}
Results where a boolean value is true or false:
Filter::make('active')->boolean(),
/articles?active=true
Same a boolean() but only allows true
:
Filter::make('active')->toggle(),
/articles?active=true
Results where a column equals one of the optionst:
Filter::make('status')->options(['published', 'draft']),
/articles?status=draft
Results where a number has a min and max value:
Filter::make('length')->range(),
/articles?length:min=5&length:max=100
Results by a named range set
Filter::make('length')
->between('small', [1, 100])
->between('medium', [101, 200])
->between('large', [201, 300])
/articles?length=small
Results where a specific date is filtered by:
Filter::make('published_at')->date(),
/articles?published_at=01/01/2021
Results where date range is filtered by:
Filter::make('published_at')->dateRange(),
/articles?published_at:min=01/01/2021&published_at:max=02/01/2021
Results where a group of columns are searched
Filter::make('written-by')->search([
'author_id',
'author.name',
'author.username'
]),
/articles?written-by=Brian
Below are a few filters for Laravel's Eloquent relationships.
Results by a relationship primary key:
Filter::make('author')->related(),
/articles?author=1
Results where a relationship exists
Filter::make('like')->exists(),
/articles?like:exists=true
Results by a relationship count
Filter::make('comments')->count(),
/articles?comments:count=5
Results by a relationship count min / max range
Filter::make('tags')->countRange(),
/articles?tags:min=5&tags:max=10
These filters use geo location to filter Laravel models.
Results within a latitude, longtitude & distance.
Filter::radius(),
/users?latitude=40.7517&longitude=-73.9755&distance=10
Results within a set of map boundaries.
Filter::bounds(),
/users?ne_lat=40.75555971122113&ne_lng=-73.96922446090224&sw_lat=40.74683062112093&sw_lng=-73.98124075728896
ne_lat
, ne_lng
, sw_lat
, sw_lng
These filters use Laravel's model scope.
Results where a model scope is applied
Filter::make('status')->scope(),
/articles?status=active
public function scopeStatus($query, $value)
{
$query->where('status', $value);
}
Results in scope = true
, or not in scope = false
Filter::make('published')->scopeBoolean(),
/articles?published=true
/articles?published=false
false
produces the opposite and returns all results that are not in the scope
Results include soft deleted and not deleted
Filter::make('with-deleted')->withTrashed(),
/articles?with-deleted=true
Results only include soft deleted
Filter::make('deleted')->onlyTrashed(),
/articles?deleted=true
Here are some scenarios and recipies:
Redirects to route('login') if unauthenticated.
Filter::make('like')->exists()->auth(),
A url key different from the relationship or column name
Filter::make('status', 'status_id'),
Filter::make('author', 'activeAuthor'),
/articles?status=1
Allow the filter to accept many values for the same key
Filter::make('status')->multiple(),
/articles?status[]=active&status[]=draft
Appends the rules set by the filter types.
Filter::make('status')->withRules('in:active,inactive'),
Add conditions based on the parameter value.
Filter::make('status')
->when('active', function($query) {
return $query->where('status', 'active');
}),
Add to the query to apply additional conditions.
Filter::make('published')
->withQuery(function($query) {
$query->whereNotNull('published_at');
}),
When the public value is in dollars and db is in cents
Filter::make('price')->asCents(),
/products?price=100 // where('price', 10000)
Useful for defining routes with filters: /active
public function active(ArticleFormation $request)
{
$request->merge(['status' => 'active']);
return $request->results();
}
For hard coding conditions within controllers:
public function index($author_id, ArticleFormation $request)
{
$request->where('author_id', $author->id);
return $request->results();
}
Use options()
to return results in the following format:
$request->options()->results()
{
"data": [
{
"display": 'Article with ID 1',
"value": 1
}
],
"links": {...},
"meta": {...}
}
Publish the config automatically with the following command:
php artisan vendor:publish --tag=formations
Then add a route using this package's SelectOptionController
use \Dillingham\Formation\Http\Controllers\SelectOptionController;
Route::get('options/{resource}', SelectOptionController::class);
The {resource}
will reference the key in the formations config
'options' => [
'users' => \App\Formations\UserFormation::class,
]
/options/users
routes to the UserFormation
+ allow search / filters etc
Hi, @im_brian_d, software developer and Laravel enthusiast.