How to search from relationship data ? In laravel - 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

Related

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();

Laravel dynamic query

I have a GET form with three filters.
make
Year
country
I need to get all posts from db. But filter the results based on these three filters.
If a country is selected, get posts for that country only or all countries.
if a make is selected, get posts for that make only or all makes
if a year is selected, get posts for that year only or all years
how to write one query that filters all these three options. What I have done is used if and else statements and written different queries for each scenario. That's 9 queries to get one information. Can we make it dynamic and just have one query?
My Example query:
public function search(Request $request)
{
$search=$request->input('search');
if($request->input('country') == "all")
{
$posts = Post::where('status','Published')->orderBy('status_change','DESC')
->where('status','Published')
->where(function($query) use ($search){
$query->where('title','LIKE','%'.$search.'%');
$query->orWhere('model','LIKE','%'.$search.'%');
$query->orWhere('notes','LIKE','%'.$search.'%');
$query->orWhere('description','LIKE','%'.$search.'%');
})
->paginate(25);
}
else
{
$posts = Country::where('country_name', $request->input('country'))->first()->posts()->orderBy('status_change','DESC')
->where('status','Published')
->where(function($query) use ($search){
$query->where('title','LIKE','%'.$search.'%');
$query->orWhere('model','LIKE','%'.$search.'%');
$query->orWhere('notes','LIKE','%'.$search.'%');
$query->orWhere('description','LIKE','%'.$search.'%');
})
->paginate(25);
}
return view('welcome')
->with('published_posts',$posts)
;
}
I think something like this would work:
/**
* #param Request $request
*/
function search(Request $request)
{
$postsQuery = Post::where('status', 'Published');
if ($request->has('country')) {
$country = $request->country;
// assuming relationships are setup correclty
$postsQuery->whereHas('country', function ($query) use ($country) {
$query->where('country_name', 'LIKE', $country);
});
}
if ($request->has('search')) {
$postsQuery->where(function ($query) use ($search) {
$query->where('title', 'LIKE', '%' . $request->search . '%');
$query->orWhere('model', 'LIKE', '%' . $request->search . '%');
$query->orWhere('notes', 'LIKE', '%' . $request->search . '%');
$query->orWhere('description', 'LIKE', '%' . $request->search . '%');
});
}
$postsQuery->orderBy('status_change', 'DESC')->paginate(25);
return view('welcome')->with('published_posts', $result);
}
I used 'when' method.
$make = null;
$year = null;
$country = null;
if($request->filled('make')){
$make = $request->query('make');
}
if($request->filled('year')){
$year = $request->query('year');
}
if($request->filled('country')){
$country = $request->query('country');
}
$posts = DB::table('posts')
->when($make, function($query, $make){
return $query->where("make", "=", $make);
})
->when($year, function($query, $year){
return $query->whereYear("year", "=", $year);
})
->when($country, function($query, $country){
return $query->where('country', "like", $country);
})
->get();
Check out the Laravel Docs:
Check out an article here

Search Function with Multiple Conditions in 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();
}

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