问题
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