Search Function with Multiple Conditions in Laravel - laravel

I tried to make a search function based on 4 requests; categories, location, keyword, and sorting. The search function with 3 requests (location, categories, and sorting) works well and has correct output.
But the problem is, when my website sent request with keywords data, the output results are only the result from keywords request only, when I try to sent a location / categories requests, the output does not change (only the output of the keyword request only)
Here is the code I write:
public function getBy(Request $request) {
$categories = $request->all()['categories'];
$location = $request->all()['location'];
$sorting = $request->all()['sorting'];
$keyword = $request->all()['keyword'];
//--- sorting code ---
//keyword request
if ($keyword === null) {
$jobs = Job::query();
} else {
$jobs = Job::query()->where('job_title', 'LIKE', "%{$keyword}%")
->orWhere('title', 'LIKE', "%{$keyword}%")
->orWhere('description', 'LIKE', "%{$keyword}%")
->orWhereHas('users', function ($q) use ($keyword) {
$q->where('company_name', 'LIKE', "%{$keyword}%");
})->orWhereHas('categories', function ($q) use ($keyword) {
$q->where('category', 'LIKE', "%{$keyword}%");
})->orWhereJsonContains('tags', $keyword);
}
//location and categories request
if ($location === [] && $categories === []) {
$jobs;
} elseif ($location === []) {
$jobs->whereHas('categories', function ($q) use ($categories) {
$q->whereIn('slugs', $categories);
});
} elseif ($categories === []) {
$jobs->whereHas('location', function ($q) use ($location) {
$q->whereIn('city_name', $location);
});
} else {
$jobs->whereHas('categories', function ($q) use ($categories) {
$q->whereIn('slugs', $categories);
})->whereHas('location', function ($q) use ($location) {
$q->whereIn('city_name', $location);
});
}
//return as JSON
}

The main issue with your code is your locations and categories search query were not setting $jobs again. It should look like this:
$jobs = $jobs->whereHas('categories', function ($q) use ($categories) {
$q->whereIn('slugs', $categories);
});
This will set the $jobs variable to include the new conditions of the query.
I would also suggest not checking if $locations or $categories are empty, as they if statements for each are dealing with the condition already. Here is some refactored code:
public function getBy(Request $request) {
$sorting = $request->all()['sorting'];
//--- sorting code ---
//keyword request
if (! $keywords = request('keywords')) {
$jobs = Job::query();
} else {
$jobs = Job::query()->where('job_title', 'LIKE', "%{$keyword}%")
->orWhere('title', 'LIKE', "%{$keyword}%")
->orWhere('description', 'LIKE', "%{$keyword}%")
->orWhereHas('users', function ($q) use ($keyword) {
$q->where('company_name', 'LIKE', "%{$keyword}%");
})->orWhereHas('categories', function ($q) use ($keyword) {
$q->where('category', 'LIKE', "%{$keyword}%");
})->orWhereJsonContains('tags', $keyword);
}
foreach (['categories', 'locations'] as $field) {
if ($request->filled($field)) {
$jobs = $jobs->whereHas($field, function ($q) use ($field) {
$q->whereIn('slugs', request($field));
});
}
}
return $jobs->get()->toArray();
}
Here we loop through the categories and locations request data and see if the data is ->filled() (is defined and not empty). If so, we run the query.

Try this
public function getBy(Request $request) {
$categories = $request->categories;
$location = $request->location;
$sorting = $request->sorting;
$keyword = $request->keyword;
//--- sorting code ---
$jobs = Job::query();
//keyword request
if ($keyword !== null) {
$jobs = $jobs->where('job_title', 'LIKE', "%{$keyword}%")
->orWhere('title', 'LIKE', "%{$keyword}%")
->orWhere('description', 'LIKE', "%{$keyword}%")
->orWhereHas('users', function ($q) use ($keyword) {
$q->where('company_name', 'LIKE', "%{$keyword}%");
})->orWhereHas('categories', function ($q) use ($keyword) {
$q->where('category', 'LIKE', "%{$keyword}%");
})->orWhereJsonContains('tags', $keyword);
}
//location and categories request
if ($location === []) {
$jobs = $jobs->whereHas('categories', function ($q) use ($categories) {
$q->whereIn('slugs', $categories);
});
} elseif ($categories === []) {
$jobs = $jobs->whereHas('location', function ($q) use ($location) {
$q->whereIn('city_name', $location);
});
} else {
$jobs = $jobs->whereHas('categories', function ($q) use ($categories) {
$q->whereIn('slugs', $categories);
})->whereHas('location', function ($q) use ($location) {
$q->whereIn('city_name', $location);
});
}
return $jobs->get();
}

