Filter eloquent

怎甘沉沦 提交于 2020-03-05 03:05:48

问题


Im using laravel for a project i am wanting to create an endpoint which filters and searches a Film model and returns a collection of films that match the chosen filter options which will be Options, Location and Age Rating picked by the user.

I have created a query with how i would initially join the tables in symfony(hopefully its correct) but im unsure on how i adjust this to be more Laravel or eloquent.

Film Model

    public function location(): BelongsTo
    {
        return $this->belongsTo(Location::class);
    }

    public function options(): BelongsToMany
    {
        return $this->belongsToMany(
            Option::class,
            'film_options',
            'film_id',
            'option_id'
        );
    }

 public function ageRatings(): BelongsToMany
    {
        return $this->belongsToMany(
            AgeRating::class,
            'film_age_ratings',
            'film_id',
            'age_rating_id'
        );
    }

Query in Doctrine

Select *
        From films  f
        Join film_options fo on f.id = fo.film_id
        Join options o on o.id = fo.option_id 
        Join film_age_ratings fa on f.id = fa.film_id
        Join age_ratings a on a.id = fa.age_rating_id
        Join location l on l.id = p.location_id

How would i write this query within laravel?


回答1:


To achieve what you're after you can use a mixture of when() and whereHas():

$films = Film
    ::when($request->input('first'), function ($query, $first) {
        $query->whereHas('options', function ($query) use ($first) {
            $query->where('first', $first);
        });
    })
    ->when($request->input('second'), function ($query, $second) {
        $query->whereHas('options', function ($query) use ($second) {
            $query->where('second', $second);
        });
    })
    ->when($request->input('age'), function ($query, $age) {
        $query->whereHas('ageRatings', function ($query) use ($age) {
            $query->where('age', $age);
        });
    })
    ->when($request->input('country'), function ($query, $country) {
        $query->whereHas('locations', function ($query) use ($country) {
            $query->where('country', $country);
        });
    })
    ->when($request->input('city'), function ($query, $city) {
        $query->whereHas('locations', function ($query) use ($city) {
            $query->where('city', $city);
        });
    })
    ->orderBy('updated_at', 'desc')
    ->get();

Essentially, what the above is doing is saying when you have a non-empty value submitted it will add a where clause to the query for that relationship
e.g. is main is submitted it will limit the films to only ones that have categories when main is the submitted value.


Also, just an FYI, you don't need to add the from(...) method when using Eloquent.


A simple way to limit the number of lines would be to add scopes to your Film model e.g.

In your Film model:

public function scopeHasMain($query, $main)
{
    $query->whereHas('options', function ($query) use($first) {
        $query->where('first', $first);
    });
}

Then your when() method would be:

when($request->input('first'), function ($query, $first) {
    $query->hasFirst($first);
})



回答2:


You can use the whereHas method as shown in the docs: https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-existence

Example:

use Illuminate\Database\Eloquent\Builder;

//...

$optionIds = [/* Option ids to filter by */];
$films = Film::whereHas('options', function (Builder $query) use ($optionIds) {
    $query->whereIn('options.id', $optionIds);
})->get();


来源:https://stackoverflow.com/questions/59695291/filter-eloquent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!