Laravel eloquent complex search query question - laravel

Have been trying different approaches to perform a search query with Eloquent on multiple and nested many-to-many and hasmany relationships but having trouble finding the solution.
To simplify below the part of the models where I want to perform the search using 'model', 'LIKE', '%' . $request->name . '%'.
The models
class Company extends Model {
// the class properties, dates, etc...
public function offices(){
return $this belongsToMany(Office::class);
}
}
class Office extends Model {
// the class properties, dates, etc...
public function companies(){
return $this belongsToMany(Company::class);
}
public function addresses(){
return $this belongsToMany(Address::class);
}
}
class Address extends Model {
// the class properties, dates, etc...
public function offices(){
return $this belongsToMany(Office::class);
}
public function services(){
return $this belongsToMany(Service::class);
}
public function countries(){
return $this belongsToMany(Country::class);
}
}
class Service extends Model {
// the class properties, dates, etc...
public function addresses(){
return $this belongsToMany(Address::class);
}
}
class Country extends Model {
// the class properties, dates, etc...
public function addresses(){
return $this belongsToMany(Address::class);
}
}
The goal to to search on the different models based on the main model which is Company. In pseudo code would be something like the following:
Find in Company where name like $request->name
Or where Company website like $request->name
Or where Office office_name $request->name
Or where Address street $request->name
Or where Address country.name $request->name
Or where Service addresses.service.name $request->name
A Company has many Office
An Office has many Address
An Address has a Country and
An Address has many Services.
In all of them, and to simplify (i'll probably be able to extrapolate and work o other fields for each model, I'll be using the name column. Eg. company name, office name, address name, service name country name.
What I have now is the following which is not performing the search as I need:
public function search(Request $request)
{
$data = Company::Active()->with('offices', 'addresses', 'offices.addresses')
->where('company_name', 'LIKE', '%' . $request->name . '%')
->orWhere('company_short_description', 'LIKE', '%' . $request->name . '%')
->orWhere('company_long_description', 'LIKE', '%' . $request->name . '%')
->orWhere('company_website', 'LIKE', '%' . $request->name . '%')
->whereHas('offices', function ($query) use ($request) {
$query->where('name', 'LIKE', '%' . $request->name . '%');
})
->whereHas('offices.addresses', function ($query) use($request){
$query->where('name', 'LIKE', '%' . $request->name . '%')
->orWhere('address_city', 'LIKE', '%' . $request->name . '%');
})
->orderBy('company_name')
->paginate(20);
return response()->json($data, 200);
}
Thank you in advance for any help or tips on the better solution to perform this broad (complex) search query with Eloquent.

I think I could manage the query. Not sure if the best approach or it might need some optimization, but I could get at least the most approximate result sets from the below query. Suggestions on improvements are welcome :)
public function search(Request $request)
{
$data = Company::Active()->with('offices', 'addresses', 'offices.addresses')
->where('company_name', 'LIKE', '%' . $request->name . '%')
->orWhere('company_short_description', 'LIKE', '%' . $request->name . '%')
->orWhere('company_long_description', 'LIKE', '%' . $request->name . '%')
->orWhere('company_website', 'LIKE', '%' . $request->name . '%')
->orWhereHas('offices', function ($query) use ($request) {
$query->where('name', 'LIKE', '%' . $request->name . '%');
})
->orWhereHas('offices.addresses', function ($query) use($request){
$query->where('name', 'LIKE', '%' . $request->name . '%')
->orWhere('address_city', 'LIKE', '%' . $request->name . '%');
})
->orWhereHas('offices.addresses.services', function ($query) use($request){
$query->where('name', 'LIKE', '%' . $request->name . '%');
})
->orderBy('company_name')
->paginate(20);
return response()->json($data, 200);
}

Related

How to get foreign key data in main field Laravel

I have a problem connecting to the data for searching the customer's name because I only identify the id as a foreign key. How can I get data from the customer table? I tried using a join table but no got no result.
public function render()
{
$search = $this->searchTerm;
$data = Order::with('customer')->where('user_id', Auth::id())
->where(function ($query) use ($search) {
$query->where('customer_id', 'like', '%' . $search . '%') // <- this field linked in customers table to get name of customer
->orWhere('orderNumber', 'like', '%' . $search . '%');
})->orderBy('id', $this->sortDirection)->paginate(9);
return view('livewire.dashboard.orders.list-order', compact('data'));
}
If I am right I think you are trying to search for customer name through customer relationship
You can do it like this:
$search = $this->searchTerm;
$data = Order::where('user_id', Auth::id())->with(['customer' =>
function($query) use($search){
$query->where('name','like', '%' . $search . '%')
->orWhere('orderNumber', 'like', '%' . $search . '%');
}])->orderBy('id', $this->sortDirection)->paginate(9);

searching on name instead of id on sql

