使用Queue时如何获取Laravel Excel导入的验证失败信息
队列模式下Laravel Excel获取导入失败记录的解决方案
当导入类实现ShouldQueue接口后,SkipsFailures trait中存储的失败数据无法在AfterImport事件中获取——原因是队列任务在独立进程执行,内存中的临时数据会随进程结束释放,且序列化后的导入实例无法保留这些内存数据。
解决方法:持久化失败记录到数据库
通过将每条验证失败的记录存储到数据库,在AfterImport事件中从数据库查询获取失败数据,具体步骤如下:
- 创建失败记录的数据库表
生成迁移文件并执行:
Schema::create('import_failures', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); $table->string('import_type'); // 标记导入类,比如App\Imports\ProductImport $table->integer('row'); // 失败的行号 $table->json('errors'); // 错误信息数组 $table->string('import_id')->nullable(); // 唯一标识单次导入,区分同用户的不同导入任务 $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); });
- 创建对应模型
namespace App\Models; use Illuminate\Database\Eloquent\Model; class ImportFailure extends Model { protected $fillable = ['user_id', 'import_type', 'row', 'errors', 'import_id']; protected $casts = ['errors' => 'array']; }
- 修改导入类逻辑
在导入类中实现onFailure方法存储失败记录,同时在AfterImport事件中查询数据库获取失败数据:
use App\Models\ImportFailure; use Maatwebsite\Excel\Concerns\ToModel; use Maatwebsite\Excel\Concerns\WithValidation; use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Events\AfterImport; use Illuminate\Contracts\Queue\ShouldQueue; use Maatwebsite\Excel\Concerns\SkipsOnFailure; use Maatwebsite\Excel\Concerns\SkipsFailures; use Maatwebsite\Excel\Validators\Failure; use Maatwebsite\Excel\Concerns\WithBatchInserts; use Maatwebsite\Excel\Concerns\WithChunkReading; use Maatwebsite\Excel\Concerns\WithHeadingRow; class ProductImport implements ToModel, WithValidation, WithEvents, WithBatchInserts, WithChunkReading, WithHeadingRow, ShouldQueue, SkipsOnFailure { use SkipsFailures; protected $user; protected $importId; public function __construct($user) { $this->user = $user; $this->importId = uniqid('product_import_'); // 生成单次导入的唯一标识 } // 捕获验证失败,存储到数据库 public function onFailure(Failure ...$failures) { foreach ($failures as $failure) { ImportFailure::create([ 'user_id' => $this->user->id, 'import_type' => self::class, 'row' => $failure->row(), 'errors' => $failure->errors(), 'import_id' => $this->importId ]); } } public function registerEvents(): array { return [ AfterImport::class => function(AfterImport $event) { // 查询本次导入的所有失败记录 $failures = ImportFailure::where('user_id', $this->user->id) ->where('import_type', self::class) ->where('import_id', $this->importId) ->get(); // 统计成功导入数量(需根据实际导入逻辑实现,例如可在ToModel中计数并存入临时表或缓存) $importedCount = 0; // 替换为实际统计逻辑 $this->user->notify(new ImportCompleted($importedCount, $failures)); }, ]; } // 其他必要方法(ToModel、rules等)请自行补充 }
额外说明
- 如果不需要持久化失败记录,也可以使用Redis缓存临时存储失败数据,但数据库存储更可靠,不会因缓存过期或清理丢失数据。
- 成功导入数量的统计需要结合你的业务逻辑实现,例如在
ToModel方法中记录创建成功的模型数量,存入数据库或缓存后在AfterImport中读取。
内容的提问来源于stack exchange,提问作者Muzammil Riaz
相关产品推荐
相关产品推荐

