Multilevel relationship whereHas on eloquent Model in Laravel - laravel

I'd like to find
Project::with('tasks.tags')->get();
where only projects with a particular id of tag return in the result set.
For ex. I'd like to find a project with tasks and tasks with tags with only id of 1. In other words, filter the tasks return inside of the Project - Task relationship.
I have tried various ways but have failed so far.
I have tried:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('id', 1);
});
})->get();
And:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
})->get();
This is how the relationships are setup:
In Project.php
public function tasks()
{
return $this->hasMany(Task::class, 'project_id')->setEagerLoads([]);
}
In Task.php
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable')->setEagerLoads([]);
}
Note that relationship between Task and Tags is of morphToMany.
Any pointers?

You would need to scope the eager loading as well. Something like the following should work:
$project = Project::with(['tasks.tags' => function ($query) {
$query->where('id', 1);
}])->whereHas('tasks', function ($query) {
$query->whereHas('tags', function ($query) {
$query->where('id', 1);
});
})->get();

Found the answer over here.
Project::with(['tasks' => function($q) {
$q->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
}])->get();

Related

Why is the model loading while whereHas is false?

I have this query:
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere([
['phone_number_start', '<=', $numbers[0]],
['phone_number_end', '>=', $numbers[1]],
])->get();
The PortingItem model still returns the query result while the porting relation is empty. I don't understand why this happens.
This is my Porting model relation
public function items()
{
return $this->hasMany(PortingItem::class);
}
This is my PortingItem model relation:
public function porting()
{
return $this->belongsTo(Porting::class);
}
You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere(function ($query) use ($numbers) {
$query->where('phone_number_start', '<=', $numbers[0])
->where('phone_number_end', '>=', $numbers[1]);
});
})->get();
https://laravel.com/docs/8.x/queries#logical-grouping

Laravel eloquent search query for two foreign tables

i have a question about the code above , i want to search with criteria from 2 extra tables
I want 'charge' from charges table , 'name' from user table and also 'name' from customer table
all has binds the above query runs but the doesnt fetch data from customers->name any idea how to make it work?
public function scopeSearch($query, $val){
return $query->has('customer')
->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->Orwhere('name','like','%'.$val.'%');
})
->with('user')
->with('customer');
}
You can follow the documentation about adding stuff to your relation query (whereHas).
So, you should have this:
public function scopeSearch($query, $val){
return $query->with(['user', 'customer'])
->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->Orwhere('name','like','%'.$val.'%');
})
->whereHas('customer', function($query) use ($val) {
$query->where('name','like','%'.$val.'%');
});
}
See that you had only used whereHas for users but not customers...
Finally worked! after some research i found that the problem was my using of or statement
the code above works for me:
public function scopeSearch($query, $val){
return $query->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->orWhere('name','like','%'.$val.'%');
})
->orWhereHas('customer', function($query) use ($val) {
$query->where('name', 'LIKE', '%'.$val.'%');
})
->with('user', 'customer');
}

Laravel eloquent order by subquery

I have a problem with ordering by columns in subquery (lastname, firstname).
I already tried this code as suggested by other posts:
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}])
Here my full code, but it doesn't work.
return Membership::forCompany($companyId)
->whereIn('state', ['ATTIVA', 'IN ATTESA DI ESITO', 'DA INVIARE'])
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->with('federation')
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}]);
Here the relationships:
In customer model I have:
public function memberships() {
return $this->hasMany('App\Models\Membership');
}
In Membership model I have:
public function customer() {
return $this->belongsTo("App\Models\Customer");
}
Try orderBy() with join() like:
$memberships = \DB::table("memberships")
->where("company_id", $companyId)
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->join("customers", "memberships.customer_id", "customers.id")
->select("customers.*", "memberships.*")
->orderBy("customers.lastname", "asc")
->get();
dd($memberships);
Let me know if you are still having the issue. Note, code not tested! so you may need to verify by yourself once.

Laravel Eloquent - Having trouble querying relationship with ownership

I want to get all categories and within those categories, only items that belong to the logged in user. If there are none, the category should still be there.
This is what I tried. Still getting items from other users.
$categories = Category::parents()
->with(['lineItems' => function ($query) use($id) {
$query->where('user_id', $id);
}])->get();
Haven't been able to find anything that works. (using laravel 5.7)
Relationships
Category
public function lineItems()
{
return $this->hasMany(LineItem::class);
}
LineItems
public function category()
{
return $this->belongsTo(Category::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
I'm not sure where the ::parents() method is coming from (I can't find documentation for it anywhere; is it something you wrote?), but it seems like
$categories = Category::all()
->with(['lineItems' => function ($query) use ($id) {
$query->where('user_id', $id);
}])->get();
might work?
So, Travis's question made me think about my loop. My with was affecting my top level categories which left its children's line items without the where user. There's probably a more elegant method of doing this but this is what ended up working.
This queries the child's line items and the grandchild's line items.
$categories = Category::parents()->ordered()
->with(['children.lineItems' => function($q) use($id) {
$q->where('user_id', '=', $id);
}, 'children.children.lineItems' => function($q) use($id) {
$q->where('user_id', '=', $id);
}])->get();
Try this:
$categories = Category::parents()
->whereHas('lineItems', function ($query) use($id) {
$query->where('user_id', $id);
})->get();

Laravel 4 Eager Loading constraints

I want to get all Items (topics) WITH their comments, if comments user_id = $id. I try something like this, but it isn't working. So if Item hasn't got any comment with user_id = $id, then I don't need this Item.
In DiscussionsItem model I have methode:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id');
}
My query in controller is like this:
$items = DiscussionsItem::whereBrandId($brand_id)
->whereBrandCountryId($country_id)
->with(['discussionsComments' => function($query) use ($id) {
$query->where('user_id', '=', $id);
}])
->whereHas('discussionsComments', function($query) use ($id) {
$query->where('user_id', '=', $id);
})
->with(['views' => function($query) use ($id) {
$query->where('user_id', $id)->count();
}])
->orderBy('created_at', 'DESC')->get();
My problem is that I get items with comments, where comments user_id != $id.
P.S. I need to take 5 comments, but I cant imagine how to do that, because ->take(5) in my eager load is not working.
You can do a custom scope, or just limit the amount returned by your relation:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id')
->latest()
->take(5);
}

Resources