Related

laravel inside with leftjoin is not working

I have added left join inside with but it is not working at all.
Please suggest or guide.
$q = $q->leftJoin('product_sort_order', function ($join) {
$join->on('products.id', '=', 'product_sort_order.product_id');
$join->on('products.sub_category_id', '=', 'product_sort_order.type_id');
})->orderBy('product_sort_order.sort_order', 'ASC');
Controller code (trying to get category products with relationship)
$category = Category::query();
$category->where('status', '=', '1');
$category->where('id', $sub_category_id);
// $category->where('status', '!=', '2');
$category = $category->with([
'subproducts' => function ($q) use ($request, $sub_category_id) {
$q->select('products.*');
$q->where('products.status', '=', 1);
$q->where('products.is_pendding', '=', 0);
$q->where('products.sub_category_id', $sub_category_id);
if ($request->get('theme')) {
$q->Where('products.theme_id', 'LIKE', '%' . $request->get('theme') . '%');
}
if ($request->get('categories')) {
$q->where('products.category_id', getCategoryIdFromSlug($request->get('categories')));
}
if ($request->get('sections')) {
$q->where('products.section_category_id', getSectionIdFromSlug($request->get('sections')));
}
if ((App::getLocale()) == 'en') {
// $q->orderBy('product_name_lang->en');
} else {
// $q->orderBy('product_name_lang->fr');
}
if ($request->get_j0_product == true) {
$q->where('products.delivery', 'J0');
}
// $q->orderBy('sale_price', 'DESC');
// $q->orderBy('created_at', 'DESC');
// $q = $q->leftJoin('product_sort_order', function ($join) {
// $join->on('products.id', '=', 'product_sort_order.product_id');
// $join->on('products.sub_category_id', '=', 'product_sort_order.type_id');
// })->orderBy('product_sort_order.sort_order', 'ASC');
}
])->first();
model relationship inside category
public function subproducts(){
return $this->hasMany(Product::class,'sub_category_id','id');
}

How to search from relationship data ? In laravel

public function scopeSearch($query, $value)
{
$searchValues = explode(' ', $value);
if (!$value) return $query;
return $query->where(function ($q) use ($searchValues) {
foreach ($searchValues as $token) {
$q->orWhere('name', 'like', "%{$token}%");
$q->orWhere('street', 'like', "%{$token}%");
}
});
}
I want to search the data. This model also has
public function brands()
{
return $this->belongsToMany(Brand::class, 'dealer_brands');
}
public function province()
{
return $this->belongsTo(Province::class);
}
How can I get data from the relastionship. Like Dealer(model) has data Nmae = josh , brand_id = 1 {brand.name = samsung} , province_id = 2 (province.name = "aligora"). When I search Josh Samsung Alogora, I want to ge the data. When I only search aligora, I want to get the data of model having province aligora. hOW CAN I MODIFY CODE?
looking at your model relationships. This may work for you
public function scopeSearch($query, $value)
{
if (!$value) return $query;
$searchValues = explode(' ', $value);
return $query->where(function ($q) use ($searchValues) {
foreach ($searchValues as $token) {
$q->where('name', 'like', "%{$token}%")
->orWhere('street', 'like', "%{$token}%")
->orWhereHas('brands', function ($sub_q) use ($searchValues) {
$sub_q->where('name', 'like', "%{$token}%")
->orWhere('street', 'like', "%{$token}%");
})
->orWhereHas('province', function ($sub_q) use ($searchValues) {
$sub_q->where('name', 'like', "%{$token}%")
->orWhere('street', 'like', "%{$token}%");
});
}
});
}
I have no idea about column names in related tables so repeating name and street. you can change as per requirement

How can I filter data from relations in Laravel 8?

