I've tried to calculate the total sum of an order with help of this: Laravel Eloquent: Best Way to Calculate Total Price
I want the calculation to be done in the model, so I can use it in multiple controllers.
My code looks like this:
class Order extends Model
{
public function customer()
{
return $this->belongsTo('App\Customer');
}
public function orderItems()
{
return $this->hasMany('App\OrderItem');
}
public function total()
{
return $this->orderItems->sum(function($orderItem)
{
return $orderItem->net_price;
});
}
}
So I think I have done everything exactly like in the example, but I'm getting following error:
ErrorException in Model.php line 2696: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Any help will be highly appreciated.
Thanks.
Joha, I would be very careful using the sum function on a collection when you are working with decimal values. This will not be relevant if you are using integer values.
You may find that the sum function will sometimes miscalculate the sum, and leave you with quirky numbers like 59.999999999998184
. This is because decimal operations aren't very stable in computers, so you must loop around each item and use bcmath instead to avoid this. Even if you're not experiencing it now, as the app grows, this would become a problem.
Here would be a more secure & accurate example:
class Order extends Model{
public function customer()
{
return $this->belongsTo('App\Customer');
}
public function orderItems()
{
return $this->hasMany('App\OrderItem');
}
public function getTotalAttribute() {
$totalPrice = 0;
foreach ($this->orderItems as $orderItem) {
$totalPrice = bcadd($totalPrice, $orderItem->net_price, 2);
}
return $totalPrice;
}
}
I would also refactor the function into an attribute, as shown in the code example. This allows you to access $order->total
as if it was an attribute on the model.
What about:
public function total() {
return $this->orderItems->sum('net_price');
}
The problem is in you hasMany
relationship. Try this:
public function orderItems()
{
return $this->hasMany(App\OrderItem::class, 'order_id');
}
Of course, you must change order_id
to the name that holds the information in the OrderItem's table.
Seems like the function is correct and the problem was that the view from where i called it was not uploaded correctly after i changed it. the call in the view must be {{ $order->total() }}
Thanks for your help guys!