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
相关产品推荐
相关产品推荐

