使用 Filament 导入大型 Excel 文件

259 阅读3分钟

假设您的任务是从一所学校的在线申请系统导入数据。当学生提交申请时,数据存储在 Excel 文件中,需要将其导入到您的 Laravel 应用程序中。在本文中,我们将引导您完成使用 Filament 和 Laravel 有效处理大型 Excel 文件的过程。

Excel 导入包

对于此项目,我们将使用 Spatie\SimpleExcel 包从 Excel 文件中读取数据,并在后端进行所需的更改。此包还处理 CSV 文件。确保使用命令安装软件包: composer require spatie/simple-excel 。该软件包为复杂任务提供了许多有用的功能,但在本文中我们将重点介绍一个更简单的示例。

要开始数据处理任务,我们将在 Filament Application Resource 页面上创建一个操作按钮。此按钮 Student Applications Import 将处理导入过程。为简单起见,我们从 Resource 页面中删除了其余代码,如表单和表格。我们已通过 headerActions 将按钮放在表头中。

<?php

use App\Jobs\ApplicationsImportsJob;

class ApplicationResource extends Resource
{
    protected static ?string $model = Application::class;

    public static function form(Form $form): Form
    {}

	public static function table(Table $table): Table
	{
		return $table
            ->columns([])
            ->filters([])
            ->actions([])
            ->headerActions([
                Tables\Actions\Action::make('Import Applications')
                    ->form([
                        FileUpload::make('xlsxFile')
                            ->label('XLSX File')
                            ->disk('local')
                            ->required()
                            ->directory('imports'),
                    ])->action(function (array $data) {
                        if ($data['xlsxFile'] !== null) {
                            $filePath = $data['xlsxFile'];

                            ApplicationsImportsJob::dispatch($filePath);
                        }
                    })
            ]);
	}
}

以块的形式处理数据

接下来,我们需要创建一个作业来处理导入的数据。在我们的示例中,此作业名为 ApplicationsImportsJob。该作业将读取 Excel 文件,将数据分块为可管理的部分,并为每个块分派一个新作业。我们已将 chunk 每个 chunk 设置为 500 行,这在我们的项目中运行良好,但请随意尝试。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Spatie\SimpleExcel\SimpleExcelReader;

class ApplicationsImportsJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(public $filename)
    {
        //
    }

    public function handle(): void
    {
        SimpleExcelReader::create(storage_path('app/' . $this->filename))
            ->getRows()
            ->chunk(500)
            ->each(fn ($chunk) => ApplicationsImportChunkJob::dispatch($chunk, $this->filename));
    }
}

处理数据并保存

鉴于 Excel 文件中的数据量很大,因此将数据分解为可管理的块以进行高效处理非常重要。此作业将遍历 chunk 中的 500 行,并为每个学生创建一个新应用程序。它将保存 Excel 文件头中相应列名找到的姓名、电话和地址。在将作业标记为失败之前,将尝试该作业 5 次。

<?php

namespace App\Jobs;

use App\Models\Application;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ApplicationsImportChunkJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $tries = 5;

    /**
     * Create a new job instance.
     */
    public function __construct(public $chunk, public $file)
    {
        //
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        foreach ($this->chunk as $row) {
            Application::updateOrInsert([
                'name' => $row['name'],
                'phone' => $row['phone'],
                'address' => $row['address'],
            ]);
        }
    }
}

设置用于处理大型 Excel 文件的 Laravel 作业后,下一步是运行这些作业以开始数据处理。运行作业涉及执行分派作业的代码,并允许 Laravel 在后台处理它们,而不会减慢主应用程序的速度。

在 Laravel 中,队列用于异步处理耗时的任务。当任务被分派时,它被添加到队列中,等待队列工作线程处理。如果您想了解如何在本地设置队列,请阅读文章 Laravel 11 for Beginners: Using Queues。要处理队列中的作业,您需要运行队列工作程序: php artisan queue:work 。

必须正确配置队列以确保您的作业能够运行。在项目的  .env 部分中,将 QUEUE_CONNECTION 设置为 redis,以利用其快速的内存数据存储功能。为了清楚起见,这里有一个片段:

QUEUE_CONNECTION=redis
REDIS_DATABASE=0

如果您在同一服务器上运行多个站点,请将每个站点分配给不同的 Redis 数据库,以防止任何重叠。只需相应地增加 REDIS_DATABASE 数字(例如,0、1、2 等)。

通过执行这些步骤并使用 Laravel 和 Spatie\SimpleExcel 包,您可以在 Filament 应用程序上高效处理大型 Excel 文件。将数据分解为可管理的块并使用专用作业处理它们,可确保导入过程顺利有效。