Eloquent - Multiple where Clause and orWhere - laravel

I have a little problem to make a query in my laravel application :
I have a table which displays all the customers of my shop.
We are many administrators, and each one have his own shop and his own customers.
The user table has a field 'shop_id' to filter that and the table will only displays the customers who have the same 'shop_id' as the authentified admin.
So I have this query :
$customers = Customer::where('shop_id', Auth::user()->shop_id)->paginate(12);
But we have a lot of customers, so I want to filter those customers. I use a livewire component to make this filter dynamic with a public $search.
So my new query is :
$customers = Customer::where('shop_id', Auth::user()->shop_id)->where('name', 'like', '%' . $this->search . '%')->paginate(12);
Everything's ok if I don't want to add some additionnal filters. But I need to filter by name, by reference_client, and by society name, everything in the same search input.
I thought the next query were correct :
$customers = Customer::where('shop_id', Auth::user()->shop_id)->where('name', 'like', '%' . $this->search . '%')->orWhere('society', 'like', '%' . $this->search . '%')->orWhere('reference', 'like', '%' . $this->search . '%')->paginate(12);
But the orWhere clauses cancel the first where clause (relative to shop_id) : the table displays all the customers, not only the customers who have the good 'shop_id'.
I imagine that I have to combine the 'search' queries in a function, but I have some problem to realize that.
I hope someone could help me, it would be great :)
Thanks in advance

I think I found the solution, a function a the where clause as i thought : $customers = Customer::where('shop_id', Auth::user()->shop_id)->where(function($q) { $query->where('name', 'like', '%'.$this->search.'%')->orWhere('company', 'like', '%'.$this->search.'%')->orWhere('reference', 'like', '%'.$this->search.'%'); })->paginate(12)

Related

Livewire filter with multiple conditions : How to?

I am in trouble with a little functionnality I want to add in my project, sure someone can help me :)
The stack is Laravel with Livewire to add easily some interactivity.
I have a table with a list of bills. I use Livewire pagination in this table, and I have a search field to dynamically filter those bills.
There's no problem for a simple filter, for example by bill numerotation, or by date, or both... using where and orWhere clauses.
I have an additionnal filter, activated by a button, which filters bills by "paid or not".
For this case, my Livewire Controller should look like this :
public function render()
{
return view('livewire.bills.index', [
'bills' => Bill::where('numero', 'like', '%'.$this->search.'%') // string modified by search input
->orWhere('created_at', 'like', '%'.$this->search.'%') // string modified by search input
->where('paid', $this->paid) // bool switched by click on a button
->paginate(12),
]);
}
In addition, I want to allow filter by customer name. Of course, Bill Model and Customer Model are relationned in a One-To-many Relationship :
-- Bill --
-id
-numero (string)
-customer_id (foreign)
-paid (bool)
-price(int)
-created_at (datetime)
-- Customer --
-id
-name (string)
To allow filter by customer name and 'paid or not', i use whereHas clause in addition to the where clause :
'bills' => Bill::whereHas('customer', function($query) {
return $query->where('name', 'like', '%'.$this->search.'%');
})
->where('paid', $this->paid)
->paginate(12),
Everything's ok. But I can't add the third filter (filter by created_at) in addition of those 2 filters.
I tried this :
return view('livewire.devis.index', [
'bills' => Bill::whereHas('customer', function($query) {
return $query->where('name', 'like', '%' . $this->search . '%');
})
->orWhere('created_at', 'like', '%' . $this->search . '%')
->where('paid', $this->paid)
->paginate(12),
]);
It works for filtering by customer name or by date (search field), but the 'paid or not' filter doesn't work anymore.
Anyone can help me to understant where my query is failing please.
Thanks to everybody who's watching this and maybe could give me a hand

Search with multiple tables

