Laravel eloquent search on fields of related model - laravel

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

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

Search in all columns (Eloquent)

I am doing a method to search in all the columns of the table
$busqueda = $request->input('buscar');
/* Get columns */
$client = new Crmclient;
$table = $client->getTable();
$columns = \Schema::getColumnListing($table);
foreach ($columns as $column) {
$users_client = Crmclient::where('user_id', Auth::id())
->where($column, 'like', '%' . $busqueda . '%')
->orWhere('user_id_subaccount', Auth::id())
->where($column, 'like', '%' . $busqueda . '%')
->get();
}
whats wrong? I can get all the columns and if I do var_dump inside the loop in some interactions it looks for me and in others not, but finally I get the empty array
Try this
$columns = \Schema::getColumnListing((new Crmclient)->getTable());
$users_client = Crmclient::where(function ($query) {
$query->where('user_id', Auth::id())->orWhere('user_id_subaccount', Auth::id());
})->where(function ($query) use ($columns, $busqueda) {
foreach ($columns as $column) {
$query->orWhere($column, 'like', "%{$busqueda}%");
}
})->get();

Way to structure code for "Search Engine"

I'm currently putting together some code that allows for a user to search an activities table in multiple ways (i.e. if title checkbox is selected) I feel like my code looks a little messy so I wanted to come on stack overflow and ask everyone what would be the best way to make this code more elegant? I'm just looking for ways to improve, have more readable code, and have a better structure for it.
if (request('name')){
$name = request('name');
$user = User::where('name', $name)->firstOrFail();
if (request('title') == 1) {
$activities = Activity::with('activity')->where('user_id', $user->id)->whereHas('thread', function ($query) use ($search, $user) {
$query->where('threads.user_id', '=', $user->id)
->where('threads.title', 'LIKE', '%' . $search . '%');
})->get();
dd($activities);
} else {
$activities = Activity::with('activity')->where('user_id', $user->id)->whereHas('thread', function ($query) use ($search, $user) {
$query->where('threads.user_id', '=', $user->id)
->where('threads.title', 'LIKE', '%' . $search . '%')
->orWhere('threads.body', 'LIKE', '%' . $search . '%');
})->orWhereHas('reply', function ($query) use ($search, $user) {
$query->where('replies.user_id', '=', $user->id)
->where('replies.body', 'LIKE', '%' . $search . '%');
})->get();
dd($activities);
}
} else {
if (request('title') == 1) {
$activities = Activity::with('activity')->where('user_id', $user->id)->whereHas('thread', function ($query) use ($search, $user) {
$query->where('threads.title', 'LIKE', '%' . $search . '%');
})->get();
dd($activities);
} else {
$activities = Activity::with('activity')->whereHas('thread', function ($query) use ($search) {
$query->where('threads.body', 'LIKE', '%' . $search . '%')
->orWhere('threads.title', 'LIKE', '%' . $search . '%');
})->orWhereHas('reply', function ($query) use ($search) {
$query->where('replies.body', 'LIKE', '%' . $search . '%');
})->get();
}
}
Thank you!
You could use the query builder's when and unless methods as well as define some query scopes in your models so your end result could look something like this
$user = request('name') ? User::where('name', $name)->firstOrFail() : null;
$title = request('title') == 1;
$activities = Activity::with('activity')->search($search, $user, $title)->get();
# Activity model
public function scopeSearch(Builder $query, ?$search = null, ?User $user = null, bool $title = false)
{
if (!$search)
return $query;
else
return $query->when($user, fn($q) => $q->where('user_id', $user->id))
->whereHas('thread', fn($thread) => $thread->search($search, $user))
->unless($title, fn($q) => $q->orWhereHas('reply', fn($reply) => $reply->search($search, $user)));
}
# Thread model
public function scopeSearch(Builder $query, ?string $search = null, ?User $user = null)
{
if (!$search)
return $query;
else
return $query->when($user, fn($q) => $q->where('threads.user_id', $user->id))
->where(fn($q) => $q->where('threads.title', 'LIKE', "%$search%")
->orWhere('threads.body', 'LIKE', "%$search%"));
}
# Reply model
public function scopeSearch(Builder $query, ?string $search = null, ?User $user = null)
{
if (!$search)
return $query;
else
return $query->when($user, fn($q) => $q->where('replies.user_id', $user->id))
->where('replies.body', 'LIKE', "%$search%");
}
Scopes are basically reusable queries. You can define them at a global level (for all models) or at a local level (this is what I've done here).
Local Query Scopes
With them, I've moved nearly all the query related logic to the models but if you prefer, you could still write it all in the controller.
Using the scopes I defined,
$activities = Activity::with('activity')
// call Activity Model's search scope
->search($search, $user, $title)
->get();
translates to
$activities = Activity::with('activity')
->when($user, fn($q) => $q->where('user_id', $user->id))
// call Thread model's search scope in whereHas('thread', ...) closure
->whereHas('thread', fn($thread) => $thread->search($search, $user))
// call Reply model's search scope in whereHas('reply', ...) closure
->unless($title, fn($q) => $q->orWhereHas('reply', fn($reply) => $reply->search($search, $user)))
->get();
which in turn translates to
$activities = Activity::with('activity')
->when($user, fn($q) => $q->where('user_id', $user->id))
->whereHas('thread', function ($thread) use ($search, $user) {
$thread->when($user, fn($q) => $q->where('threads.user_id', $user->id))
->where(fn($q) => $q->where('threads.title', 'LIKE', "%$search%")
->orWhere('threads.body', 'LIKE', "%$search%"));
})
->unless($title, fn($q) => $q->orWhereHas('reply', function ($reply) use ($search, $user) {
$reply->when($user, fn($q) => $q->where('replies.user_id', $user->id))
->where('replies.body', 'LIKE', "%$search%");
}))
->get();
The $title variable could be inlined at this point. ->unless(request('title') == 1, ...)
Conditional Clauses: when(), unless().
Logical Grouping: where(fn($q) => ...).

How to search a term in eloquent relation of a model?

There is a Model named Profile that has user relation.
public function user(){
return $this->belongsTo(User::class);
}
and the profile table column is:
id | user_id | image | tel
The question is how I can search the name of a user from profile?
$term = request()->term;
$profiles = Profile::with('user')->where('name', 'like', '%'.$term.'%')->get();
Then I want to show the profiles that their name comes from the search term.
use whereHas() ref link https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-existence
$term = request()->term;
$profiles = Profile::whereHas('user',function($q) use($term){
$q->where('name', 'like', '%' . $term . '%');
})->get();
$filterUser = function ($q) use ($term) {
$q->where('name', 'like', '%' . $term. '%');
};
$term = request()->term;
$profiles = Profile::whereHas('user', $filterUser)->with(['user'=> $filterUser])->get();
If you want to syntactically optimize the code and want to use this more often then add this method in model
public function scopeWithAndWhereHas($query, $relation, $constraint){
return $query->whereHas($relation, $constraint)
->with([$relation => $constraint]);
}
And Usage:
$term = request()->term;
$profiles = Profile::withAndWhereHas('user', function($q) use ($term){
$q->where('name', 'like', '%' . $term. '%');
})->get();
You need to scope it on the subquery, something like this:
$profiles = Profile::with(['user' => function ($query) {
$query->where('name', 'like', '%'.$term.'%');
}])->get();

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

Resources