I have 3 tables business, service , service_venues. I need services of business having service_name = $search and and get venues of selected services. I am using services and resources method.
When there is search_keyword the data is not filtered. But other conditions are working.
How can I fix this?
In business model
public function businessServices()
{
return $this->hasMany(BusinessService::class);
}
in businessService model
public function businessServiceVenues()
{
return $this->hasMany(BusinessServiceVenue::class);
}
In service file
public function getServices($business){
$businessservices = $business->with(['businessServices'=> function ($q){
$q->where('business_services.service_name', 'like', '%'.request()->search_key.'%');
}
])->first();
return new servicesResource($businessservices);
}
In service resource
$services = $this->businessServices()
->with(['businessServiceStaffs','businessServiceVenues'])
->when(request()->filled('venue_ids'), function ($q) use($request) {
$q->whereHas('businessServiceVenues', function($q1) use($request) {
$q1->whereIn('venue_id',$request->venue_ids);
});
})
->when(request()->filled('staff_id'), function ($q) use($request) {
$q->whereHas('businessServiceStaffs', function($q1) use($request) {
$q1->where('staff_id','=',$request->staff_id);
});
})
->get();
This works for me
$businessServices = $business->businessServices()
->with(['businessServiceStaffs', 'businessServiceVenues'])
->when(request()->filled('search_key'), function ($q) {
$q->where('business_services.service_name', 'like', '%' . request('search_key') . '%');
})
->when(request()->filled('venue_ids'), function ($q) {
$q->whereHas('businessServiceVenues', function ($q) {
$q->whereIn('venue_id', request('venue_ids'));
});
})
->when(request()->filled('staff_id'), function ($q) {
$q->whereHas('businessServiceStaffs', function ($q) {
$q->where('staff_id', '=', request('staff_id'));
});
})
->get();

return all the posts where author.username equals $username

I have a posts model that has this relationship to the User:
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
i am building a search function and I have this code
public function index(Request $request)
{
$search = $request->search;
$filter = $request->filter;
$append = array();
$posts = Post::with('author')->with('categories')->latest();
if($search){
switch ($filter) {
case 'username':
$posts->author->where('username', 'LIKE', '%'. $search . '%');
break;
}
$append += array('search' => $search);
$append += array('filter' => $filter);
}
$posts = $posts->paginate(3);
$posts->appends($append);
return view('core.blog.posts.index', compact('posts'));
}
I get
Undefined property: Illuminate\Database\Eloquent\Builder::$author
How do I add where that looks for author based on his username? I must be able to add this condition in an if case
You want to use whereHas() to searched based on a relation. This will return only posts that have an author with the username.
switch ($filter) {
case 'username':
$posts->whereHas('author', function($q) use($search) {
$q->where('username', 'LIKE', '%'. $search . '%');
});
break;
}
UPDATE
If you need conditional where, you can do this:
$postSelector = Post::with('categories');
if($search){
switch ($filter) {
case 'username':
$postSelector->with(['author' => function($q) use($search) {
$q->where('username', 'LIKE', '%'. $search . '%');
}]);
break;
}
$posts = $postSelector->get();

Is there a way for Eloquent whereHas to only get() the matching results?

I have the following function
public function index(Request $request)
{
$results = Service::whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})
->whereHas('locations', function ($query) use ($request){
$ran = false;
foreach($request->locations as $location)
{
if(!$ran)
{
$query->Where('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
else
{
$query->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
$ran = true;
}
})
->with('types', 'contacts', 'locations.datetimes')->toSql();
dd($results);
}
which produces
select * from `services` where exists
(select * from `conditions` inner join `condition_service` on `conditions`.`id` = `condition_service`.`condition_id` where `services`.`id` = `condition_service`.`service_id` and `id` in (13, 14) and `conditions`.`deleted_at` is null)
and exists
(select * from `service_locations` inner join `service_location_service` on `service_locations`.`id` = `service_location_service`.`service_location_id` where `services`.`id` = `service_location_service`.`service_id` and
(`town` like 'manchester' or `city` like 'manchester' or `town` like 'crewe' or `city` like 'crewe')
and `service_locations`.`deleted_at` is null) and `services`.`deleted_at` is null
The problem is the whereHas on locations brings back all results, whereas I only want the result where the town/city is a match. Whats the best way to achieve this?
i think you need to group your location query using the callback which wraps the query in () and just process the first location directly remove it from array and iterate over loop. so below code should work in your case.
$results = Service::whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})
->whereHas('locations', function ($query) use ($request){
$locations = $request->locations;
$query->where(function($builder) use($locations){
$builder->where('town', 'like', '%' . $locations[0] . '%')
->orWhere('city', 'like', '%'.$locations[0].'%');
unset($locations[0]); //remove first item as it is processed
foreach($locations as $location) {
$builder->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
});
});
let me know if you find any problem with it. :)
I managed to figure it out late last night.
I moved the with() to the top of the query and made a callback on locations.
public static function newGetSearchResults($request)
{
return Service::with(['types', 'contacts', 'locations.datetimes', 'locations' => function($query) use($request) {
$ran = false;
foreach($request->locations as $location)
{
if(!$ran)
{
$query->Where('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
else
{
$query->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
$ran = true;
}
}])
->whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})->get();
}

Resources