query search LIKE use keywords where and left join LARAVEL 5 - laravel

I want to find a data from two tables based on the name contained in the users, but I am having problems.
This is the users table containing the id, and name.
This is the student table that contains the id, and user_id.
Where user_id student = id users.
public function search(Request $request)
{
$keywords = trim($request->input('keywords'));
if (!empty($keywords)) {
$id_class = $request->input('id_class');
//Query
$query = User()
->leftjoin('student', 'users.id', '=', 'student.user_id')
->where('users.name', 'LIKE', '%' . $keywords . '%');
(!empty($id_class)) ? $query->Kelas($id_class) : '';
$data_student = $query->paginate(10);
//URL link pagination
$pagination = (!empty($id_class)) ? $pagination = $data_student->appends(['id_class' => $id_class]) : '';
$pagination = $data_student->appends(['keywords' => $keywords]);
$amount_data = $=data_student->total();
return view('student.index', compact('data_student', 'keywords', 'pagination', 'amount_data', 'id_class'));
}
return redirect('student');
}
Call to undefined function App\Http\Controllers\User()

As mentioned previously you need to correctly refer to the User class with namespace, you also need to change thew following:
$query = User()
->leftjoin('student', 'users.id', '=', 'student.user_id')
->where('users.name', 'LIKE', '%' . $keywords . '%');
to:
$query = User::leftjoin('student', 'users.id', '=', 'student.user_id')
->where('users.name', 'LIKE', '%' . $keywords . '%');
You must call the first method on the class as static with ::.
Also another potential typo you join the table student should it be plural; students?

Related

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 search an item by category and location in laravel simultaneously

The items have category_id and location_id which has relation to tables category and location.
The search form has 3 fields, 1 item keyword, 2nd is the category selection and 3rd is its location.
The user has to fill all the fields in order to be able to search.
The problem is that the search works only for the first input field and brings all the items with the same name but location and categories are not filtered during search...
public function search(Request $request) {
$query = $request->input('query');
$cQuery = $request->input('subCategoryId');
$pQuery = $request->input('province');
$subCategories = Business::where('name', 'like', "%$query%")
->where('province_id', 'like', "%$pQuery%")
->where('sub_category_id', 'like', "%$cQuery%")->get();
return view('pages.search-result')
->with('subCategories', $subCategories);
}
I have assumed that you have the relations setup for all the models. If not, please go through Defining Relationships.
Consider the below answer as a skeleton example for what you are looking for.
$businesses = Business::where('name', 'like', '%' . $query . '%')
->with('province', 'subCategory')
->whereHas('province', function ($q) use ($pQuery) {
$q->where('name', 'like', '%' . $pQuery . '%');
})
->whereHas('subCategory', function ($q) use ($cQuery) {
$q->where('name', 'like', '%' . $cQuery . '%');
})
->get();

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

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

Eloquent Model ID missmatch from join

I have the following database schema:
Person 1 - 1 Contact 1 - * Address
There is also another entity that is a contact, therefore the table contact is necessary.
I access a list of persons like this:
$persons = Person::with('contact.addresses')
->filter($string)
->withoutCompany()
->orderBy('persons.surname', 'ASC')
->get();
The problem is that the eloquent model that is returned overwrites the id field of person with the id of the table contact. This is due to the query scope filter($string) which can be seen below:
public function scopeFilter($query, $parameter) {
return $query
->join('contacts', 'persons.contact_id', '=', 'contacts.id')
->join('addresses', 'addresses.contact_id', '=', 'contacts.id')
->where(function($q) use($parameter) {
$q->where('addresses.city', 'like', $parameter)
->orWhere('persons.surname', 'like', '%' . $parameter . '%')
->orWhere('persons.name', 'like', '%' . $parameter . '%')
->orWhere('addresses.postcode', 'like', $parameter . '%');
});
}
public function scopeWithoutCompany($query) {
return $query->whereRaw('persons.id not in (select company_person.person_id from company_person)');
}
This problem is already addressed here
It states that a select statement should be used, because if the same column name is selected several times, the last one will overwrite the precedents when using joins to fill an eloquent model.
But when I use a select statement in a query scope, e.g. selecting only persons.* and addresses.* - I get an Cardinality violation: 1241 Operand should contain 23 column(s) error from another model where I use the scope in an eager loading constraint (Person and Address together have 23 columns).
I fixed this problem by an ugly workaround, joining again on the Persons table as a last join to overwrite the id with the person id. But this can't be the solution to my problem. Has anyone any idea how I can solve this?
This is the workaround from my Person::filter($string) query scope:
return $query
->select(array('persons.*', 'addresses.*'))
->join('contacts', 'persons.contact_id', '=', 'contacts.id')
->join('addresses', 'addresses.contact_id', '=', 'contacts.id')
->join('persons as p', 'p.id', '=', 'persons.id')
->where(function($q) use($parameter) {
$q->where('addresses.city', 'like', $parameter)
->orWhere('persons.surname', 'like', '%' . $parameter . '%')
->orWhere('persons.name', 'like', '%' . $parameter . '%')
->orWhere('addresses.postcode', 'like', $parameter . '%');
});
For reference:
This is the code that results in the cardinality violation error (database sehcma is Company * - * Person):
$companies = Company::with(array('persons' => function($q) use ($string)
{
$q->filter($string);
})
)->whereHas('persons', function($q) use ($string)
{
$q->filter($string);
})
->orderBy('name', 'ASC')
->get();
Thanks to user Kindari at Laravel.io I have a solution now.
I am not directly putting a condition on my address table, but I have the where clauses in a query scope within my Address model.
Within my Persn model in the query scope, I first retrieve all relevant addresses. I put the IDs in a list and restrict my Persons to only those that live at the addresses. With that I have one more query but have no join at all. See the solution below
public function scopeFilter($query, $parameter) {
$contact_ids = Address::filter($parameter)->lists('contact_id');
$query->with('contact')
->where(function($q) use ($parameter, $contact_ids) {
$q->where('persons.surname', 'like', '%' . $parameter . '%')
->orWhere('persons.name', 'like', '%' . $parameter . '%');
if($contact_ids) {
$q->orWhereIn('contact_id', $contact_ids);
}
});
return $query;
}
This part
$q->where('addresses.city', 'like', $parameter)
->orWhere('addresses.postcode', 'like', $parameter . '%');
is now part of the query scope of the Address model.
Nicely encapsulated. I don't know why I did not think about that one. I was somehow focusing on putting it all in one query. This solves my problem.

Resources