Laravel Yajra datatable global Search filter - laravel

I have this technical difficulty when want to use laravel yajra datatable to write custom global search query
Reference
https://yajrabox.com/docs/laravel-datatables/master/filter-column
when I do some search by passing in calendar date and searchbox value, I'm stuck at correct way to write it
Only the main ->filter got triggered
The ->filterColumn skipped through.... not sure why...
In sql vanila, it is
where firstname like %search% OR
lastname like %search% OR
fullname like %search% OR
email like %search% OR
sponsorby like %search% OR
createddate like %date%
Here is my code for reference. filterCustom is not triggered...
if ($request->ajax()) {
$users = \DB::select('
SELECT id, usercode as membercode, concat(firstname, " ", lastname) as fullname, email, created_at as createddate, (select concat(firstname, " ", lastname) from users where id= m.parentid) sponsorby
FROM users m
ORDER BY m.created_at ASC');
Update: I realize yajra doesn't support DB::select with full raw sql, however it support DB::table
So I change my sql to below,
$users = \DB::table('users')
->select('id', 'usercode as membercode', \DB::raw('concat(firstname, " ", lastname) as fullname'), 'email', 'created_at as createddate', \DB::raw('(select concat(firstname, " ", lastname) from users as b where b.id= users.parentid) as sponsorby'));
//end
return Datatables::of($users)
->addColumn('membercode', function($row){
$content= $row->membercode;
return $content;
})
->addColumn('fullname', function($row){
$content= $row->fullname;
return $content;
})
->addColumn('email', function($row){
$content= $row->email;
return $content;
})
//etc
->filter(function ($sql) use ($request) {
$search = $request->search;
if (!empty($search))
{
$sql->Where('email', 'LIKE', "%$search%");
}
})
->filterColumn('fullname', function($query, $request) {
$search = $request->search;
$sql = 'concat(firstname, " ", lastname) like ?';
$query->whereRaw($sql, ["%{$search}%"]);
})
->filterColumn('membercode', function($query, $request) {
$search = $request->search;
$sql = 'usercode as membercode like ?';
$query->whereRaw($sql, ["%{$search}%"]);
})
->filterColumn('createddate', function($query, $request) {
$search = $request->date;
$sql = 'created_at as createddate like ?';
$query->whereRaw($sql, ["%{$search}%"]);
})
->filterColumn('sponsorby', function($query, $request) {
$search = $request->search;
$sql = '(select concat(firstname, " ", lastname) from users as b where b.id= users.parentid) like ?';
$query->whereRaw($sql, ["%{$search}%"]);
})
->make(true);
}

Related

Laravel query not getting correct results

When a user types keywords for the search filter, I want to query tags related to posts. If the keyword is "water body" the result of the filter should return posts that have both tags (water and body). My code below shows results that has either of the tags
How do I query to get only collections that contain both tags?
public function searchFilter(Request $request, Post $post){
$terms = explode(" ", $request->input('keyword'));
$posts = $post->newQuery();
$page = (int)$request->input('page', 1);
$perPage = (int)$request->input('perPage', 10);
$keyword = $request->keyword;
if($request->has('keyword')){
$posts->where(function($query) use($keyword) {
$query->Where('name','LIKE', '%'.$keyword.'%')
->orWhereHas('super', function($q) use ($keyword)
{
$q->where('name','LIKE', '%'.$keyword.'%');
})
->orWhereHas('tags', function($q) use ($keyword)
{
$q->where('name','LIKE', '%'.$keyword.'%');
});
});
}
}
You can explode your keywords and then add orWhereHas for each keyword:
//...
$keywords = explode(' ', $request->keyword);
//...
// Then in your query, use foreach to search for each keyword (do the same for each field
foreach ($keywords as $keyword) {
$query->orWhereHas('tags', function($q) use ($keyword) {
$q->where('name','LIKE', '%'.$keyword.'%');
});
}
````

How to group where clauses in Laravel Query Builder correctly

I am running the following query using the search() function below - the problem is I need to group the where clauses - what am I doing wrong?
select `standings`.*, `users`.`name` as `user` from `standings`
left join `users` on `standings`.`user_id` = `users`.`id`
where `users`.`name` like '%bob%' or `users`.`email` like '%bob%'
and `standings`.`tenant_id` = '1'
In my Standings model I have the following search() that performs the WHERE clause
public static function search($query)
{
return empty($query) ? static::query()
: static::where('users.name', 'like', '%'.$query.'%')
->orWhere('users.email', 'like', '%'.$query.'%');
}
public function render()
{
$query = Standing::search($this->search)
->select('standings.*', 'users.name AS user')
->leftJoin('users', 'standings.user_id', '=', 'users.id')
->orderBy('points', 'desc')
->orderBy('goals_difference', 'desc')
->orderBy('goals_for', 'desc');
if($this->super && $this->selectedTenant) {
$query->where('standings.tenant_id', $this->selectedTenant);
}
return view('livewire.show-standings', [
'standings' => $query->paginate($this->perPage)
]);
}
The query works however it doesn't group the WHERE clause correctly on the users.name & users.email fields - how do I change this search() function so the WHERE query has them grouped like this
where (`users`.`name` like '%bob%' or `users`.`email` like '%bob%')`
You need to group the where clauses in a wrapping where clause. Try this
public static function search($query)
{
return empty($query)
? static::query()
: static::where(function($query){
$query->where('users.name', 'like', '%'.$query.'%')
->orWhere('users.email', 'like', '%'.$query.'%');
});
}
Thanks that for some reason even though looks correct gives me the following error - Object of class Illuminate\Database\Eloquent\Builder could not be converted to string NB I am using Laravel with Livewire (not sure if that should make any difference)
$query->where('users.name', 'like', '%'.$query.'%') and ->orWhere('users.email', 'like', '%'.$query.'%'); is giving the error because while trying to compare $query is being treated as a string hence the error
You can define the search as a query scope on the model
//Assuming a relation Standing belongsTo User
//Query constraint to get all Standing records where
//related User record's name or email are like searchTerm
public function scopeSearch($query, string $searchTerm)
{
return $query->whereHas('user', function($query) use($searchTerm){
$query->where('name', 'like', "%{$searchTerm)%")
->orWhere('email', 'like', "%{$searchTerm}%");
});
}
Laravel docs:https://laravel.com/docs/8.x/eloquent#local-scopes
With the above search scope defined on Standing model, you can have the render function as
public function render()
{
$query = Standing::with('user:id,name')
->search($this->search)
->orderBy('points', 'desc')
->orderBy('goals_difference', 'desc')
->orderBy('goals_for', 'desc');
if($this->super && $this->selectedTenant) {
$query->where('tenant_id', $this->selectedTenant);
}
return view('livewire.show-standings', [
'standings' => $query->paginate($this->perPage)
]);
}

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

tojson() does not return all related models

I am working on laravel 5.5 project
i have four tables as following:-
1- Subject model (has following relations)
public function types()
{
return $this->belongsToMany('App\Types');
}
public function areas()
{
return $this->belongsToMany('App\Area');
}
public function articles()
{
return $this->hasMany('App\Article');
}
2- Area and Types has many to many relation with Subject model
public function subjects()
{
return $this->belongsToMany('App\Subjects');
}
3- Article has 1 to many relation with Subject
public function subjects()
{
return $this->belongsTo('App\Subjects');
}
The below controller will search for subject by keyword, select type or area and return value as json using toJson() and return results to view:-
public function search(Request $request)
{
//start search//
$get_Subjects = new Subject();
$get_Subjects = $get_Subjects ->newQuery();
if($request->term != '')
{
$get_Subjects->with('articles')->whereHas('articles', function ($query) use ($request){
$query->where('title', 'LIKE', '% '.$request->term.' %')
->orwhere('abstract', 'LIKE', '% '.$request->term.' %')
->orwhere('fullCitation', 'LIKE', '% '.$request->term.' %');
})
->where(function($query) use ($request){
$query->where('name', 'LIKE', '%'.$request->term.'%');
});
}if($request->area != '28')
{
// search for the selected area
$get_Subjects->with('areas')->whereHas('areas', function($query) use ($request){
$query->where('area_id', $request->area);
});
}
if($request->type!= '36')
{
// search for the selected types
$get_Subjects->with('types')->whereHas('types', function($query) use ($request){
$query->where('type_id', $request->type);
});
}
$subjects = $get_Subjects->tojson();
return View::make('public.search', compact('subjects'));
}
the issue is when i search by keyword the returned json only include related articles, and if i search by area i only get related areas()
while if i did not use json and access variable from blade i can access all related models even though it is the same query
i tried to use load() but it did not work
any help will be valuable
============Update===========
i tried using load() as follow
$subjects= $get_subjects->get();
$subjects= $subjects->load('articles', 'areas', 'types')->tojson();
when search by keyword, the json does have related relations
but they are empty
when search by area or type, the json does have related relation
which mean if i search in the subject table only which is the 1st case i wont get related model with it
please need your help
Have you tried adding the ->get() method before the ->toJson() method?
$subjects = $get_Subjects->get()->toJson();
get() will run the query and return models. toJson() should then work as you expect.
Update
I would write your code like this to start with. (I haven't tested this).
It seems like you are using the whereHas the wrong way. The subject table should have the area_id and type_id fields, so whereHas isn't needed... this might not be the case, but it seems like it should be based on the info you provided.
public function search(Request $request)
{
$get_Subjects = new Subject();
$get_Subjects = $get_Subjects ->newQuery();
$with = [];
if($request->term != '') {
$with[] = 'articles';
$subjects = $get_Subjects->whereHas('articles', function ($query) use ($request){
$query->where('title', 'LIKE', '% '.$request->term.' %')
->orwhere('abstract', 'LIKE', '% '.$request->term.' %')
->orwhere('fullCitation', 'LIKE', '% '.$request->term.' %');
})
->where('name', 'LIKE', '%'.$request->term.'%');
}
if($request->area != '28') {
$with[] = 'areas';
$get_Subjects->where('area_id', $request->area);
}
if($request->type!= '36') {
$with[] = 'types';
$get_Subjects->where('type_id', $request->type);
}
$subjects = $get_Subjects->with($with)->get()->toJson();
return View::make('public.search', compact('subjects'));
}

Like query string in codelgniter

My view page has the following fields
id,name,email,gender etc..
I have a search box , and i want to perform search in all the above fields
How to write the query string in CI way
Controller
public function search()
{
$sql = "SELECT * FROM users";
$this->form_validation->set_rules('search_term', 'Search_term', 'trim|xss_clean');
if ($this->form_validation->run() == TRUE)
{
$keyword = $this->input->post('search_term');
$sql.= "WHERE name like '{$keyword }'";
$sql.= "OR email like '{$keyword }'";
$sql.= "OR gender like '{$keyword }'";
}
$query = mysql_query($sql);
}
read CI Like like query
$keyword = $this->input->post('search_term');
$this->db->select('*');
$this->db->like('name', $keyword);
$this->db->or_like('email', $keyword);
$this->db->or_like('gender', $keyword);
$res = $this->db->get('users');

Resources