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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:02:03