There is a package for that: https://spatie.be/docs/laravel-query-builder/v6/features/sorting
How to approach creating multiple versions of a ressource controller's index?
Hi, I have a bunch of calls, which I need to return sorted by different columns (/calls/datetime, /calls/operator etc.).
What'd be the correct approach in this scenario? Should the index() function of the CallController capture the URL parameter and base it's output based on that? Should it be split into multiple functions?
Isn't it for the sorting itself? If so, then that can also be done with vanilla Model functions, like orderBy().
What I'm asking is, what architecture for the routing should I build? Like, how to get a ressource controller to index() different contents based on the URL?
Correct me, If I have missunderstood your premise.
You pass the sorting criteria into your controller via the url, and then look at them to set the order by.
Similar to this, but with order by instead of where
'books' => BookIndexView::query()
->when($request['authors'], function ($query, $authors) {
$query->whereIn('author_id',
$this->numericStringToArray($authors));
})
->when($request['published'], function ($query, $published) {
$query->where('published_year', $published);
})
->when($request['genre'], function ($query, $genre) {
$query->where('genre', $genre);
})
->when($request['format'], function ($query, $format) {
$query->where('format', $format);
})
->when($request['search'], function ($query, $search) {
$query->where('title', 'LIKE', "%$search%")
->orWhere('author_name', 'LIKE', "%$search%")
->orWhere('series', 'LIKE', "%$search%");
})
->orderBy('author_name')
->orderBy('series')
->orderBy('part')
->orderBy('published_year')
->get(),
]);
That seems to be exactly what I need, thanks!
But may I ask you something else related to the topic, namely how to pass query parameters (/calls&sort=datetime) to a ressource controller? This seems to be a basic question, but I'm really struggling to get hold of it.
Simply pass it as an array on your link like so
route('books.index', ['genre' => $book->genre]
Well, I've ended up pulling them out in the Controller like
class CallController extends Controller
{
public function index (Request $request) {
// ...
datetime = $request->query('datetime');
// ...
}
// ...
}
Thank you for your advice!
Also @andrews-quest your search / query is what I meant here:
https://laracasts.com/discuss/channels/laravel/design-patterns-in-laravel?page=1&replyId=971681
When I said I might have a class I call for a complex search, just to keep the controller lean.
Yes it could go in the model, but for complex search criteria I like a little special class. But just a suggestion. Also there is nothing wrong with a "blump" model. But I do prefer a lean controller.
It seems to be a clever approach, thanks. Maybe, if you have an example of such class or a whole architecture that uses it, it would be helpfull to take a look.
Hi, I have a bunch of calls, which I need to return sorted by different columns (/calls/datetime, /calls/operator etc.).
What'd be the correct approach in this scenario? Should the index() function of the CallController capture the URL parameter and base its output based on that? Should it be split into multiple functions?
@andrews-quest You would use a query string parameter here to control how you want records sorting, i.e.
/calls?sort=datetime/calls?sort=operator
You can use Spatie’s Laravel Query Builder package as mentioned by @glukinho to implement sorting (https://spatie.be/docs/laravel-query-builder/v6/features/sorting):
class CallController extends Controller
{
public function index()
{
$calls = QueryBuilder::for(Call::query())
->allowedSorts([
'datetime',
'operator',
// Any other column you want to be able to sort by...
])
->paginate();
return view('calls.index', compact('calls'));
}
}
Oh, I see. I'll stick with the out-of-the-box solution for now, but will definetely look further into this approach on latter stages.
@andrews-quest What “out-of-the-box” solution? There isn’t one; you’d have to parse the query string and manually add the clauses yourself:
public function index(Request $request)
{
$query = Call::query();
$query = match ($request->query('sort')) {
'datetime' => $query->orderByDesc('datetime'),
'operator' => $query->orderByDesc('operator'),
default => $query,
};
$calls = $query->paginate();
return view('calls.index', compact('calls'));
}
This also doesn’t deal with sorting directions (ascending/descending) like Spatie’s package will.
Yes, that's the solution I meant. That's how it works in my app for now.
But you mentioning the sorting directions made me ponder, maybe I should really switch to Spatie as soon as possible.
Thanks a lot!
Please or to participate in this conversation.