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

Laravel updateOrCreate提交后books/editions表字段为空问题

问题排查结果

books、editions表写入空值的核心原因是前后端参数不匹配,附带多个逻辑漏洞,具体问题点如下:

  • 前端表单字段缺少对应name属性:后端updateOrCreate需要读取的id、eid、book_title、book_author等参数,前端没有设置同名的表单项。你虽然通过JS把下拉选的data属性值填充到了输入框,但这些输入框没有配置和后端参数一致的name,值不会随表单提交;版本下拉选甚至连name属性都没写,选中的版本ID根本不会传给后端。listings表能正常写入,就是因为挂牌相关字段的输入框name和后端$request->get()的键名完全匹配。
  • 前端option标签重复定义value属性:你给图书、版本的option同时写了value="yes"和value="$r[5]",浏览器只会识别最后一个value,前面的定义完全冗余,容易引发逻辑错误。
  • 后端updateOrCreate逻辑不完善:当用户选择「我的图书不在列表中」时,前端传的id、eid为空,你没有处理新建记录后的关联绑定,直接把空的book_id传给Edition模型,会导致数据关联断裂;且新建Listing时直接取前端传的eid,如果是新版本新建场景,eid为空会导致挂牌和版本关联失败。
  • 视图层写法不规范:你在Blade模板里直接写原生mysqli连接、硬编码数据库账号密码,完全绕开Laravel的ORM,存在安全隐患。
修复方案

1. 调整前端表单结构

新增两个隐藏域存储选中的图书ID、版本ID,给所有图书、版本相关的输入框配置和后端参数一致的name属性,移除option重复的value定义,不要在视图里写原生数据库查询:

<!-- 隐藏域存储选中的ID,和后端取参名对应 -->
<input type="hidden" name="id" id="book_id_input">
<input type="hidden" name="eid" id="edition_id_input">

<div class="row">
    <div class="form-group col-6">
        <label for="book">{{ __('l.selectbook') }}</label>
        <select id="book" class="form-control" onchange="bookInfo()">
            <option value="">{{ __('l.onthislist') }}</option>
            @foreach($books as $r)
            <option value="{{ $r->id }}" 
                data-ttl="{{ $r->book_title }}" 
                data-auth="{{ $r->book_author }}"
                data-desc="{{ $r->book_description }}"
                data-yr="{{ $r->book_year }}"
                data-lang="{{ $r->book_language }}">
                {{ $r->book_title }}
            </option>
            @endforeach
        </select>
    </div>
    <div class="form-group col-6" id="edition-field-div">
        <label for="edition">{{ __('l.selectedition') }}</label>
        <select id="edition" class="form-control" onchange="editionInfo()">
            <option value="">{{ __('l.editionnotlist') }}</option>
            @foreach($editions as $r)
            <option value="{{ $r->id }}"
                data-img="{{ $r->image_url }}"
                data-pblshr="{{ $r->publisher }}"
                data-eyr="{{ $r->edition_year }}"
                data-pg="{{ $r->pages }}"
                data-cov="{{ $r->cover_type }}"
                data-bookid="{{ $r->book_id }}">
                {{ $r->book->book_title }} ({{ $r->publisher }}, {{ $r->edition_year }}, {{ $r->pages }} pages, {{ $r->cover_type == 'HC' ? 'Hardcover' : 'Paperback' }})
            </option>
            @endforeach
        </select>
    </div>
</div>

<!-- 所有图书、版本字段输入框必须配置对应name,示例如下 -->
<input type="text" name="book_title" id="book_title_input" class="form-control">
<input type="text" name="book_author" id="book_author_input" class="form-control">
<!-- 其余字段:book_description、book_year、book_language、image_url、publisher、edition_year、pages、cover_type 按相同规则加name属性 -->

同步调整两个下拉选的onchange JS逻辑:选中已有图书/版本时,把option的data-id赋值给对应隐藏域,同时把字段值填充到输入框;选中「不在列表中」时,清空隐藏域的ID值,解锁输入框让用户手动填写内容。

2. 修正后端控制器逻辑

加参数校验,用数据库事务保证数据一致性,新建/更新模型后拿到实例ID再做关联,不要直接依赖前端传的空ID:

<?php

namespace App\Http\Controllers;

use App\Models\Book;
use App\Models\Edition;
use App\Models\Listing;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ListingController extends Controller
{
    // 渲染表单的方法,把查询逻辑放这里,不要写在视图里
    public function create()
    {
        $books = Book::orderBy('book_title')->get();
        $editions = Edition::with('book')->orderBy('book_title')->get();
        return view('listing.create', compact('books', 'editions'));
    }

    public function store(Request $request)
    {
        // 参数校验
        $request->validate([
            'book_title' => 'required|string|max:255',
            'book_author' => 'required|string|max:255',
            'book_description' => 'nullable|string',
            'book_year' => 'required|integer',
            'book_language' => 'required|string|max:50',
            'publisher' => 'required|string|max:255',
            'edition_year' => 'required|integer',
            'pages' => 'nullable|integer',
            'cover_type' => 'required|in:HC,PB',
            'image_url' => 'nullable|string',
            'listing_description' => 'required|string',
            'price' => 'required|numeric|min:0',
            'condition' => 'required|string',
            'shipping_type' => 'required|string',
            'listing_image' => 'nullable|string',
            'user_id' => 'required|exists:users,id',
        ]);

        DB::transaction(function () use ($request) {
            // 更新/新建图书,拿到图书实例
            $book = Book::updateOrCreate(
                ['id' => $request->get('id')],
                $request->only(['book_title', 'book_author', 'book_description', 'book_year', 'book_language'])
            );

            // 更新/新建版本,强制绑定正确的book_id,拿到版本实例
            $edition = Edition::updateOrCreate(
                ['id' => $request->get('eid')],
                array_merge(
                    $request->only(['image_url', 'publisher', 'edition_year', 'pages', 'cover_type']),
                    ['book_id' => $book->id]
                )
            );

            // 保存挂牌信息,关联刚创建/更新的版本ID,避免新版本场景下eid为空
            Listing::create([
                'user_id' => $request->get('user_id'),
                'edition_id' => $edition->id,
                'listing_description' => $request->get('listing_description'),
                'price' => $request->get('price'),
                'condition' => $request->get('condition'),
                'shipping_type' => $request->get('shipping_type'),
                'image_url' => $request->get('listing_image'),
            ]);
        });

        return redirect()->route('new-listing')->with('message', 'Listing added successfully!');
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:24:27