Laravel仓库产品展示问题:移除->first()后traceability报错
问题分析
你遇到的核心问题是:
- 使用
->first()时,只会获取产品的单条库存记录,导致同一产品有多条库存时,仅能显示第一条库存信息,且产品基础信息重复 - 移除
->first()后,查询返回的是Collection集合对象,而非单个模型实例,直接访问->traceability这类属性会触发"试图获取非对象属性"的错误
同时原代码存在两次重复查询的冗余问题,还存在SQL注入风险(whereRaw直接拼接变量),一并优化。
解决方案
以下是优化后的代码,通过一次查询获取所有数据并按产品分组,然后遍历生成包含所有库存信息的HTML:
$Input = $request->key; $almacen = $request->almacen; // 一次查询获取所有符合条件的产品+库存数据,用参数绑定避免SQL注入 $productsWithInventories = DB::table('products') ->leftJoin('inventories', 'inventories.product_id', '=', 'products.id') ->leftJoin('warehouses', 'inventories.warehouse_id', '=', 'warehouses.id') ->where(function ($query) use ($Input) { $query->where('products.reference', 'like', "%{$Input}%") ->orWhere('products.name', 'like', "%{$Input}%"); }) ->where('warehouses.id', $almacen) ->whereNull('products.deleted_at') ->whereNull('inventories.deleted_at') ->select([ 'products.reference', 'products.name', 'products.sku', 'products.id', 'inventories.lot', 'inventories.expirationDate', 'inventories.traceability', 'inventories.warehouse_id' ]) ->get() // 按产品ID分组,把同一产品的所有库存记录归到一组 ->groupBy('id'); $html = ''; // 判断是否有结果,用isEmpty()更严谨 if (!$productsWithInventories->isEmpty()) { foreach ($productsWithInventories as $productId => $inventoryItems) { // 取产品基础信息(同一组里的基础信息一致,取第一个即可) $productBase = $inventoryItems->first(); // 遍历该产品的每条库存记录,生成HTML foreach ($inventoryItems as $item) { $html .= '<div> <a style="color: #000000" class="suggest-element" traceability="' . e($item->traceability) . '" reference="' . e($productBase->reference) . '" sku="' . e($productBase->sku) . '" name="' . e($productBase->name) . '" lot="' . e($item->lot) . '" expirationDate="' . e($item->expirationDate) . '" data="' . e($productBase->reference . ' ' . $productBase->name) . '" id="' . e($productBase->id) . '"> ' . e($productBase->reference) . ' ' . e($productBase->name) . ' ' . e($item->lot) . ' ' . e($item->expirationDate) . ' ' . e($item->traceability) . ' </a> </div>'; } } } else { $html .= '<div><a style="color: #000000" class="suggest-element" exist="0" data="Sin coincidencias." id="0">Sin coincidencias.</a></div>'; } return $html;
关键改动说明
- SQL注入防护:把原
whereRaw的字符串拼接换成闭包内的参数绑定写法,避免恶意输入导致的注入风险 - 数据分组:用
->groupBy('id')将同一产品的所有库存记录分组,避免产品基础信息重复处理 - 安全输出:用Laravel的
e()函数对输出内容进行转义,防止XSS攻击 - 逻辑简化:移除冗余的第二次查询,直接基于第一次查询的结果生成HTML,提升性能
- 严谨判断:用
isEmpty()替代字符串对比$name != '[]',更符合集合操作的规范
内容的提问来源于stack exchange,提问作者user20389386
相关产品推荐
相关产品推荐

