Search in all columns (Eloquent) - laravel

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

Related

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) => ...).

laravel query builder search all fields

Guys I need to have a filter that validates in all fields with orWhere, for example: users? Search = Jhon he has to check that there is jhon in the name, email ....
Has anyone done this?
thankful
Same with other answer, you should use multiple orWhere() to do that
Here is the sample
$search = 'Jhon';
$conditions = ['name', 'email'];
$data = User::where(function ($query) use ($conditions, $search) {
foreach ($conditions as $column)
$query->orWhere($column, 'like', '%' . $search . '%');
})->get();
You Can get this type.
$query = User::query();
$columns = ['name', 'surname', 'address'];
foreach($columns as $column){
$query->orWhere($column, 'LIKE', '%' . $input . '%');
}
$users = $query->get();

Laravel Eloquent add 'where' clause in the query by condition

I want to add a condition first before adding another where query it but seems that laravel won't allow. I want something like the following.
function index()
{
$role = Auth::user()->role; //SEE_ALL, SEE_DEPT_A, SEE_DEPT_B
$q = Input::get('q');
if ($q != "") {
$user = User::where('name', 'LIKE', '%' . $q . '%')
->orWhere('email', 'LIKE', '%' . $q . '%')
->orderBy('name');
if ($role == "SEE_DEPT_A") {
$user->where('user_department', "A");
}
$user->paginate(10)->appends('q', $q);
}
return view('users.index')->with('data', ['users' => $user, 'q' => $q]);
}
You should use the when() function :
$user = User::where('name', 'LIKE', '%' . $q . '%')
->orWhere('email', 'LIKE', '%' . $q . '%')
->orderBy('name')
->when($role == "SEE_DEPT_A", function($query){
return $query->where('user_department', "A");
})->paginate(10)->appends('q', $q);
You need to assign the statement where you used where clause:
if ($role == "SEE_DEPT_A") {
$user = $user->where('user_department', "A");
}
And if the if statement does not run (in case of false), it will throw an error about $user being undefined
You can insert multi conditions like this:
$user_model = User::where('name', 'LIKE', '%' . $q . '%')
->orWhere('email', 'LIKE', '%' . $q . '%')
->orderBy('name');
if ($role == "SEE_DEPT_A") {
$user_model = $user_model->where('user_department', "A");
}
...
//other if statements
...
$users = $user_model->paginate(10)->appends('q', $q);

laravel search multiple keywords

I have a problem with search form on my website. Basically, when user will type multiple keywords to search form (e.g. business card ) then search result will show all images from keyword 1 (e.g. business) and all images from keyword2 (e.g. card). This is bad, the search form is not relevant at all. Can you please look at the code down bellow and help me fix it so the search form will show only images with both keywords together (keyword1 + AND + keyword2).
public function search($search, $category = null, $timeframe = null)
{
$extends = explode(' ', $search);
if ($category) {
$categoryId = $this->category->whereSlug($category)->first();
}
$images = $this->posts($category, $timeframe)->where('title', 'LIKE', '%' . $search . '%')
->orWhere('tags', 'LIKE', '%' . $search . '%')
->whereNull('deleted_at')->whereNotNull('approved_at')->orderBy('approved_at', 'desc');
foreach ($extends as $extend) {
if (isset($categoryId)) {
$images->whereCategoryId($categoryId)->Where('tags', 'LIKE', '%' . $extend . '%')->whereNotNull('approved_at')->whereNull('deleted_at')
->whereCategoryId($categoryId)->orWhere('title', 'LIKE', '%' . $search . '%')->whereNotNull('approved_at')->whereNull('deleted_at')
->whereCategoryId($categoryId)->orWhere('image_description', 'LIKE', '%' . $search . '%')->whereNotNull('approved_at')->whereNull('deleted_at');
} else {
$images->orWhere('tags', 'LIKE', '%' . $extend . '%')->whereNotNull('approved_at')->whereNull('deleted_at')
->orWhere('title', 'LIKE', '%' . $search . '%')->whereNotNull('approved_at')->whereNull('deleted_at')
->orWhere('image_description', 'LIKE', '%' . $search . '%')->whereNotNull('approved_at')->whereNull('deleted_at');
}
}
return $images = $images->with('user', 'comments', 'favorites')->whereNotNull('approved_at')->whereNull('deleted_at')->paginate(perPage());
}
When you use the % sign before and after the search query, you say "give me anything with that items", if you want your system to search and give results exactly as per what the user has entered, you should use only the key phrase. try the code below.
public function search($search, $category = null, $timeframe = null)
{
$extends = explode(' ', $search);
if ($category) {
$categoryId = $this->category->whereSlug($category)->first();
}
$images = $this->posts($category, $timeframe)
->where('title', 'LIKE', "$search")
->orWhere('tags', 'LIKE', "$search")
->whereNull('deleted_at')
->whereNotNull('approved_at')
->orderBy('approved_at', 'desc');
foreach ($extends as $extend) {
if (isset($categoryId)) {
$images->whereCategoryId($categoryId)->Where('tags', 'LIKE', "$search")
->whereNotNull('approved_at')->whereNull('deleted_at')
->whereCategoryId($categoryId)->orWhere('title', 'LIKE', "$search")
->whereNotNull('approved_at')->whereNull('deleted_at')
->whereCategoryId($categoryId)
->orWhere('image_description', 'LIKE', "$search")
->whereNotNull('approved_at')->whereNull('deleted_at');
}
else {
$images->orWhere('tags', 'LIKE', "$extend")
->whereNotNull('approved_at')->whereNull('deleted_at')
->orWhere('title', 'LIKE', "$search")
->whereNotNull('approved_at')->whereNull('deleted_at')
->orWhere('image_description', 'LIKE', "$search")
->whereNotNull('approved_at')->whereNull('deleted_at');
}
}
return $images = $images->with('user', 'comments', 'favorites')
->whereNotNull('approved_at')
->whereNull('deleted_at')
->paginate(perPage());
}

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