在基于 Filament 的应用程序中从 excel 文件导入数据

0 阅读3分钟

Configuration 配置

,由于我们将从 Excel 文件导入数据,我们还需要一个 Excel 文件,该文件应包含基于导入类型的数据,在这种情况下,我们的 Excel 文件包含学生的数据,包括姓名、电子邮件、地址、电话号码和班级/部分数据。

实现导入功能

让我们从定义 import 类开始,我们将在其中定义我们想要如何执行导入,Laravel Excel 提供了不同的方法来实现这一点,通过 Collection 或 from Model,在这种情况下,我们将使用 model 方法。文档可在此处找到

让我们从定义 Import 类开始,将这个类命名为 StudentsImport

php artisan make:import StudentsImport

这将在 app/Imports 中创建一个新文件,让我们继续填充我们的模型方法,我们还将实现 WithHeadingRow,它允许我们在从 Excel 访问数据时使用标题名称,以及 SkipsEmptyRows 特征,它基本上会跳过任何空行。

最终的模型方法如下所示:

public function model(array $row)
    {
        return new Student([
            'section_id' => self::getSectionId($row['class'], $row['section']),
            'class_id' => self::getClassId($row['class']),
            'name' => $row['name'],
            'email' => $row['email'],
            'address' => $row['address'],
            'phone_number' => $row['phone_number'],
        ]);
    }

如果我们仔细研究该方法,定义了两个静态方法,称为 getSectionId 和 getClassId,这些方法是必需的,因为用户将传递 Class name 和 Section name,我们需要找到它们各自的 ID,对于 Section,我们也传递了 Class 数据,因为每个 Section 都属于一个 Class,我们需要找到相对于该 Class 的 Section。

最终的 StudentsImport 类如下所示:

<?php

namespace App\Imports;

use App\Models\Classes;
use App\Models\Section;
use App\Models\Student;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class StudentsImport implements ToModel, WithHeadingRow, SkipsEmptyRows
{
    public function model(array $row)
    {
        return new Student([
            'section_id' => self::getSectionId($row['class'], $row['section']),
            'class_id' => self::getClassId($row['class']),
            'name' => $row['name'],
            'email' => $row['email'],
            'address' => $row['address'],
            'phone_number' => $row['phone_number'],
        ]);
    }

    public static function getClassId($class)
    {
        $class = Classes::where('name', $class)->first();

        return $class->id;
    }

    public static function getSectionId($class, $section)
    {
        $class_id = self::getClassId($class);

        $section_model = Section::where([
            'class_id' => $class_id,
            'name' => $section
        ])->first();

        return $section_model->id;
    }
}

定义 filament 操作

让我们继续定义我们的 Custom Action,在哪里定义这个动作取决于用例。在本例中,我们将在 Students Index (学生索引) 页面上定义此操作。 让我们给它起个名字 importStudents,将标签定义为 Import Students 以及一个危险的颜色,在 form 方法中,我们将传递 FileUpload 组件并将表单字段命名为 attachment 目前,操作如下所示:

 Action::make('importStudents')
                ->label('Import Students')
                ->color('danger')
                ->form([
                    FileUpload::make('attachment'),
                ])

对于操作方法,我们将从存储文件夹中获取文件,并确保将存储文件夹链接到公共文件夹,这样我们就可以公开访问文件。

可以使用以下命令链接存储:

php artisan storage:link

获取文件后,我们会将其传递给我们之前定义的 StudentsImport 类,这将负责从数据库中获取 Class/Section ID,并使用单个插入查询将所有数据插入数据库。

我们还将使用 Filament 的 Notification 包通知用户有关导入的信息。

最终操作如下所示:

Action::make('importStudents')
                ->label('Import Students')
                ->color('danger')
                ->form([
                    FileUpload::make('attachment'),
                ])
                ->action(function (array $data) {
                    // $data is an array which consists of all the form data
                    $file = public_path("storage/" . $data['attachment']);

                    Excel::import(new StudentsImport, $file);

                    Notification::make()
                        ->success()
                        ->title('Students Imported')
                        ->body('Students data imported successfully.')
                        ->send();
                }),