You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算购物车中商品与课程的总金额?

购物车总金额计算问题

问题背景

我有两张products表和一张courses表,每个购物车可添加多个商品和课程。商品/课程的单价×订购数量后的单项总价,已经正确存储在中间表的total字段中。现在需要计算每个订单的总金额,生成订单概览,但现有代码计算结果始终为0,移除判断后又报数组键不存在的错误。

首次尝试的代码

@php
    $totalPrice = 0;
    foreach (App\Services\Cart\Cart::all() as $cart) {
       if (isset($cart['product']) && isset($cart['course'])) {
          $productPrice = intval($cart['product']->price);
          $coursePrice = intval($cart['course']->price);
          $totalPrice += ($productPrice + $coursePrice) * $cart['quantity'];
       }
    }
    $totalPrice = number_format($totalPrice);
@endphp
<div class="text-large"><strong>{{ $totalPrice }} $</strong></div>

移除判断后的代码

@php
    $totalPrice = 0;
    foreach (App\Services\Cart\Cart::all() as $cart) {
        $productPrice = intval($cart['product']->price);
        $coursePrice = intval($cart['course']->price);
        $totalPrice += ($productPrice + $coursePrice) * $cart['quantity'];
    }
    $totalPrice = number_format($totalPrice);
@endphp
<div class="text-large"><strong>{{ $totalPrice }} $</strong></div>

Cart服务类代码(App\Services\Cart\Cart.php)

<?php

namespace App\Services\Cart;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class Cart
{
    protected $cart;

    public function __construct()
    {
        $this->cart = session()->get('cart') ?? collect([]);
    }

    /**
     * @param array $value
     * @param null $obj
     * @return $this
     */
    public function put(array $value , $obj = null)
    {
        if(!is_null($obj) && $obj instanceof Model) {
            $value = array_merge($value , [
                'id' => Str::random(10),
                'subject_id' => $obj->id,
                'subject_type' => get_class($obj)
            ]);
        } elseif(!isset($value['id'])) {
            $value = array_merge($value , [
                'id' => Str::random(10)
            ]);
        }
        $this->cart->put($value['id'] , $value);
        session()->put('cart' , $this->cart);
        return $this;
    }

    public function update($key, $options)
    {
        $item = collect($this->get($key, false));
        if (is_numeric($options)) {
            $item = $item->merge([
                'quantity' => $item['quantity'] + $options
            ]);
        }
        if (is_array($options)) {
            $item = $item->merge($options);
        }
        $this->put($item->toArray());
        return $this;
    }

    public function count($key)
    {
        if (!$this->has($key)) return 0;
        return $this->get($key)['quantity'];
    }

    public function has($key)
    {
        if($key instanceof Model) {
            return ! is_null(
                $this->cart->where('subject_id' , $key->id)->where('subject_type' , get_class($key))->first()
            );
        }

        return ! is_null(
            $this->cart->firstWhere('id' , $key)
        );
    }

    public function get($key, $withRelationship = true)
    {
        $item = $key instanceof Model
            ? $this->cart->where('subject_id' , $key->id)->where('subject_type' , get_class($key))->first()
            : $this->cart->firstWhere('id' , $key);

        return $withRelationship ? $this->withRelationshipIfExist($item) : $item;
    }

    public function all()
    {
        $cart = $this->cart;
        $cart = $cart->map(function($item) {
            return $this->withRelationshipIfExist($item);
        });

        return $cart;
    }

    protected function withRelationshipIfExist($item)
    {
        if(isset( $item['subject_id'] ) && isset($item['subject_type']) ) {
            $class = $item['subject_type'];
            $subject = (new $class())->find( $item['subject_id'] );

            $item[strtolower(class_basename($class))] = $subject;

            unset($item['subject_id']);
            unset($item['subject_type']);

            return $item;
        }
        return $item;
    }

    public function delete($key)
    {
        if ($this->has($key)) {
            $this->cart = $this->cart->filter(function ($item) use ($key){
                if ($key instanceof Model) {
                    return ($item['subject_id'] != $key->id ) && ($item['subject_type'] != get_class($key));
                }
                return $key != $item['id'];
            });
            session()->put('cart', $this->cart);
            return true;
        }
        return false;
    }

    public function flush()
    {
        $this->cart = collect([]);
        session()->put('cart', $this->cart);
        return $this;
    }
}

移除判断后出现的错误

Undefined array key "course"

解决方案

问题核心:每个购物车项要么是商品(仅含product键),要么是课程(仅含course键),不会同时存在两者。之前的代码要么要求两者都存在才计算(导致所有项都不满足,结果为0),要么强制访问两个不存在的键(触发报错)。

结合你提到的「单项总价已存储在total字段」,推荐直接读取该字段计算总金额,更高效且避免重复计算:

方案1:修改视图计算代码

@php
    $totalPrice = 0;
    foreach (App\Services\Cart\Cart::all() as $cartItem) {
        // 优先读取已存储的单项总价
        if (isset($cartItem['total'])) {
            $totalPrice += intval($cartItem['total']);
        } else {
            // 兼容无total字段的情况,分别处理商品/课程
            $itemPrice = 0;
            if (isset($cartItem['product'])) {
                $itemPrice = intval($cartItem['product']->price) * intval($cartItem['quantity']);
            } elseif (isset($cartItem['course'])) {
                $itemPrice = intval($cartItem['course']->price) * intval($cartItem['quantity']);
            }
            $totalPrice += $itemPrice;
        }
    }
    $totalPrice = number_format($totalPrice);
@endphp
<div class="text-large"><strong>{{ $totalPrice }} $</strong></div>

方案2:在Cart类中新增总金额计算方法(更优雅)

在Cart类中添加以下方法:

// 计算购物车总金额
public function getTotal()
{
    return $this->cart->sum(function($item) {
        // 优先使用已存储的单项总价
        if (isset($item['total'])) {
            return intval($item['total']);
        }
        
        // 无total字段时,关联模型后计算
        $itemWithRel = $this->withRelationshipIfExist($item);
        if (isset($itemWithRel['product'])) {
            return intval($itemWithRel['product']->price) * intval($itemWithRel['quantity']);
        } elseif (isset($itemWithRel['course'])) {
            return intval($itemWithRel['course']->price) * intval($itemWithRel['quantity']);
        }
        
        return 0;
    });
}

然后在视图中直接调用:

@php
    $cart = app(App\Services\Cart\Cart::class);
    $totalPrice = number_format($cart->getTotal());
@endphp
<div class="text-large"><strong>{{ $totalPrice }} $</strong></div>

内容的提问来源于stack exchange,提问作者irankhostravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:25:57