How to put where condition on nested relation in laravel? - laravel

I have table Invoice which has relation with consignment hasMany
public function consignments_invoices()
{
return $this->hasMany('App\Models\Admin\Consignment', 'invoice_id');
}
and consignment has relation hasMany with Charge
public function charges()
{
return $this->hasMany('App\Models\Admin\Charge', 'object_id')->where('model', 'Consignment');
}
Here in charge I want to put where clause on attribute rate_zone_id
How i can achieve this?
I have existing query like
Invoice
::when(!empty($request->customer_id), function ($q) use ($request) {
return $q->where('customer_id', $request->customer_id);
})
->where('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date)
->with('consignments_invoices')->
->when(!empty($request->rate_zone_id), function ($q) use ($request) {
//Here is want to use where condition on rate zone id
})
->get();

For this you can use whereHas(). whereHas() can take a nested relationships using dot notation (consignments_invoices.charges) so you would have something like:
$query->whereHas('consignments_invoices.charges', function ($query) use ($request) {
$query->where('rate_zone_id', $request->rate_zone_id);
});
Furthermore, when() passes the first parameter as the second argument to the callback so you could have something like:
->when($request->rate_zone_id, function ($q, $rateZoneId) {
$q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) {
$q->where('rate_zone_id', $rateZoneId);
});
})
This would mean the entire query would look something like:
Invoice
::when($request->customer_id, function ($q, $customerId) {
return $q->where('customer_id', $customerId);
})
->when($request->rate_zone_id, function ($q, $rateZoneId) {
$q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) {
$q->where('rate_zone_id', $rateZoneId);
});
})
->where('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date)
->get();
The above will limit the Invoices to the specific rate_zone_id (when it's supplied), however, it won't constrain the consignments_invoices.
For this, you will need to constrain the consignments_invoices relationship in the with() call as well:
->with([
'consignments_invoices' => function ($query) use ($request) {
$query->with('charges')->when($request->rate_zone_id, function ($q, $rateZoneId) {
$q->whereHas('charges', function ($q) use ($rateZoneId) {
$q->where('rate_zone_id', $rateZoneId);
});
});
},
])
This will mean your entire query will look like:
Invoice
::with([
'consignments_invoices' => function ($query) use ($request) {
$query->with('charges')->when($request->rate_zone_id, function ($q, $rateZoneId) {
$q->whereHas('charges', function ($q) use ($rateZoneId) {
$q->where('rate_zone_id', $rateZoneId);
});
});
},
])
->when($request->customer_id, function ($q, $customerId) {
return $q->where('customer_id', $customerId);
})
->when($request->rate_zone_id, function ($q, $rateZoneId) {
$q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) {
$q->where('rate_zone_id', $rateZoneId);
});
})
->where('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date)
->get()

You can use nested relationship
Invoice::when(!empty($request->customer_id), function ($q) use ($request) {
return $q->where('customer_id', $request->customer_id);
})->where('start_date', '>=', $request->start_date)->whereDate('end_date', '<=', $request->end_date)
->when(!empty($request->rate_zone_id), function ($q) use ($request) {
$q->whereHas('consignments_invoices.charges',function ($query) use ($request){
$query->where('rate_zone_id',$request->rate_zone_id);
});
})->get();

$invoice = Invoice::with('charges')
->when(!empty($request->customer_id), function ($q) use ($request) {
return $q->where('customer_id', $request->customer_id);
})
->whereDate('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date);
if (!empty($request->rate_zone_id)) {
$invoice->whereHas('charges', function ($query1)use($request) {
$query1->where('rate_zone_id', $request->rate_zone_id);
});
}
$invoices = $invoice->get()->toArray();
Or
$invoices = Invoice::with('charges')
->when(!empty($request->customer_id), function ($q) use ($request) {
return $q->where('customer_id', $request->customer_id);
})
->whereDate('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date)
->when(!empty($request->rate_zone_id), function ($query1) use ($request) {
$rate_zone_id = $request->rate_zone_id;
$query1->whereHas('charges', function ($query2)use($rate_zone_id) {
$query2->where('rate_zone_id', $rate_zone_id );
});
})->get()->toArray();
$invoice = Invoice::when(!empty($request->customer_id), function ($q) use ($request) {
return $q->where('customer_id', $request->customer_id);
})
->whereDate('start_date', '>=', $request->start_date)
->whereDate('end_date', '<=', $request->end_date);
if (!empty($request->rate_zone_id)) {
$rate_zone_id = $request->rate_zone_id;
$invoice->with(['charges', function ($query1)use($rate_zone_id) {
$query1->where('rate_zone_id', $rate_zone_id);
}]);
}
$invoices = $invoice->get()->toArray();
use whereHas=> https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

Related

How can I filter data from relations in Laravel 8?

I have 3 tables business, service , service_venues. I need services of business having service_name = $search and and get venues of selected services. I am using services and resources method.
When there is search_keyword the data is not filtered. But other conditions are working.
How can I fix this?
In business model
public function businessServices()
{
return $this->hasMany(BusinessService::class);
}
in businessService model
public function businessServiceVenues()
{
return $this->hasMany(BusinessServiceVenue::class);
}
In service file
public function getServices($business){
$businessservices = $business->with(['businessServices'=> function ($q){
$q->where('business_services.service_name', 'like', '%'.request()->search_key.'%');
}
])->first();
return new servicesResource($businessservices);
}
In service resource
$services = $this->businessServices()
->with(['businessServiceStaffs','businessServiceVenues'])
->when(request()->filled('venue_ids'), function ($q) use($request) {
$q->whereHas('businessServiceVenues', function($q1) use($request) {
$q1->whereIn('venue_id',$request->venue_ids);
});
})
->when(request()->filled('staff_id'), function ($q) use($request) {
$q->whereHas('businessServiceStaffs', function($q1) use($request) {
$q1->where('staff_id','=',$request->staff_id);
});
})
->get();
This works for me
$businessServices = $business->businessServices()
->with(['businessServiceStaffs', 'businessServiceVenues'])
->when(request()->filled('search_key'), function ($q) {
$q->where('business_services.service_name', 'like', '%' . request('search_key') . '%');
})
->when(request()->filled('venue_ids'), function ($q) {
$q->whereHas('businessServiceVenues', function ($q) {
$q->whereIn('venue_id', request('venue_ids'));
});
})
->when(request()->filled('staff_id'), function ($q) {
$q->whereHas('businessServiceStaffs', function ($q) {
$q->where('staff_id', '=', request('staff_id'));
});
})
->get();

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 query with relationship where have all ids

I try to do a query where I get a room where I have all the services.
With my current code I get the room that has at least one of the services from the array, because I am using whereIn.
$rooms = Room::select([
'rooms.id',
'rooms.available_from',
'rooms.available_till',
'rooms.description',
'rooms.room_type_id',
'room_types.name as room_types_name',
])
->leftJoin('room_types', 'room_types.id', 'rooms.room_type_id')
->with('services','reserved_rooms')
->when($request->services, function ($query) use ($request) {
$query->whereHas('services', function ($q) use ($request) {
$q->whereIn('id', $request->services);
});
})
->orderByDesc('id')
->get();
If you want to match all services, you can use for loop to create AND query.
Try below code:
->when($request->services, function ($query) use ($request) {
foreach ($request->services as $key => $service) {
$query->whereHas('services', function ($q) use ($service) {
$q->where('id', $service);
});
}
})
->when($request->services, function ($query) use ($request) {
$query->whereHas('services', function ($q) use ($request) {
$q->selectRaw('count(distinct id)')->whereIn('id', $request->services);
}, '=', count($request->services)
);
})
Changed it,not tested but this is the general idea: get the rows where the COUNT of distinct ids is equal to the length of array.The array should be unique.

Remove duplication of code in Laravel- optimize

I want to how to optimize my code below without affecting its output in laravel?
$user = User::with('voucherUtilizations.voucher')
->with('voucherUtilizations', function ($query) use($campaignId ,$date_from,$date_to) {
if ($campaignId && $date_from &&$date_to) {
return $query->where('campaign_id', $campaignId)
->whereDate('created_at', '>=', $date_from)
->whereDate('created_at', '<=', $date_to)
->whereNotNull('voucher_id');
}
if ($campaignId) {
return $query->where('campaign_id', $campaignId)
->whereNotNull('voucher_id',);
}
if ($date_from &&$date_to) {
return $query->whereDate('created_at', '>=', $date_from)
->whereDate('created_at', '<=', $date_to)
->whereNotNull('voucher_id');
}
})
->withCount(['voucherUtilizations as no_of_prizes_won' => function ($query) use($campaignId ,$date_from,$date_to){
//the same code above function
}])
->where('id', $id->id)
->first()
some functions are repeated all common how can I minimize this code
$user = User::where('id', $id)
->with('voucherUtilizations.voucher')
->with(['voucherUtilizations', function ($query) use($campaignId, $date_from, $date_to) {
$query->when(!empty($campaignId), function ($q1) use ($campaignId) {
return $q1->where('campaign_id', $campaignId);
});
$query->when(!empty($date_from), function ($q2) use ($date_from) {
return $q2->whereDate('created_at', '>=', $date_from);
});
$query->when(!empty($date_to), function ($q3) use ($date_to) {
return $q3->whereDate('created_at', '<=', $date_to);
});
}])
->withCount('voucherUtilizations')
->whereNotNull('voucher_id')
->first();
use when() or also put if condition ,and value exist in if condition then return values,so not added 2 times same condition.
Hope fully it will help to you easily.

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.

Resources