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

Laravel Filament v3升级报错:Livewire不支持Decimal属性类型

解决方案:Livewire无法处理php-decimal类型的问题

问题根源

Livewire默认仅支持原生PHP类型(字符串、数值、数组等)及实现特定序列化接口的对象,php-decimal扩展的Decimal实例不在此列,导致序列化时抛出类型不支持错误。


方案1:在自定义Cast中适配Livewire场景(推荐)

直接修改现有DecimalZeroCast类,针对Livewire请求返回可序列化的字符串类型,非Livewire场景保留原有Decimal实例:

use Decimal\Decimal;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\CastsAttributes;

class DecimalZeroCast implements CastsAttributes
{
    /**
     * Cast the given value.
     */
    public function get(Model $model, string $key, mixed $value, array $attributes): Decimal|string
    {
        $decimal = is_null($value) ? new Decimal(0) : (is_float($value) ? new Decimal((string) $value) : new Decimal($value));
        
        // Livewire请求下返回字符串,兼容序列化规则
        if (app()->runningInLivewire()) {
            return $decimal->toString();
        }
        
        return $decimal;
    }

    /**
     * Prepare the given value for storage.
     */
    public function set(Model $model, string $key, mixed $value, array $attributes): float
    {
        // 处理Livewire传入的字符串值,转成Decimal再处理
        if (is_string($value)) {
            $value = new Decimal($value);
        }
        
        return is_null($value) ? 0 : ($value instanceof Decimal ? $value->toFixed(12) : $value);
    }
}

此方案无需改动业务逻辑,仅在Cast层做场景适配,不影响原有依赖Decimal实例的代码。


方案2:为Decimal实现Livewire的Wireable接口

如果需要在Livewire中保留Decimal实例的操作能力,可以创建一个包装类实现Wireable接口,让Livewire能正确序列化/反序列化:

use Decimal\Decimal;
use Livewire\Wireable;

class WireableDecimal implements Wireable
{
    public function __construct(public Decimal $decimal) {}

    // 从Livewire序列化值重建对象
    public static function fromLivewire($value)
    {
        return new self(new Decimal($value));
    }

    // 将对象转为Livewire可处理的类型
    public function toLivewire()
    {
        return $this->decimal->toString();
    }

    // 代理所有方法到内部Decimal实例,兼容原有业务调用
    public function __call($method, $arguments)
    {
        return $this->decimal->$method(...$arguments);
    }
}

然后修改DecimalZeroCast的get方法:

public function get(Model $model, string $key, mixed $value, array $attributes): WireableDecimal|Decimal
{
    $decimal = is_null($value) ? new Decimal(0) : (is_float($value) ? new Decimal((string) $value) : new Decimal($value));
    
    if (app()->runningInLivewire()) {
        return new WireableDecimal($decimal);
    }
    
    return $decimal;
}

方案3:在Livewire组件中自定义序列化规则

若仅需在特定组件中解决问题,可在对应Filament/Livewire组件中指定字段的序列化方式:

use App\Models\Project;
use Livewire\Component;

class YourProjectResource extends Component
{
    public Project $project;

    protected function serialize(): array
    {
        $data = parent::serialize();
        
        // 将Decimal实例转为字符串,适配Livewire序列化
        $data['project']['investment'] = $this->project->investment->toString();
        
        return $data;
    }
}

或者使用serializeUsing方法更精准地指定字段规则:

public function mount(Project $project)
{
    $this->project = $project;
    
    $this->serializeUsing('project.investment', function ($decimal) {
        return $decimal->toString();
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:26:10