Laravel11+Livewire:如何将非模型字段保存至SERVICE_EXTEND表
问题描述
我正在使用Laravel 11搭配Livewire开发,现有Service模型,需要添加类似wp_postmeta的SERVICE_EXTEND通用字段(包含meta_key和meta_value)。我已在表单视图中添加了matricola字段,但不清楚如何将这个不属于Service模型的字段数据保存到SERVICE_EXTEND数据表中。相关代码如下:
Model\Service.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; /** * Class Service * * @property $id * @property $father_id * @property $category_id * @property $customer_id * @property $name * @property $date * @property $description * @property $created_at * @property $updated_at * * @property Category $category * @property Customer $customer * @property Service $service * @property Service[] $services * @property ServiceExtend[] $serviceExtends * @property ServiceItem[] $serviceItems * @package App * @mixin \Illuminate\Database\Eloquent\Builder */ class Service extends Model { protected $perPage = 20; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = ['father_id', 'category_id', 'customer_id', 'name', 'date', 'description']; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function category() { return $this->belongsTo(\App\Models\Category::class, 'category_id', 'id'); } /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function customer() { return $this->belongsTo(\App\Models\Customer::class, 'customer_id', 'id'); } /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function service() { return $this->belongsTo(\App\Models\Service::class, 'father_id', 'id'); } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function services() { return $this->hasMany(\App\Models\Service::class, 'id', 'father_id'); } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function serviceExtends() { return $this->hasMany(\App\Models\ServiceExtend::class, 'id', 'service_id'); } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function serviceItems() { return $this->hasMany(\App\Models\ServiceItem::class, 'id', 'service_id'); } }
Forms\ServiceForm.php
<?php namespace App\Livewire\Forms; use App\Models\Service; use Livewire\Form; class ServiceForm extends Form { public ?Service $serviceModel; public $father_id = ''; public $category_id = ''; public $customer_id = ''; public $name = ''; public $date = ''; public $description = ''; public function rules(): array { return [ 'category_id' => 'required', 'customer_id' => 'required', 'name' => 'required|string', 'date' => 'required', 'description' => 'string', ]; } public function setServiceModel(Service $serviceModel): void { $this->serviceModel = $serviceModel; $this->father_id = $this->serviceModel->father_id; $this->category_id = $this->serviceModel->category_id; $this->customer_id = $this->serviceModel->customer_id; $this->name = $this->serviceModel->name; $this->date = $this->serviceModel->date; $this->description = $this->serviceModel->description; } public function store(): void { $this->serviceModel->create($this->validate()); $this->reset(); } public function update(): void { $this->serviceModel->update($this->validate()); $this->reset(); } }
service\form.blade.php 新增代码
<div> <x-label for="matricola" :value="__('Matricola')"/> <input type="text" name="matricola" id="matricola" wire:model.defer='matricola' class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"> @error('matricola') <x-label class="mt-2" :messages="$message"/> @enderror </div>
service\Create.php
<?php namespace App\Livewire\Services; use App\Livewire\Forms\ServiceForm; use App\Models\Service; use App\Models\Category; use App\Models\Customer; use App\Models\Item; use Livewire\Attributes\Layout; use Livewire\Component; class Create extends Component { public ServiceForm $form; public function mount(Service $service) { $this->form->setServiceModel($service); } public function save() { $this->form->store(); if ($this->form['matricola']) { ServiceExtend::updateOrCreate( ['service_id' => $this->form->id, 'meta_key' => 'matricola'], ['meta_value' => $this->form['matricola'], 'meta_type' => null] ); } session()->flash('message', 'Service saved successfully.'); return $this->redirectRoute('services.index', navigate: true); } #[Layout('layouts.app')] public function render() { $categories = Category::all()->where('type','service')->pluck('name', 'id'); $customers = Customer::all()->mapWithKeys(function ($customer) { return [$customer->id => $customer->surname . ' ' . $customer->name]; }); $items = Item::all()->pluck('name','id'); return view('livewire.service.create', compact('categories','customers','items')); } }
解决方案
1. 修正Service模型的关联关系
当前serviceExtends方法的参数顺序错误,hasMany的语法为hasMany(关联模型, 外键, 本地键),需要调整为:
public function serviceExtends() { return $this->hasMany(\App\Models\ServiceExtend::class, 'service_id', 'id'); }
2. 更新ServiceForm类
添加matricola字段、验证规则,并完善store/update方法的扩展字段处理逻辑:
<?php namespace App\Livewire\Forms; use App\Models\Service; use Livewire\Form; class ServiceForm extends Form { public ?Service $serviceModel; public $father_id = ''; public $category_id = ''; public $customer_id = ''; public $name = ''; public $date = ''; public $description = ''; // 添加matricola字段 public $matricola = ''; public function rules(): array { return [ 'category_id' => 'required', 'customer_id' => 'required', 'name' => 'required|string', 'date' => 'required', 'description' => 'string', // 添加matricola验证规则,可根据需求调整 'matricola' => 'nullable|string', ]; } public function setServiceModel(Service $serviceModel): void { $this->serviceModel = $serviceModel; $this->father_id = $this->serviceModel->father_id; $this->category_id = $this->serviceModel->category_id; $this->customer_id = $this->serviceModel->customer_id; $this->name = $this->serviceModel->name; $this->date = $this->serviceModel->date; $this->description = $this->serviceModel->description; // 编辑时加载已保存的matricola值 $this->matricola = $this->serviceModel->serviceExtends->where('meta_key', 'matricola')->first()?->meta_value ?? ''; } public function store(): Service { // 创建Service实例并返回 $service = $this->serviceModel->create($this->validate()); // 保存扩展字段 if (!empty($this->matricola)) { $service->serviceExtends()->updateOrCreate( ['meta_key' => 'matricola'], ['meta_value' => $this->matricola, 'meta_type' => null] ); } $this->reset(); return $service; } public function update(): void { $this->serviceModel->update($this->validate()); // 更新扩展字段,为空则删除记录 if (!empty($this->matricola)) { $this->serviceModel->serviceExtends()->updateOrCreate( ['meta_key' => 'matricola'], ['meta_value' => $this->matricola, 'meta_type' => null] ); } else { $this->serviceModel->serviceExtends()->where('meta_key', 'matricola')->delete(); } $this->reset(); } }
3. 修正Create组件的save方法
移除原有的手动保存扩展字段逻辑,直接调用Form的store方法即可:
public function save() { $this->form->store(); session()->flash('message', 'Service saved successfully.'); return $this->redirectRoute('services.index', navigate: true); }
若后续需要编辑Service,Edit组件可直接复用Form的update方法,逻辑完全一致。
内容的提问来源于stack exchange,提问作者GMazzacua
相关产品推荐
相关产品推荐

