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); }
错误原因分析
- 参数类型错误:
Product::create()方法要求传入数组格式的属性,但代码中把原本存储请求数据的$storeData变量重新赋值为Product实例,导致传参类型不匹配。 - 编码生成逻辑错误:
- Carbon直接转字符串不会得到
MMMyy格式,需要指定格式化规则 - 直接对
lastValue->kode做处理,没有拆分出编码的数字部分,且未考虑表为空(无数据)的情况 - 字符串拼接与数字加法的顺序错误,会导致非预期的运算结果
- Carbon直接转字符串不会得到
- 验证顺序错误:先处理编码生成逻辑再做验证,若验证失败会白耗算力,且可能因无合法数据导致逻辑报错
修复后的完整代码
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); }
关键逻辑说明
- 验证前置:先执行请求验证,避免无效的编码计算
- 日期格式处理:使用Carbon的
format('M')获取月份缩写,format('y')获取两位年份,拼接成编码前缀(如Oct22) - 自增数字处理:
- 通过
where('kode', 'like', "{$currentPrefix}-%")确保只统计当前年月前缀下的记录,避免跨年月的编码冲突 - 拆分最后一条记录编码的后4位数字,转成整数后自增
- 表为空时默认从1开始,通过
str_pad补零成4位格式
- 通过
- 正确使用create方法:保持
$storeData为数组格式,追加生成的kode字段后传入create()
内容的提问来源于stack exchange,提问作者Bruh Brah
相关产品推荐
相关产品推荐

