spatie / laravel-query-builder

Easily build Eloquent queries from API requests
https://spatie.be/docs/laravel-query-builder
MIT License
4.06k stars 397 forks source link

Config to set custom default FiltersField and SortsField #301

Closed edlouth closed 5 years ago

edlouth commented 5 years ago

Would be useful to have a config option to set the FiltersField and SortsField that are used by default.

Currently I end up with something like ->allowedFilters(Filter::custom('field1', CustomFiltersField::class), Filter::custom('field2', CustomFiltersField::class), Filter::custom('field3', CustomFiltersField::class))

I am imagining

return [
    /*
     * By default the package will use the 'include', 'filter', 'sort' and 'fields' query parameters.
     *
     * Here you can customize those names.
     */
    'parameters' => [
        'include' => 'include',

        'filter' => 'filter',

        'sort' => 'sort',

        'fields' => 'fields',

        'filter_field' => Spatie\QueryBuilder\Filters\FiltersField::class,

        'sort_field' => Spatie\QueryBuilder\Sorts\SortsField::class,
    ],
];

Happy to have a go at a PR if this is an appropriate way to go about this

AlexVanderbist commented 5 years ago

Hi!

I'm not sure that I understand what you're looking for. Do you want to apply a bunch of filters to every query by default?

edlouth commented 5 years ago

That was the idea, to be honest using Filter::custom for each allowedFilter is perfectly workable, so I am not sure there is a need for this.

AlexVanderbist commented 5 years ago

Yeah, I would propose creating specific query builder classes that extend the QueryBuilder class to be re-used in your application, these query builder classes can then use your default filters:

Something like this:

class UsersQuery extends QueryBuilder
{
    public function __construct()
    {
        parent::__construct(User::class);

        $this
            ->allowedFilters(
                Filter::exact('status'),
                Filter::custom(
                    'search',
                    new FuzzyFilter(
                        'name',
                        'email',
                    )
                )
            );
    }
}

You could then re-use this UsersQuery class to as a base query builder instance:

class UsersController {
    public function index(UsersQuery $usersQuery) {
        // Using dependency injection to get a usersQuery instance

        return $usersQuery
            ->allowedSorts('id') // add another sort
            ->get();
    }
}

Hopefully this helps you out. Good luck & feel free to open a new issue if you're still having questions!

codeclem commented 5 years ago

Yeah, I would propose creating specific query builder classes that extend the QueryBuilder class to be re-used in your application, these query builder classes can then use your default filters:

Something like this:

class UsersQuery extends QueryBuilder
{
    public function __construct()
    {
        parent::__construct(User::class);

        $this
            ->allowedFilters(
                Filter::exact('status'),
                Filter::custom(
                    'search',
                    new FuzzyFilter(
                        'name',
                        'email',
                    )
                )
            );
    }
}

You could then re-use this UsersQuery class to as a base query builder instance:

class UsersController {
    public function index(UsersQuery $usersQuery) {
        // Using dependency injection to get a usersQuery instance

        return $usersQuery
            ->allowedSorts('id') // add another sort
            ->get();
    }
}

Hopefully this helps you out. Good luck & feel free to open a new issue if you're still having questions!

Did the API change since this? I'm trying what you wrote here but the __construct() method wants an Eloquent Builder and a Request. What's the recommended way to set defaults so you don't have to repeatedly define the same allowed stuff in the controller methods?

abdulmatinsanni commented 5 years ago

Using ::query() instead of ::class worked for me.

<?php

namespace App\Queries;

use App\Models\Ingredient;
use Spatie\QueryBuilder\QueryBuilder;

class IngredientsQuery extends QueryBuilder
{
    public function __construct()
    {
        parent::__construct(Ingredient::query());
    }
}