Laravel 5.6 search forms - php

In an app I'm working on there are two main searches: a site wide search and a quick search.
Quick search
The quick search has to take the role, user and department and return all the users that match the criteria. I already see a potential problem in the fact that you could select a role that isn't in a department... but anyway.
This is what I've tried.
public function userSearch(Request $request)
{
$department = $request->get('department');
$role = $request->get('role');
$location = $request->get('location');
$users = User::where('department', $department)
->where('role', $role)
->where('location', $location)
->get();
foreach($users as $user)
{
echo '<br />' . $user->username;
}
}
It gets complicated though as user, role and department are drop down boxes and may not have had anything selected.
So If I search for just Digital as a department the query string is:
http://127.0.0.1:8000/usersearch?department=Digital&role=&location=
Obviously, this doesn't return anything as I'm using multiple where clauses.
Would I have to individually check whether each variable is empty and construct the query? This seems a bit sketchy as I'd have to check every possible order to get the query right.
Site wide search
The other search is a site search that takes one query string, here is my stupidly basic method startings:
public function search(Request $request)
{
$search = $request->get('q');
return view('pages.search.index', compact('search'));
}
I read in the Laravel documentation that there is a package available called Scout but is there a more rudimentary way to just get everything from every model, given the query string?
Things I'd like to return:
Users
Teams
Documents with similar titles
News articles
I have models associated to database tables for all the above so could I just do the following?
users = User::where('name', 'like', '%' . Input::get('name') . '%')
->orWhere('name', 'like', '%' . Input::get('name') . '%')
articles= Article::where('name', 'like', '%' . Input::get('name') . '%')
->orWhere('name', 'like', '%' . Input::get('name') . '%')
and so on...
Then when displaying results just do:
return('nameofview', compact('users', 'articles')
Or is this likely to be slow and cumbersome?
Update
For the site-wide search, for now, I just have:
public function search(Request $request)
{
$search = $request->get('q');
$users = User::where('username', 'like', '%' . $request->get('q') . '%')
->orWhere('displayName', 'like', '%' . $request->get('q') . '%')
->orWhere('email', 'like', '%' . $request->get('q') . '%')
->orWhere('role', 'like', '%' . $request->get('q') . '%')
->orWhere('department', 'like', '%' . $request->get('q') . '%')
->orWhere('location', 'like', '%' . $request->get('q') . '%')
->orWhere('directDialIn', 'like', '%' . $request->get('q') . '%')
->orWhere('mobileNumber', 'like', '%' . $request->get('q') . '%')->get();
return view('pages.search.index', compact('search', 'users'));
}
For the quick search, I added some query scopes
/**
* Scope a query by department
*/
public function scopeByDepartment($query, $department)
{
return $query->where('department', $department);
}
/**
* Scope a query by role
*/
public function scopeByRole($query, $role)
{
return $query->where('role', $role);
}
/**
* Scope a query by location
*/
public function scopeByLocation($query, $location)
{
return $query->where('location', $location);
}

There is a much better way to achieve what you are looking to do using a combination of conditional clauses and scopes. For example...
User::all()->when(isset($request->department), function ($q) use ($request) {
$q->byDepartment($request->department);
})
->when(isset($request->role), function($q) use ($request) {
$q->byRole($request->role);
});
Once you set up your scopes on the model you can now selectively filter by any number of the request variables so you don't have to worry if it is not set. This also keeps your code much more compact.

Related

Laravel Query Builder Join vs With Function, Which One is Better?

I want to ask about Laravel Query using Join or With which is better.
In this case there is a short query that I have tried. But there are some things that make me wonder.
In my case, I'm trying to create a list of users using the API. The problem lies in sorting the data.
The problem is divided into several.
If I use With.
The advantage of using with is that I can call the attributes in the model without rewriting the attributes I want to use. But I was confused when calling data related to other tables for me to sort. example query:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$sortBy = $request->query('sortBy');
$sortDesc = (is_null($request->query('sortDesc'))) ? $request->query('sortDesc') : ($request->query('sortDesc') == 'true' ? 'desc' : 'asc');
$page = $request->query('page');
$itemsPerPage = $request->query('itemsPerPage');
$search = $request->query('search');
$starDate = $request->query('start');
$endDate = $request->query('end');
$start = ($page - 1) * $itemsPerPage;
$query = MemberRegular::query();
$query->with(['users' => function ($subQuery) {
$subQuery->select('id', 'name', 'email', 'phone');
}]);
$query->select(
'id',
'code'
);
if ($search) {
$query->where(function ($subQuery) use ($search) {
$subQuery->where('code', 'like', '%' . $search . '%');
$subQuery->orWhere(function ($q) use ($search) {
$q->whereHas('users', function ($j) use ($search) {
$j->where('name', 'like', '%' . $search . '%');
$j->orWhere('email', 'like', '%' . $search . '%');
})
});
});
}
if ($sortBy && $sortDesc) {
$query->orderBy($sortBy, $sortDesc)->orderBy('id', 'desc');
} else {
$query->orderBy('created_at', 'desc')->orderBy('id', 'desc');
}
if ($starDate && $endDate) {
$query->whereBetween('created_at', [$starDate, $endDate]);
}
$data['totalItems'] = $query->count();
$data['items'] = $query->skip($start)->take($itemsPerPage)->get();
return HResource::collection($data['items'])->additional(['totalItems' => (int) $data['totalItems']], true);
}
If I use Join.
The advantage of using Join is that I can sort data easily if the data is related to other tables. But I have to re-create a new attribute in a collection. example query:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$sortBy = $request->query('sortBy');
$sortDesc = (is_null($request->query('sortDesc'))) ? $request->query('sortDesc') : ($request->query('sortDesc') == 'true' ? 'desc' : 'asc');
$page = $request->query('page');
$itemsPerPage = $request->query('itemsPerPage');
$search = $request->query('search');
$starDate = $request->query('start');
$endDate = $request->query('end');
$start = ($page - 1) * $itemsPerPage;
$query = MemberRegular::query();
$query->join('users', 'users.id', '=', 'member_regulars.user_id');
$query->select(
'member_regulars.id',
'member_regulars.code',
'users.name',
'users.email',
'users.phone'
);
if ($search) {
$query->where(function ($subQuery) use ($search) {
$subQuery->where('member_regulars.code', 'like', '%' . $search . '%');
$subQuery->orWhere('users.name', 'ilike', '%' . $search . '%');
$subQuery->orWhere('users.email', 'ilike', '%' . $search . '%');
$subQuery->orWhere('users.phone', 'ilike', '%' . $search . '%');
});
}
if ($sortBy && $sortDesc) {
$query->orderBy($sortBy, $sortDesc)->orderBy('member_regulars.id', 'desc');
} else {
$query->orderBy('member_regulars.created_at', 'desc')->orderBy('member_regulars.id', 'desc');
}
if ($starDate && $endDate) {
$query->whereBetween('member_regulars.created_at', [$starDate, $endDate]);
}
$data['totalItems'] = $query->count();
$data['items'] = $query->skip($start)->take($itemsPerPage)->get();
return HResource::collection($data['items'])->additional(['totalItems' => (int) $data['totalItems']], true);
}
If using Query With The problem lies in sending the sortBy parameter like the following users.name it will be an error because the table is not found in the query I made, but I can immediately call attributes that can be used directly without needing to create a new custom attribute.
If using Query Join, the problem is that I have to re-create custom attributes to be used in data collections, but I don't need to worry about sorting data.
Both are equally important to me. However, if anyone is willing to give advice on the best way I have to use Join or With for this case.
Thank you.
Finally I found the best solution to the problem I was facing. I hope this can help others.
Here I choose to use Join why? because it turns out that I can call the function relations users() in the model that I created so that I can still retrieve custom attributes in the Users model. I don't really know if this is the right way or not. I hope this helps others.
Thank you.

