Laravel Eloquent - Filter Relationship of Relationship - laravel

This is the query I tried to do:
$products = Product::with(['cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->where('status_id',2)
->get();
I get this results:
In cross_selling I still get id:12 that doesn't has any product_related. I need some help for making that the query doesn't give me that item if product_related is null.
Tks.

First get only those cross selling which has any related products after that get related products. Use the whereHas condition on cross_selling.
$products = Product::with(['cross_selling' => function($qry){
$qry->whereHas('product_related', function ($q) {
$q->where('status_id', 2);
});
}, 'cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->where('status_id',2)
->get();

Try this
$products = Product::with(['cross_selling.product_related' =>
fn($query) => $query->where('status_id', '=', '2')])
->has('cross_selling.product_related')
->where('status_id',2)
->get();

If you don't want cross selling products with no related products you can add
->whereHas('product_related')
Which basically says: Get me only cross selling which have 'product_related'.
In order to do it properly, you can:
$callback = fn($query) => $query->where('status_id', 2);
$products = Product::whereHas('cross_selling.product_related', $callback)
->with(['cross_selling.product_related' => $callback])
->where('status_id',2)->get();
Now the callback is applied to the whereHas() and the with() plus you can pass additional constraints using $callback.

Related

Laravel query orderBy nested relationship

I have the following relationship:
Unit (HasMany)-> Users -> (BelongsTo) -> Position
I am trying to return an array of units with users, where users are sorted by their position. The property in the position model is 'order' that I would like to use as the sort field. I have attempted the following:
return Unit::query()->ordered()->with(['users' => function($query) {
$query->with(['position' => function($query) {
$query->orderBy('order');
}]);
}])->get();
You can not order by nested relationship just using with() method. You need to join the relation first. So the code should be:
return Unit::query()->ordered()->with([
'users' => function ($query) {
$query->join('positions', 'positions.id', '=', 'users.position_id');
$query->orderBy('positions.order');
}
])->get();
or another way is order using laravel collection sortBy
$ordered_units = Unit::query()->ordered()->with(['users' => function($query) {
$query->with(['position' => function($query) {
$query->orderBy('order');
}]);
}])->get();
return $ordered_units->sortBy('users.position.order');

Laravel - Filter collection with closure on relationship

Wondering if there is a way to use closure on a relationship in order to filter the whole line if there isn't a value which corresponds?
Example code:
foreach ($paiementMethods as $value) {
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods' => function($query) use ($value)
{
$query->where('id', $value);
}])
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')->get();
$giftCardsCollection = $giftCardsCollection->merge($giftCards);
}
}
In this example, if $query->where doesn't find a row for the payement.payementMethods which matches the $value, I want the giftCard to return null. The result I get is the giftCard with only the relation on payement.payementMethods being empty.
My other solution would be to query the giftCard and after that checking the $value to see if I have to include the giftCard in the collection or not.
Best regards
I think using whereHas, it can be solved
$giftCards = GiftCard::with(['userEntered', 'userEmployee', 'client', 'payement', 'payement.payementMethods'])
->whereHas( 'payement.payementMethods', function($query) use ($paiementMethods) {
$query->whereIn('id', $paiementMethods);
})
->where('date','>=', $dateStart)
->where('date','<=', $dateEnd)
->orderBy('updated_at', 'desc')
->get();

How to add where inside aggregate function in laravel?

How can I add "where" inside this code?
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->sum('amount_paid');
}])->get();
i'd like to say "with 'loanPayments', sum 'amount_paid' where 'type' is 'payment'.
Thank you so much in advance!
Inside the function, $query is a normal query builder. I think this is what you want:
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->sum('amount_paid');
$query->where('type', 'payment');
}])->get();
Add ->where('type', 'payment')
Select the foreign_key out, and group by foreign_key
$loans = LoanApplication::with('loanInterests')
->with(['loanPayments' => function($query) {
$query->where('type', 'payment')
->select(DB::raw('SUM(amount_paid) AS sum_amount_paid'), 'loan_application_id')
->groupBy('loan_application_id');
}])->get();

How to Write Sub Query in With()?

I have to get specific data like "roles" table have filed status and i need status = 1 that all data get from the role table
$result = User::select()
->with('roles')
->where('email', $email)
->get();
return $result;
Following the answers to this question: Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean?
If I understood correctly how your data model is structured:
User has many Roles
Role has a property status
Want to filter by status = 1
$users = User::whereHas('roles', function($q){
$q->where('status', '1');
})
->where('email', $email)
->get();
EDIT: I am not happy with the answer above because in that case as far as I understood, the Users returned do not have the list of roles already loaded, so I checked the documentation (https://laravel.com/docs/5.8/eloquent-relationships) and given what I found, the following code should do what you ask:
$users = User::with(['roles' => function ($query) {
$query->where('status', '1');
}])
->where('email', $email)
->get();
I never used eloquent nor laravel and I am not a php developer, so I could not try this snippet, please if it is not correct let me know.
You can write subQuery like
$result = User::select()
->with(['roles' => function($q){
$q->where('status', 1);
}])
->where('email', $email)
->get();
return $result;

How to get flat array of eager loading in laravel 5.5?

this my eloquent query:
$data = Disciplines::where('type', '<>', 'Initiator')
->with(['discipline_boxes.assign.box' => function($query) {
$query->select('id');
}])
->get();
return $data;
i want return only array of id's of box relation
e.g:[2,3,4,5]
Solved!!
this worked for me!
$disciplines = new Disciplines();
$results = $disciplines->getAllBox_ID()->toArray();
dd(array_flatten(array_pluck($results,'discipline_boxes.*.assign.box.id')));
Potentially if you have the inverse for this chain of relationships you could get this information from the Box end (making name assumptions here):
Box::whereHas('assign.discipline_box.discipline', function ($q) {
$q->where('type', '<>', 'Initiator');
})->pluck('id');

Resources