spatie / laravel-query-builder

Easily build Eloquent queries from API requests

Home Page:https://spatie.be/docs/laravel-query-builder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug or Oversight: allowed filter with value of an empty string bypasses the filter

jpgilchrist opened this issue · comments

I have a controller method, that I want to allow a user to switch a scope filter on and off for controlling the data they are authorized to see that will be returned.

For instance and admin account may want to just see their own personal data or they may want to see all the data for every user they have access manage.

So I created a scope query, but when playing with the query parameter values for the filter method, I noticed that if a user specifies an empty string as the parameter, then it's completely ignored despite having a default value set. I need to turn this behavior off.

/api/widgets?filter[all_users]= triggers the undesired behavior.

        $query = QueryBuilder::for(Widget::class)
            ->allowedIncludes('type', 'type.settings', 'type.settings.options', 'values')
            ->allowedFilters([
                AllowedFilter::scope('all_users')->default(false)
            ]);
    public function scopeAllUsers (Builder $query, bool $value): Builder {
        dd($value);
        if ($value) {
            return $query->whereIn('UserID',  Auth::user()->accessibleUserIds());
        }

        return $query->where('UserID', '=', Auth::user()->Id);
    }

I've also tried to set the ignored values to an empty array or nothing with something like

AllowedFilter::scope('all_users')->default(false)->ignore()

OR

AllowedFilter::scope('all_users')->default(false)->ignore([])

neither work, as the scope function is bypassed completely and the dd($value) is never hit.

Hi @jpgilchrist,

I've tried reproducing the behavior you are describing but failed at that. Can you specify which version you are using or provide a sample project to reproduce this error?

Heres the test setup I used.

class TestModel {
    public function scopeOnlyFirst(Builder $query, bool $value) : Builder{
        if ($value)
            return $query->where('id', 1);
        return $query;
    }
}

it('interprets an empty string as boolean false', function() {
    $models = createQueryFromFilterRequest(['only_first' => ''])
        ->allowedFilters(AllowedFilter::scope('only_first')->default(false))
        ->get();

    expect($models)->toHaveCount(5);
    expect(TestModel::all()->count())->toBe(5);
});

If you want to dig deeper yourself a good starting point would be FiltersQuery#addFiltersToQuery.