how to prevent specific word to search result laravel

I need to prevent some specific searches like a username.
the scenario is when I search auth username I get all friends but if I search auth username I don't want to search result,
here's my query
$searchVal = $request->input('search');
$friend_data = Friend::with('getAccept', 'getRequest')->where('status', '1')->where(static function ($q) use ($user) {
$q->where('user_id', $user->id)->orWhere('ref_id', $user->id);
})->where(function ($q1) use ($searchVal) {
if($searchVal) {
$q1->whereHas('getRequest', function ($q) use ($searchVal) {
$q->where('username', 'LIKE', '%' . $searchVal . '%');
});
$q1->orWhereHas('getAccept', function ($q) use ($searchVal) {
$q->where('username', 'LIKE', '%' . $searchVal . '%');
});
}
})->get();
Thanks in Advance.
Just replace if($searchVal) in your where function with if($searchVal !== Auth::user()->username) and that should exclude the auth username results.

Laravel 6: redirect with variables AND message - not working

i am trying to redirect using a function in my main controller with both variables and a message.
The message code is fine and is usually displayed by ->with('abo', 'messagetext').
The Problem is that not both types are redirected, only the variables (without the message) :(
The goal is to redirect the following variables: suchString, userId, suche
public function subscribe(Request $request)
{
$suchString = $request->input('suchString');
$userId = $request->input('userId');
Subscribe::create([
'abo_string' => $suchString,
'userid' => $userId
]);
$suche = Document::where( 'title', 'LIKE', '%' . $suchString . '%' )
->orWhere( 'category', 'LIKE', '%' . $suchString . '%' )
->orWhere( 'description', 'LIKE', '%' . $suchString . '%' )
->get();
$users = User::all();
return view('pages.search')->with('abo', 'messagetext');
}
You should try the compact() method to redirect your variable.
session()->flash( 'abo', 'Your message' );
return view('pages.search', compact('suchString', 'userId', 'suche' ));
You are returning a view() not a redirect()
And you can also chain with() as much as you like.
return redirect()->route('pages.search')
->with('abo', 'messagetext')
->with('suche', $suche)
->with('userId', $userId)
->with('suchString', $suchString);
Is likely what you want.
These will all be in the session on your next page view.

Eloquent where clause for timestamp in Laravel 5.1

I have a table and search bar.
When user input in the search that when I grab that and query my database.
This is what I got
public function getLogsFromDb($q = null) {
if (Input::get('q') != '') {
$q = Input::get('q');
}
$perPage = 25;
if ($q != '') {
$logs = DB::table('fortinet_logs')
->orWhere('account_id', 'like', '%'.$q.'%')
->orWhere('cpe_mac', 'like', '%'.$q.'%')
->orWhere('p_hns_id', 'like', '%'.$q.'%')
->orWhere('g_hns_id', 'like', '%'.$q.'%')
->orWhere('data', 'like', '%'.$q.'%')
->orWhere('created_at', 'like', '%'.$q.'%') <----🐞
->orderBy('updated_at', 'desc')->paginate($perPage)
->setPath('');
//dd($logs);
$logs->appends(['q' => $q]);
} else {
$logs = DB::table('fortinet_logs')
->orderBy('created_at', 'desc')->paginate($perPage)
->setPath('');
}
return view('telenet.views.wizard.logTable', get_defined_vars());
}
Result
In the network tab, I kept getting
Undefined function: 7 ERROR: operator does not exist: timestamp without time zone ~~ unknown
How would one go about debugging this further?
PostgreSQL is strict about different data types. Convert the timestamp column to text:
->orWhereRaw('created_at::text like ?', ['%'.$q.'%'])
sanitize your inputs to avoid such problems
$remove = array("'","!",";","+",'|','||',"&&","}","{","[","]");
$replace = array("","","","","","","","","","","");
$q = str_replace($remove, $replace, $q);
Use the new defined $q in your queris
first step on debuggin to make an sql by tihs. And you look what is the problem for your query.
Like this:
dd($logs = DB::table('fortinet_logs')
->orWhere('account_id', 'like', '%'.$q.'%')
->orWhere('cpe_mac', 'like', '%'.$q.'%')
->orWhere('p_hns_id', 'like', '%'.$q.'%')
->orWhere('g_hns_id', 'like', '%'.$q.'%')
->orWhere('data', 'like', '%'.$q.'%')
->orWhere('created_at', 'like', '%'.$q.'%')//This is the cri
->orderBy('updated_at', 'desc')->toSql());
This is show for you whats the problem of this query.
By the way, can you cast $q to daterange and can find in this range the logs.

Laravel - AJAX Search allow Multiple Filters to be applied

I have a controller that works on an AJAX jQuery call when I need to search/filter the database:
$launchsitesatellite = DB::table('satellites')
->where(function($q) use ($request) {
if(empty($request->type) && empty($request->rocket_type)) {
$q->orWhere('satname','LIKE','%'.$request->search.'%')
->orWhere('norad_cat_id','LIKE','%'.$request->search.'%')
->orWhere('country','LIKE','%'.$request->search.'%')
->orWhere('object_id','LIKE','%'.$request->search.'%');
} else {
if(!empty($request->type)) {
$q->orWhere($request->type,'LIKE','%'.$request->search.'%');
}
if(!empty($request->object_type)) {
$q->orWhere('object_type','LIKE','%'.$request->object_type.'%');
}
if(!empty($request->launch_year)) {
$q->orWhere('launch','LIKE','%'.$request->launch_year.'%');
}
}
})
->where('site', $site_code)->Paginate(300);
This controller can search/filter my database with no problem. The only thing I would like to fix is to allow multiple filters to be applied. For example, currently when I filter by Object Type and then decide to filter by Country, it resets the Object Type.
What I want to be able to do is to allow it to filter by Object Type AND Country, not only one.
There was a lack of examples/documentation so I could not find any examples of how this is done.
EDIT: JS AJAX Call
$("#filter-type").change(function() {
$value=$(this).val();
$.ajax({
type: "get",
url: "{{$launchsitename->site_code}}",
data: {'search':$value, type:'object_type'},
success: function(data){
$('#launchsatdisplay').html(data);
}
});
});
I think the reason you're having this issue is because you're using orWhere rather than where so in theory the more filters you use the more results you will have returned (rather than limiting the results).
$launchsitesatellite = DB::table('satellites')
->where(function ($q) use ($request) {
if (!$request->has('type') && !$request->has('rocket_type')) {
$q->orWhere('satname', 'LIKE', '%' . $request->search . '%')
->orWhere('norad_cat_id', 'LIKE', '%' . $request->search . '%')
->orWhere('country', 'LIKE', '%' . $request->search . '%')
->orWhere('object_id', 'LIKE', '%' . $request->search . '%');
} else {
if ($request->has('type')) {
$q->where($request->type, 'LIKE', '%' . $request->search . '%');
}
if ($request->has('object_type')) {
$q->where('object_type', 'LIKE', '%' . $request->object_type . '%');
}
if ($request->has('launch_year')) {
$q->where('launch', 'LIKE', '%' . $request->launch_year . '%');
}
}
})
->where('site', $site_code)
->Paginate(300);
Also, just FYI, Laravel Query Builder comes with a when() method which is an alternative to using multiple if statements. So the main else section would look like:
$q
->when($request->has('type'), function ($q) use ($request) {
$q->where($request->type, 'LIKE', '%' . $request->search . '%');
})
->when($request->has('object_type'), function ($q) use ($request) {
$q->where('object_type', 'LIKE', '%' . $request->object_type . '%');
})
->when($request->has('launch_year'), function ($q) use ($request) {
$q->where('launch', 'LIKE', '%' . $request->launch_year . '%');
});
Obviously, you don't have to do this though (I just thought I'd mention it).
Hope this helps!

Categories