$provider is optional, is it correct to use whereHas in this scenario even when I have already used with() Eager Loading?
public function findByStatus($status, $provider = null)
{
$result = $this->hosts->with('logins')->where('status', $status);
if ($provider) {
$result->whereHas('logins', function ($query) use ($provider) {
$query->where('provider', $provider);
});
}
return $result->get();
}
You can you it in the way you are using. But I'd do like this.
$result = $this->hosts->whereHas('logins', function ($query) use ($status, $provider) {
$query->where('status', $status);
if ($provider) {
$query->where('provider', $provider);
}
return $query;
})->get();
Since both the quires about logins you can group them in one query.
Related
i want to filter a collection in order to return only items with fullname that is like the one given in parmaters
public function searchFriend($fullName){
return Auth::user()->friends->filter(function ($item) use ($fullName) {
return false !== stristr($item->friend->full_name, $fullName);
});
}
the function actually is not returning the correct results.
Instead of accessing the collection directly, you can do the filtering in SQL.
public function searchFriend($fullName){
return Auth::user()
->friends()
->where('full_name', 'like', '%'.$fullName.'%')
->get();
}
If you, for whichever reason, need to do it on the collection, then the problem with your current code is that $item represents the friend, so you're checking $item->friend->full_name instead of $item->full_name.
public function searchFriend($fullName){
return Auth::user()
->friends
->filter(function ($item) use ($fullName) {
return false !== stristr($item->full_name, $fullName);
});
}
I guess friend is a relationship to the User model so it could be
public function searchFriend($fullName)
{
return Auth::user()->friends()->whereHas('friend', function ($query) use ($fullName) {
$query->where('full_name', 'like', "%{$fullName}%");
})->get();
}
If you have first_name and last_name in User model then you can use concat.
public function searchFriend($fullName)
{
return Auth::user()->friends()->whereHas('friend', function ($query) use ($fullName) {
$query->whereRaw("concat(first_name, ' ', last_name) like ?", ["%{$fullName}%"]);
})->get();
}
I'm building a website with laravel.
I use these models:
Post
Countrytag
Citytag
Categorytag
A post can have many countrytags, citytags or categorytags and vice versa.
I would like to search posts by tags.
I use this function:
public function blogsearchresults(Request $request)
{
$attributes=request()->validate([
'countrytag_id'=>'required_without_all:citytag_id,categorytag_id',
'citytag_id'=>'required_without_all:countrytag_id,categorytag_id',
'categorytag_id'=>'required_without_all:countrytag_id,citytag_id'
]);
$posts=Post::all();
if($request->has('countrytag_id')) {
$countryid=$attributes['countrytag_id'];
$posts =$posts->whereHas('countrytags', function ($query) use ($countryid){
$query->wherein('countrytag_id', $countryid);
});
}
if($request->has('citytag_id')) {
$cityid=$attributes['citytag_id'];
$posts=$posts->whereHas('citytags', function ($query2) use ($cityid){
$query2->wherein('citytag_id', $cityid);
});
}
if($request->has('categorytag_id')) {
$categoryid=$attributes['categorytag_id'];
$posts=$posts->whereHas('categorytags', function ($query3) use ($categoryid){
$query3->wherein('categorytag_id', $categoryid);
});
}
$posts=$posts->paginate();
return view('pages.blog.blogsearchresults', compact('posts'));
}
But I get this error:
Method Illuminate\Database\Eloquent\Collection::whereHas does not exist.
Could you please help me in solving this issue?
Thank you
the method all() returns a collection, you can't use query builder methods on it. (also when you query build, you dont need to assign the value $posts over and over)
public function blogsearchresults(Request $request)
{
$attributes = request()->validate([
'countrytag_id'=>'required_without_all:citytag_id,categorytag_id',
'citytag_id'=>'required_without_all:countrytag_id,categorytag_id',
'categorytag_id'=>'required_without_all:countrytag_id,citytag_id'
]);
$postQuery = Post::query();
if($request->has('countrytag_id')) {
$countryid = $attributes['countrytag_id'];
$postQuery->whereHas('countrytags', function ($query) use ($countryid){
$query->wherein('countrytag_id', $countryid);
});
}
if($request->has('citytag_id')) {
$cityid = $attributes['citytag_id'];
$postQuery->whereHas('citytags', function ($query2) use ($cityid){
$query2->wherein('citytag_id', $cityid);
});
}
if($request->has('categorytag_id')) {
$categoryid = $attributes['categorytag_id'];
$postQuery->whereHas('categorytags', function ($query3) use ($categoryid){
$query3->wherein('categorytag_id', $categoryid);
});
}
$posts = $postQuery->paginate();
return view('pages.blog.blogsearchresults', compact('posts'));
}
I have these 2 linked models: jobs and job_translations. A job have many translations. So in my job model, there is :
/**
* Get the translations for the job.
*/
public function translations()
{
return $this->hasMany('App\Models\JobTranslation');
}
In my controller, I want to build a query dynamically like that :
$query = Job::query();
if ($request->has('translation')) {
$query->translations()->where('external_translation', 'ilike', '%'.$request->translation.'%');
}
$jobs = $query->paginate(10);
I have this error :
Call to undefined method Illuminate\Database\Eloquent\Builder::translations()
Is it possible to do such a dynamic query with Eloquent?
Yes, it is possible. What you are looking for is whereHas('translations', $callback) instead of translations():
$query = Job::query();
if ($request->has('translation')) {
$query->whereHas('translations', function ($query) use ($request) {
$query->where('external_translation', 'ilike', '%'.$request->translation.'%');
});
}
$jobs = $query->paginate(10);
Your query can be improved further by using when($condition, $callback) instead of an if:
$jobs = Job::query()
->when($request->translation, function ($query, $translation) {
$query->whereHas('translations', function ($query) use ($translation) {
$query->where('external_translation', 'ilike', "%{$translation}%");
});
})
->paginate(10);
the issue you should do eager loading to detected on next chained query like this:
$query = Job::with('translations')->query();
I have made a query in Laravel Eloquent to search in table.
public function searchContest($search){
$category = [];
$area = [];
if(isset($search['area'])){
$area = $search['area'];
}
if(isset($search['category'])){
$category = $search['category'];
}
$qry = self::whereIn('area',$area)
->whereIn('category', $category)
->get();
var_dump($query);
return;
}
But sometimes, area or category is empty and whereIn does not work with it. I'm not able to find any working solutions in the net. How can I make such a query?
Or you can take advantage of the conditional clauses as here
DB::table('table_name')
->when(!empty($category), function ($query) use ($category) {
return $query->whereIn('category', $category);
})
->when(!empty($area), function ($query) use ($area) {
return $query->whereIn('area', $area);
})
->get();
$q = self::query();
if (isset($search['area'])) {
$q->whereIn('area', $search['area']);
}
if (isset($search['category'])) {
$q->whereIn('category', $search['category']);
}
$qry = $q->get();
You can use query scope inside the entity
public function scopeArea($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('area', $ids);
}
public function scopeCategory($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('category', $ids);
}
Now you can build the query
$entity
->area($area)
->category($category)
->get();
https://laravel.com/docs/5.7/eloquent#query-scopes
These are all optional fields, so will I have to write multiple queries with conditions or is there any way to handle this using Laravel? What will be the query looks like?
Thanks
It depends a bit on how the filters are submitted, but you can do one of the following two things (and probably a gazillion more...):
public function listCars(Request $request)
{
$cars = Car::when($request->get('make'), function ($query, $make) {
$query->where('make', $make);
})
->when($request->get('model'), function ($query, $model) {
$query->where('model', $model);
})
->...
->get();
// do what you have to do
}
So you are basically wrapping your query builder calls in when($value, $callback), which will only execute $callback if $value evaluates to true. When you retrieve a not set parameter with $request->get('parameter'), it will return null and the callback is not executed. But be careful, if $value is 0 it will also not execute the callback. So be sure you don't have this as an index.
As alternative to this, you can also do the same thing but with a bit less eloquent expressions...
public function listCars(Request $request)
{
$query = Car::query();
if($request->filled('make')) {
$query->where('make', $request->get('make'));
}
if($request->filled('model')) {
$query->where('model', $request->get('model'));
}
// some more filtering, sorting, ... here
$cars = $query->get();
// do what you have to do
}
Here is a working example of something similar query i have in my app.
$filters = $vehicle->newQuery();
if (!empty($request->make)) {
$filters->where('make_id', $request->make);
}
if (!empty($request->carmodel)) {
$filters->where('carmodel_di', $request->carmodel);
}
if (!empty($request->year)) {
$filters->where('year_id', $request->year);
}
if (!empty($request->engine)) {
$filters->where('engine_id', $request->engine);
}
if (!empty($request->price)) {
$filters->where('price_id', $request->price);
}
$cars = $filters->latest()->paginate(50);
and now push the $cars variable to view. I hope this works for you or atleast gives you an idea on how to proceed
here is a simple way, you can also make the joins conditional inside the ->when() condition, if you are in Laravel version > 5.4, use $request>filled() instead of $request->has()
public function listCars(Request $request)
{
$cars = Car::when($request->has('make'), function ($query)use($request) {
$query->join('maker','car.makerId','=','maker.id')
->where('make', $request->input('make'));
})
->when($request->has('model'), function ($query)use($request) {
$query->where('model', $request->input('model'));
})
->...
->get();
// you can even make the join conditionaly,
}
$fiterItem = ['make','model','year','engine','price'];
$filters = $vehicle->newQuery();
foreach ($filter as $item) {
if ($r->filled($item)) {
$list->where($item, $r->query($item));
}
}
$list = $filters->paginate(20);