I have 3 tables that are connected/have relation.
Posts table have many tag and one Category
Category table have many Posts
Tag table have many Posts
i want a search feature, i know how to search only use Posts (based on title).
I tried to search each tables with Where in my controller but still no luck.
public function Search(Request $request)
{
$search = $request->search;
$posts = post::where('title', 'like', "%{$search}%")->paginate(5);
return view('search', compact('posts'))->with('result', $search);
}
For example
i have a post Titled 'Test' and with Category 'Tost' and with Tags 'Tast and Tust'
so if i type either the title, category or tags i want it to show up. how can i achieve it?
Try use whereHas method (for further info check https://laravel.com/docs/5.8/eloquent-relationships#querying-relations)
So would become something like:
Post::query()
->where('title', 'like', "%$search%")
->orWhereHas('categories', function ($query) use ($search) {
$query->where('name', 'like', "%$search%");
})
You must use like this.
Post::where('title', 'like', '%' . Input::get('search') . '%')->get();

Laravel: searching related data

I have models: Student, Tutor, Country.
Main model is Student with code:
public function studentTutors()
{
return $this->morphedByMany(Tutor::class, 'studentable')
->with('tutorAddresses');
}
Then relations.
Tutor:
public function tutorAddresses()
{
return $this->hasMany(TutorAddress::class, 'tutor_id', 'id')
->with('tutorCountry');
}
TutorAddress:
public function tutorCountry()
{
return $this->hasOne(Country::class, 'country_id', 'country_id')
->where('user_lang', 'en');
}
How do I use it:
$paginator = $student->studentFavouriteTutors()
->getQuery() //for paginate
->where(function ($query) use ($searchPhraze) {
if (strlen(trim($searchPhraze))) {
return $query
->where('username', 'like', '%' . $searchPhraze . '%')
->orWhere('firstname', 'like', '%' . $searchPhraze . '%')
->orWhere('lastname', 'like', '%' . $searchPhraze . '%');
}
})
->paginate($pages, $columns, $pageName, $page);
Question:
I am searching in tutors table (Tutor) for user/first/last names.
Is there are way to search for country name from countries table (Country: tutorCountry)? Lets say, table has 'name' column with country names.
If yes, how should $paginator code look like, to get data from countries table?
Same question goes for relation tutorAddresses. Lets say, table has 'city' column with city names.
Is this possible?
Now, I do not use relations for search, and just do joins.
BTW: I tried hasManyThrough relation, but it does not seem to pass data from that 'through' table, so this is not going to work for me. Also, my 'through' relations go a bit too deep for it (unless I do not understand something as far as this relation is concerned).
EDIT:
Answer by jedrzej.kurylo is perfect!
I just want to add, for all these, who look for a way to search within relation of a relation, like in my case:
studentTutors / tutorAddresses / tutorCountry
... where within model Student, I also want to look for country name inside of Country model, that is deeper in chain of relations and is not directly related to Tutor, but to TutorAddress, which is related to Tutor.
It is just a question of nesting queries:
$searchPhraze = 'France';
$res = $student->studentFavouriteTutors()
//first relation level
->whereHas('tutorAddresses', function($query) use ($searchPhraze) {
//deeper relation
$query->whereHas('tutorCountry', function($query) use ($searchPhraze) {
$query->where('country', 'like', '%' . $searchPhraze . '%');
});
})->get();
Or you can even combine of searches of parent and child relations:
$searchPhraze = 'Hodkiewiczville';
$res = $student->studentFavouriteTutors()
//first relation level
->whereHas('tutorAddresses', function($query) use ($searchPhraze) {
$query
//first level relation search
->where('city', 'like', '%' . $searchPhraze . '%')
//deeper relation
->orWhereHas('tutorCountry', function($query) use ($searchPhraze) {
$query->where('country_label', 'like', '%' . $searchPhraze . '%'));
});
})->get();
Above code found related datasets as expected.
Thou, I am not sure as to benchmark of this.
You can search data in related tables using whereHas() function, e.g.:
$student->studentFavouriteTutors()
->whereHas('tutorAddresses', function($query) use ($searchPhraze) {
$query->where('city', 'like', '%' . $searchPhraze . '%');
})->get();
This will get you all student's favourite tutors that have an address where city column contains given phrase.

How do I query a relation database in Laravel?

I have this search query for Post model in Laravel:
return $q ->where('title', 'like', '%'.$keyword.'%')
Which works totally fine. In my Post model I also have a relation database categories. This is available as an object in my returned post object.
Is there a way I can query the category -> name?
I have tried:
return $q ->where('category->name', 'like', '%'.$keyword.'%')
I believe what you are looking for can be found here: https://laravel.com/docs/5.6/eloquent-relationships#querying-relations
For your use case you need to make sure you have the relationship established in your Post model. If that is set your query should look similar to the following:
return $q->where('title', 'like', '%'.$keyword.'%')->whereHas('category',
function ($query) use ($keyword) {
$query->where('name', 'like', '%'.$keyword.'%');
})->get();
Hope this helps!
If you're db is well structured - then will want to use Laravel's ORM for this stuff.
https://laravel.com/docs/5.6/eloquent#introduction
I assume that you have Models:
Post
Category
Also that you have category_id as a foreign key in Post model.
This is basic structure.
I assume that you want to search Posts and Categories same time so you can do something like this:
return Post::leftJoin('categories', 'posts.category_id', '=', 'categories.id)
->where('categories.name', 'like', '%' . $keyword . '%')
->orWhere('posts.title', 'like', '%' . $keyword . '%')
->get();

Laravel pagination not working with closure

I am trying to implement search functionality using Laravel. Here is my method that should return results of search:
$keyword = request('q');
$posts = Post::where('deleted', false)
->where(function($q) use($keyword) {
$q->where('title', 'like', '%' . $keyword . '%')
->orWhere('body', 'like', '%' . $keyword . '%');
})
->latest()
->paginate(5);
The problem is when I search for something that has more than 5 results it shows first 5 results and 2(for example) pages in links, but then when I click on the second page there are somehow 3 pages in links and some of the posts are repeated. I am guessing that closure is causing this problem but I don't know how to fix it.
Any advice is welcome, thanks! :)
Since you're using data from the request, you need to append it to be able to use in the next request:
{{ $posts->appends(['q' => request('q')])->links() }}
From the docs:
You may append to the query string of pagination links using the appends method.

Resources