I have search input in my products page. I can search on name on description and on category if I type the id but that's not really practical how i change this sql so i can search on the name of the category instead of the id.
DB i have Products | name,description,category_id
Categories | id,name
public function scopeFilter($query,array $filters){
if ($filters['search'] ?? false){
$query
->where('name', 'like', '%' . request('search') . '%')
->orWhere('description', 'like', '%' . request('search') . '%')
->orWhere('category_id', 'like', '%' . request('search'). '%');
}
}
Since the category is a related model search on the relationship:
public function scopeFilter($query,array $filters){
if ($filters['search'] ?? false){
$query
->where('name', 'like', '%' . request('search') . '%')
->orWhere('description', 'like', '%' . request('search') . '%')
->orWhereHas('category', function ($q) {
$q->where('name','like', '%' . request('search'). '%'
});
}
}
This is assuming you have defined your relationship in your model.
Since the category is a related model search on the relationship AND I suggest using this code: ‌
public function scopeFilter($query,array $filters) {
if ($filters['search'] ?? false){
return $query->where('name', 'like', '%' . request('search') . '%')
->orWhere('description', 'like', '%' . request('search') . '%')
->orWhereHas('category', function ($q) {
$q->where('name','like', '%' . request('search'). '%');
});
}
return $query;
}

How To Get Search Query From Multiple Columns in Database

I have search form to get information from table named books.
Right now i'm using this controller
public function search(Request $request)
{
$keyword = $request->input('keyword');
$query = Book::where('judul', 'LIKE', '%' . $keyword . '%');
$book_list = $query->paginate(5);
$pagination = $book_list->appends($request->except('page'));
$total_book = $book_list->total();
return view('dashboards.index', compact('book_list', 'keyword', 'pagination', 'total_book'));
}
The problem is the data that i get from the request only available for judul. it just show empty result if the input keyword search addressed to search writter or publisher
I want the search form able to get data from other columns named writters and publisher
Is there any method to get data from multiple column?
You can use orwhere to fullfill this, like this
Book::where(function ($query) use($keyword) {
$query->where('judul', 'like', '%' . $keyword . '%')
->orWhere('writters', 'like', '%' . $keyword . '%');
})
->get();
I hope it helps you.
You can execute conditional queries in many ways.
1. You can use when():
Book::when($keyword, function ($q) use ($keyword) {
return $q->where('judul', 'LIKE', '%' . $keyword . '%');;
})
->get();
2. Use the where closure:
Book::where(function($q) use ($keyword, $request) {
if ($request) {
$q->where('judul', 'LIKE', '%' . $keyword . '%');
}
})
->get();
3. Do this:
$books = Book::query();
if ($request) {
$books = $books->where('judul', 'LIKE', '%' . $keyword . '%');
}
$books = $books->get();

Laravel sort model by one to many relationship

I have two models Location and Danger
Danger has two fields location_id and user_id it simply save users report about locations
btw Danger has a one to many relation with Location
the question is
how can I sort locations with count of it's danger in a search form
here is my form:
$locations = Location::latest();
if ($request->get('q')) {
$q = $request->get('q');
$locations->where('desc', 'like', '%' . $q . '%')
->orWhere('name', 'like', '%' . $q . '%');
}
$locations=$locations->paginate(12);
return view('list')->with(compact('locations'));
If your location has many danger and your relation is named dangers then you can use withCount() for sorting as:
$locations = Location::withCount('dangers');
if ($request->get('q')) {
$q = $request->get('q');
$locations->where('desc', 'like', '%' . $q . '%')
->orWhere('name', 'like', '%' . $q . '%');
}
$locations->orderBy('dangers_count', 'desc')
$locations=$locations->paginate(12);
this might work.
$locations = Location::latest();
if ($request->get('q')) {
$q = $request->get('q');
$locations->where('desc', 'like', '%' . $q . '%')
->orWhere('name', 'like', '%' . $q . '%');
$locations->sortBy(function($item, $key){
return $location->danger()->count();
})
}
$locations=$locations->paginate(12);
return view('list')->with(compact('locations'));

Laravel eloquent search on fields of related model

I have an eloquent models as,
User : users(id, username, password, email, status)
Profile : profiles(id, user_id, first_name, last_name, gender, dob)
In the controller logic, I am eagerly loading the Profile model.
I can do this,
$user = User::with('Profile')->get();
or
$user = User::with('Profile')->where('status', '1')->get();
but how to do something like,
$user = User::with('Profile')->where('status', '1')->where('gender', 'Male')->get();
That's where whereHas comes in handy:
$user = User::with('Profile')->where('status', 1)->whereHas('Profile', function($q){
$q->where('gender', 'Male');
})->get();
Basically it adds the condition that the user needs to have a profile with gender = Male
If you want to search multiple columns in relation model.
$searchText = 'test text';
Product::with('owner')->where(function($query) use ($searchText)
{
$query->where('product_name', 'LIKE', '%' . $searchText . '%');
$columns = ['product_code', 'place_location', 'remark'];
foreach ($columns as $column ) {
$query->orWhere($column, 'LIKE', '%' . $searchText . '%');
}
$query->orWhereHas('owner', function($q) use ($searchText) {
$q->where(function($q) use ($searchText) {
$q->where('name', 'LIKE', '%' . $searchText . '%');
$q->orWhere('company_name', 'LIKE', '%' . $searchText . '%');
});
});
});
Let's say you've multiple relations
and you want to search records based on multiple relational columns value
User::with('associate')
->where('name', 'like', '%' . $input . '%')
->orWhere(function ($query) use ($input) {
$query->whereHas('associate', function ($q) use ($input) {
$q->where('first_name', 'like', '%' . $input . '%');
});
})
->orWhere(function ($query) use ($input) {
$query->with('roles')->whereHas('roles', function ($q) use ($input) {
$q->where('display_name', 'like', '%' . $input . '%');
});
})
->get();
Suppose, Your search input field name is q.
function name(Request $request){
$query = User::select();
if($request->q && $request->q !=''){
// if you search
$keyword = $request->q;
$query = User::with('Profile')->whereHas('Profile', function($q) use
($keyword){
$q->where('gender', 'like', "%{$keyword}%" );
});
}
$query->latest('id')->paginate();
}

Resources