Laravel Eloquent Many to Many Query - laravel

Please help me make this query in eloquent. A business can have many categories.
SELECT b.*
FROM businesses b
INNER JOIN categorybusiness cb
ON b.id = cb.business_id
INNER JOIN category c
ON cb.category_id = c.id
WHERE b.location LIKE '%query1%'
AND b.location LIKE '%query2%'
AND c.name LIKE '%query3%'
AND c.name LIKE '%query4%'
my tables are.. businesses - contain the location column and a pivot table for category and business..
UPDATE:
so i used this query...
$business5 = Business::WhereHas('categories', function($q) use($category,$query1)
{
$q->whereRaw("name like '%$category%' or businesses.name like '%$category%' $query1");
})->get();
$query1 looks like this but in a loop.
$query1 .= " and businesses.address1 like '%$string%'";
It's working fine but can someone help me make a "MATCH AGAINST" statement in eloquent from this.

For making an Eloquent query you need to setup relationship and to create a many-to-many relationship you need to build the relationship like this in both models:
The Business model:
class Business extends Eloquent {
//...
public function categories()
{
return $this->belongsToMany('Caregory');
}
}
The Category model:
class Category extends Eloquent {
//...
public function businesses()
{
return $this->belongsToMany('Business');
}
}
The Eloquent query (You already have a pivot table):
$businesses = Business::with(array('categories' => function($q) use ($query3, $query4) {
$q->where('categories.name', 'LIKE', '%'. $query3 .'%')
->where('categories.name', 'LIKE', '%'. $query4 .'%');
}))->where('businesses.location', 'like', '%'. $query1 .'%')
->where('businesses.location', 'like', '%'. $query2 .'%')
->get();
To check the result just use dd($businesses); and examine the collection so you'll get the idea about how you can loop them in your view. Basically, $businesses will contain a collection and each $business model in the collection will contain another collection of $categories, so loop could be something like this:
#foreach($businesses as $business)
{{ $business->propertyname }}
#foreach($business->categories as $category)
{{ $category->propertyname }}
#endforeach
#endforeach

Assuming you have Business moel setup, this is exactly the query you wanted, as eager loading suggested by #WereWolf won't do the job here (where clauses on joined tables vs on 2 separate queries):
Business::from('businesses as b')
->join('categorybusiness as cb', 'b.id', '=', 'cb.business_id')
->join('category as c', 'c.id', '=', 'cb.category_id')
->where('b.location', 'like', "%$query1%")
->where('b.location', 'like', "%$query2%")
->where('c.name', 'like', "%$query3%")
->where('c.name', 'like', "%$query4%")
->get(['b.*']);
There is also another way using whereHas method as long as you have belongsToMany relations setup correctly
Business::whereHas('categories', function ($q) use ($query3, $query4) {
$q->where('categories.name', 'like', "%$query3%")
->where('categories.name', 'like', "%$query4%");
})->where('businesses.location', 'like', "%$query1%")
->where('businesses.location', 'like', "%$query2%")
->get();

Related

Laravel how to Order by relation in scope?

I have the following scope in User model
$query->with('country')
->when($filters['search'] ?? null, function ($query, $search) {
return $query->where('name', 'LIKE', '%' . $search . '%')
->orWhereHas('country', function ($query) use ($search) {
$query->where('name', 'LIKE', '%' . $search . '%');
});
});
$query->orderBy('name', 'asc');
}
return $query;
}
I am pretty new to Laravel - I currently the above query is sorting by user name but I would like to sort by country name. I can do this with country_id as there is a relation but not sure how to sort by country name.
Thanks
there are two approaches we can use to order these users by their company. The first is using a join:
$users = User::select('users.*')
->join('countries', 'countries.id', '=', 'users.country_id')
->orderBy('companies.name')
->get();
Here is the generated SQL for this query:
select users.*
from users
inner join countries on countries.id = users.country_id
order by countries.name asc
The second way is using a subquery:
$users = User::orderBy(Country::select('name')
->whereColumn('countries.id', 'users.country_id')
)->get();
And you can see the reference here: ordering database queries by relationship columns in laravel

Laravel Query Through Relationship

I am creating a search in laravel where customers can search for vehicles.
Table 1
Vehicle
VIN
PLATE
make_and_model_id
Table 2
Vehicle Makes and Models
id
make
model
Relationship in Table 1: Vehicle
public function vehicle_make_and_model_fk()
{
return $this->belongsTo('App\Models\VehicleMakeAndModel', 'vehicle_make_and_model_id');
}
So I am searching for VIN or Plate. That works fine.
I also am Searching for a Make and Model name which is a foreign key.
I pulled in the related table using with which works fine.
Now how to search through the columns of Make and Model Table?
if($request->ajax()) {
$search = $request->search_query;
$vehicles = Vehicle::with('vehicle_make_and_model_fk')
->where(function ($query) use ($search) {
$query->where('plate', 'LIKE', '%'.$search.'%')
->orWhere('vin', 'LIKE', '%'.$search.'%')
->orWhere('vehicle_make_and_models.make', 'LIKE', '%'.$search.'%');
})
->limit(5)
->get();
echo json_encode($vehicles);
exit;
}
To filter the relationship, you need to use a closure in your with()
For example:
$vehicles = Vehicle::query()
->with([
'vehicle_make_and_model_fk' => function ($query) use ($search) {
$query->where('make', 'like', "%$search%")
->orWhere('model', 'like', "%$search%");
}
])
->where(function ($query) use ($search) {
$query->where('plate', 'like', "%$search%")
->orWhere('vin', 'like', "%$search%");
})
->limit(5)
->get();
Eloquent Relationships - Constraining Eager Loads
$vehicles = Vehicle::where('plate','LIKE','%'.$search.'%')
->orWhere('vin','LIKE','%'.$search.'%')
->with('vehicle_make_and_model_fk')
->orwhereHas('vehicle_make_and_model_fk',
function($query) use($search){
$query
->where('vehicle_make_and_models.make','like',$search.'%')
->orWhere('vehicle_make_and_models.model','LIKE','%'.$search.'%');
}
)
->limit(5)
->get();
This query worked. It would search and bring results from vehicle table and would go to makes and models table and bring results from there as well. Based on - Laravel Eloquent search inside related table

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

Sort a result of search in Laravel Eloquent model with relations

I did a search for a Model (Startup), next step is to order results of the search by DESC or ASC (it doesn't matter now)
My current code is:
$startups = Startup::whereHas('category', function ($query) use ($search, $sort_type) {
$query
->where('name', 'like', "%$search%")
->orderBy('name', $sort_type);
})
->orWhere('description', 'LIKE', "%$search%")
->orWhere('url', 'LIKE', "%$search%")
->get();
return StartupResource::collection($startups);
Explanation of the code:
as you see at the beginning I'm using "whereHas" to search also for coincidences in related model - "Category".
then inside of "whereHas" I'm trying to apply 'orderBy('name', $sort_type)' but it doesn't work properly (it doesn't sort by categories)
I know that we can create method in Startup model and sort it inside of the method, but the problem is that I have to pass variables to the method ( $sort_type, $search) and I don't know how to do this
So how to sort Startups model including related Category model by ASC or DESC in my case ?
Thank you guys a lot for any ideas and help!
That's not possible with whereHas(). You can use a JOIN:
$startups = Startup::select('startups.*')
->join('category', 'category.id', '=', 'startups.category_id')
->where('category.name', 'LIKE', "%$search%")
->orWhere('startups.description', 'LIKE', "%$search%")
->orWhere('startups.url', 'LIKE', "%$search%")
->orderBy('category.name', $sort_type)
->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.

Resources