Can I use `when` with `whereHas` in a Laravel query? - php

I want to add a whereHas to a Laravel query but only if a variable is true. I'm trying the below which doesn't error but doesn't return anything when it should.
$assets = Asset::with('media')
->when($category, function ($q) use ($category) {
return $q->whereHas('category', function ($query) use ($category) {
$query->whereId($category);
});
})->offset($offset)->limit($limit)->get();
If $category is true nothing is returned. If $category is false all is returned. It works without the when clause.

This is my code, it is working:
return App\Car::with(['user'])
->when($_GET['area']>'', function ($query)
{ $query-> whereHas('user', function($query) { $query->where('area_id', $_GET['area']); } ); })->get();

Related

how can i do query biulder with (AND) for 3 or more parameters

im did a query for brand of car and the model but when i did added a
query to price range (whereBetwen) its not working
public function indexBrowse(Request $request)
{
$brand=$request->get('searchbrand');
$model=$request->get('searchmodel');
$searchtype=$request->get('searchtype');
$from=$request->get('pricefrom');
$to=$request->get('priecto');
$cars=car::where('brand', 'like', '%'.$brand.'%')
->where(function ($query) use ($model) {
$query->where('model','like','%'.$model.'%');
})->where(function ($query2) use ($from,$to) {
$query2->car::whereBetween('price',['%'.$from.'%','%'.$to.'%']);
})->get();
dd($cars);
$success = 'Results Car';
return view('cars.index', compact('cars', 'success'));
}
Something like this if you want to perform all these where with and condition.
car::where('brand', 'like', '%'.$brand.'%')
->where('model','like','%'.$model.'%')
->whereBetween('price'['%'.$from.'%','%'.$to.'%'])->get();

Laravel nested relation filter

Have a query, how I can filter results by translation relation (by name column)
$item = Cart::select('product_id','quantity')
->with(['product.translation:product_id,name','product.manufacturer:id,name'])
->where($cartWhere)
->get();
my model
Cart.php
public function product($language = null)
{
return $this->hasOne('App\Models\Product','id','product_id');
}
Product.php
public function translations()
{
return $this->hasMany('App\Models\ProductTranslation','product_id','id');
}
Update v1.0
do like this, but query takes too long time
$item = Cart::select('product_id','quantity')
->with(['product.translation', 'product.manufacturer:id,name'])
->where($cartWhere)
->when($search,function ($q) use ($search) {
$q->whereHas('product.translation', function (Builder $query) use ($search) {
$query->where('name', 'like', '%'.$search.'%');
$query->select('name');
});
}
)
->get() ;
Inside the array within your with() method, you can pass a function as a value.
Cart::select('product_id','quantity')
->with([
'product', function($query) {
$query->where($filteringAndConditionsHere);
}
]);
https://laravel.com/docs/7.x/eloquent-relationships#eager-loading

Laravel Filter using various relations

I am doing a filter using relations here is my controller code:
$userList = User::with(['role' ,'userMetaData','userBet','userComission','userPartnership'])
->where('deleted', '=', '0')
->when($request->parent_id, function ($builder, $parent_id) {
return $builder->where('parent_id', $parent_id);
})
->when($request->role_id, function ($builder, $role_id) {
return $builder->where('role', $role_id);
})
->when($request->to && $request->from , function ($builder) use ($request) {
return $builder->whereBetween('exposure_limit', [$request->from, $request->to]);
})
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
});
})
->orderBy('created_at', 'DESC')
->get();
In this case(in my code) i am trying to use whereHas() to filter a data from another table(within relations) by eloquent but it's something i am missing:
here in your case, when you use Wherehas to userMetaData it'll filter and gives you only those users who's has city as $request->sport..
In another case, you've used with('userMetaData') which means whatever users you got in filter return all userMetaData.
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
})->with(['userMetaData' => function($q) use ($request) {
$q->where('city', $request->sport);
}]);
})
Remove userMetaData from User::with(['role','userBet','userComission','userPartnership'])

eloquent - dynamic and conditional whereHas() in the query builder

