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

Laravel 9 基于Carbon生成带日期的4位自增编码报错排查

Laravel 9 生成MMMyy-0001格式自增编码及控制器错误修复

问题背景

需求是在Laravel 9中为products表生成格式为MMMyy-0001(例如Oct22-0001、Sep22-0002)的4位自增字符串编码,对应的表迁移代码如下:

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('nama_barang');
        $table->string('kode', 10);
        $table->double('harga');
        $table->integer('jumlah');
        $table->timestamps();
    });
}

原编写的ProductController的store方法运行时抛出错误:

"message": "Illuminate\Database\Eloquent\Builder::create(): Argument #1 ($attributes) must be of type array, App\Models\Product given, called in C:\Users\nana\test\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php on line 23"

原控制器代码:

public function store(Request $request) 
{
    $storeData = $request->all();
    $validate = Validator::make($storeData, [
        'nama_barang' => 'required|max:60|unique:products',
        'harga' => 'required|numeric',
        'jumlah' => 'required|numeric'
    ]);

    $lastValue = Product::orderBy('kode', 'desc')->first();
    $storeData = new Product();
    $date = Carbon::now();
    $storeData->kode = $date . '-' . str_pad($lastValue->kode, 4, '0', STR_PAD_LEFT) + 1;

    if($validate->fails())
        return response(['message' => $validate->errors()], 400);

    $product = Product::create($storeData); 
    return response([
        'message' => 'Add product Success',
        'data' => $product
    ], 200);
}

错误原因分析

  1. 参数类型错误:Product::create()方法要求传入数组格式的属性,但代码中把原本存储请求数据的$storeData变量重新赋值为Product实例,导致传参类型不匹配。
  2. 编码生成逻辑错误:
    • Carbon直接转字符串不会得到MMMyy格式,需要指定格式化规则
    • 直接对lastValue->kode做处理,没有拆分出编码的数字部分,且未考虑表为空(无数据)的情况
    • 字符串拼接与数字加法的顺序错误,会导致非预期的运算结果
  3. 验证顺序错误:先处理编码生成逻辑再做验证,若验证失败会白耗算力,且可能因无合法数据导致逻辑报错

修复后的完整代码

use Carbon\Carbon;
use Illuminate\Support\Facades\Validator;
use App\Models\Product;

public function store(Request $request) 
{
    // 先做请求验证,失败直接返回错误
    $validate = Validator::make($request->all(), [
        'nama_barang' => 'required|max:60|unique:products',
        'harga' => 'required|numeric',
        'jumlah' => 'required|numeric'
    ]);

    if($validate->fails()) {
        return response(['message' => $validate->errors()], 400);
    }

    // 获取请求数据数组
    $storeData = $request->only(['nama_barang', 'harga', 'jumlah']);

    // 生成自增编码
    $datePrefix = Carbon::now()->format('M'); // 获取月份缩写(如Oct、Sep)
    $yearSuffix = Carbon::now()->format('y'); // 获取两位年份(如22、23)
    $currentPrefix = $datePrefix . $yearSuffix;

    // 查询当前前缀下的最后一条记录
    $lastProduct = Product::where('kode', 'like', "{$currentPrefix}-%")
        ->orderBy('kode', 'desc')
        ->first();

    if ($lastProduct) {
        // 拆分编码的数字部分并自增
        $lastNumber = (int) substr($lastProduct->kode, -4);
        $newNumber = $lastNumber + 1;
    } else {
        // 无记录时从0001开始
        $newNumber = 1;
    }

    // 拼接成最终编码
    $storeData['kode'] = "{$currentPrefix}-" . str_pad($newNumber, 4, '0', STR_PAD_LEFT);

    // 创建并保存产品
    $product = Product::create($storeData); 

    return response([
        'message' => 'Add product Success',
        'data' => $product
    ], 200);
}

关键逻辑说明

  1. 验证前置:先执行请求验证,避免无效的编码计算
  2. 日期格式处理:使用Carbon的format('M')获取月份缩写,format('y')获取两位年份,拼接成编码前缀(如Oct22)
  3. 自增数字处理:
    • 通过where('kode', 'like', "{$currentPrefix}-%")确保只统计当前年月前缀下的记录,避免跨年月的编码冲突
    • 拆分最后一条记录编码的后4位数字,转成整数后自增
    • 表为空时默认从1开始,通过str_pad补零成4位格式
  4. 正确使用create方法:保持$storeData为数组格式,追加生成的kode字段后传入create()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 02:20:30