I am trying to avoid DRY in my query builder, specifically on adding additional method in the chain.
Example, this is initially the query builder that I have:
$products = $app->myShop->realProducts()
->where($query)
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
Then if user used some filter, I needed to append a method (specifically a whereHas()) to the query builder
$products = $app->myShop->realProducts()
->where($query)
->whereHas('colour', function ($q) use ($find) {
$q->where('colour_slug', $find);
})
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
I find it "ugly" that to achieve this result, I have to keep repeating those builder query:
if ($user_filtered_this_page == TRUE) {
$products = $app->myShop->realProducts()->where($query)
->whereHas('colour', function ($q) use ($find) {
$q->where('colour_slug', $find);
})
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
} else {
$products = $app->myShop->realProducts()->where($query)
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
}
Is there a more clever or elegant way to dynamically and conditionally append the whereHas() method to the chain?
Hope somebody can help. Thank you!
The query doesn't get executed until you call ->get() so you can quite simply build your query, conditionally add your ->whereHas() and then execute it:
$query= $app->myShop->realProducts()
->where($query)
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder);
if (...) {
$query->whereHas(...);
}
$products = $query->get();
This could be done using Query Builder Conditional Clauses
$products = $app->myShop->realProducts()
->where($query)
->when($user_filtered_this_page, function($query) use($find){
$query->whereHas('colour', function ($q) use ($find) {
$q->where('colour_slug', $find);
})
})
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
You can write like this:
$products = $app->myShop->realProducts()->where($query)
->whereHas('colour', function ($q) use ($find) {
if ($user_filtered_this_page) {
$q->where('colour_slug', $find);
}
})
->skip($skip)->take($take)
->orderBy($sortKey, $sortOrder)
->get();
Hope it help you ;)

Constrain does not take effect when eager loading in laravel 5

I have this function to get the results from joining relationships. However, the constraints don't seem to be taking effect. If I comment out the constraints, it still it gives the same result set as the uncommented constraints.
public function singleCategory($type, $category)
{
$track = TrackType::with(['tracks.subgenres'], function($query, $category) {
$query->where('name','=', $category);
})->where('name', '=', $type)->get();
dd($track->toArray());
}
Any help would be really appreciated :)
The constraining closure is only passed one parameter: $query. The other parameter you're trying to access ($category) needs to be made available via the use keyword:
public function singleCategory($type, $category)
{
$track = TrackType::with(['tracks.subgenres'], function($query) use ($category) {
$query->where('name', '=', $category);
})->where('name', '=', $type)->get();
dd($track->toArray());
}
Edit
The above will not affect the TrackTypes that are returned, it will only limit the related subgenres that are eager loaded. Based on the comments, it seems as if you are trying to limit the TrackTypes returned to those that contain a certain subgenre. In this case, you need to use the whereHas method:
public function singleCategory($type, $category)
{
$track = TrackType::with('tracks.subgenres')
->whereHas('tracks.subgenres', function($query) use ($category) {
$query->where('name', '=', $category);
})
->where('name', '=', $type)
->get();
dd($track->toArray());
}
Edit 2
It sounds like your target result set is actually the tracks, and not the track types. If so, you probably want to start by querying the tracks, and add in your filter criteria from there (I don't know your exact model and relationship names, so adjust accordingly):
public function singleCategory($type, $category)
{
$track = Track::with(['tracktype', 'subgenres'])
->whereHas('tracktype', function($query) use ($type) {
$query->where('name', '=', $type);
})
->whereHas('subgenres', function($query) use ($category) {
$query->where('name', '=', $category);
})
->get();
dd($track->toArray());
}
If you really are looking to start with the TrackType, then in addition to adding the whereHas() to find the TrackType, you need to add a whereHas() to filter down the Tracks that are eager loaded:
public function singleCategory($type, $category)
{
$track = TrackType::with(['tracks' => function ($query) use ($category) {
$query->whereHas('subgenres', function($query) use ($category) {
$query->where('name', '=', $category);
});
}, 'tracks.subgenres'])
->whereHas('tracks.subgenres', function($query) use ($category) {
$query->where('name', '=', $category);
})
->where('name', '=', $type)
->get();
dd($track->toArray());
}
The first example is much cleaner. In plain English, the first example would sound like "get all tracks of a type and a subgenre". The second example would sound like "get the track type, but only if it has tracks in a certain subgenre; also, only load those tracks within that subgenre".

Categories