如何跳过大小为 website-excel 3.1 的空白行以在 Laravel 上进行模型导入

How to skip blank rows in maatwebsite-excel 3.1 for model-way import on Laravel

我正在 laravel 项目中使用 maatwebsite-exvel 3.1 从文件上传方法导入 excel 文件。这是我的 StudentsImport class.

public function model(array $row)
{
    return new Student([
        'school_uuid' => Auth::user()->school_uuid,
        'cardid'     => $row[0],
        'prefix'    => $row[1], 
        'name'    => $row[2], 
        'lastname'    => $row[3], 
        'dob'    => $row[4], 
        'address'    => $row[5], 
        'phone'    => $row[6], 
    ]);
}

下面是控制器。

 Excel::import(new StudentsImport,  $request->file('file'));

代码工作正常。我可以将 excel 的数据导入数据库,但也导入了空白行。我想 filter/validate 在放入数据库之前跳过这些空白。对此有任何建议或指导,将不胜感激,谢谢

根据 package documentation,支持使用 Laravel 的验证来防止插入无效行。

要使用它,请在您的导入器上实现 WithValidation 接口 class 并添加一个 rules() 方法,return 应使用验证规则来确保该行有效。

public function rules(): array
{
    return [
        '0' => 'required|string',
        '1' => 'required|string',
        '2' => 'required|numeric',
        // so on
    ];
}

Instead of passing the file directly to this function directly, create a function to filter the data having the blank fields something like below:

function returnNotEmpty($array){
    return array_filter($array, function($i){
        return !empty($i);
    });
}

Use the function like this:

Excel::import(new StudentsImport,  $this->returnNotEmpty($request->file('file'))); 

请注意,rules() 方法不会跳过空行,但会抛出一个错误,导致导入失败并回滚已验证的行。

但是我发现文档中存在此功能,只需将其实施到您的导入 class:"Maatwebsite\Excel\Concerns\SkipsOnFailure"

例如这样:

class UsersImport implements ToModel, WithValidation, SkipsOnFailure {
    // Your import class
}

然后在导入 class 中定义一个方法来处理错误:

/**
 * @param Failure[] $failures
 */
public function onFailure(Failure ...$failures)
{
    // Handle the failures how you'd like.
}

现在 rules() 方法不会再在空行上抛出错误,您可以静默处理错误,您仍然应该使用 rules() 方法,只是因为您需要它抛出错误现在可以由您处理的错误,也许您可​​以将它们记录到一个文件中,或者您可以正常进行。

最终您将能够收集所有错误,这里是文档中的示例:

$import = new UsersImport();
$import->import('users.xlsx');

dd($import->errors());

所以,现在您可以静静地捕获错误并最终 return 满足您的要求,您甚至可以 return 像这样的详细信息:

foreach ($import->failures() as $failure) {
   $failure->row(); // row that went wrong
   $failure->attribute(); // either heading key (if using heading row concern) or column index
   $failure->errors(); // Actual error messages from Laravel validator
   $failure->values(); // The values of the row that has failed.
}

这不是复制粘贴 material 好的,我只是解释了如何根据文档中给出的示例访问错误,我将由您处理这些数据。

这是我找到所有这些信息的文档的 link:https://docs.laravel-excel.com/3.1/imports/validation.html#skipping-failures

您还可以根据您所做的验证跳过行。如果您的其中一个请求未涵盖

,您可以在模型中输入一个 return null

public function model(array $row)
{
    if ($row[2] === null || $row[3] === null ...) {
      return null;
    }
    return new Student([
        'school_uuid' => Auth::user()->school_uuid,
        'cardid'     => $row[0],
        'prefix'    => $row[1], 
        'name'    => $row[2], 
        'lastname'    => $row[3], 
        'dob'    => $row[4], 
        'address'    => $row[5], 
        'phone'    => $row[6], 
    ]);
}

并且您还可以在必填字段的规则中添加验证规则“required_with”,如果在其他字段中存在验证将丢弃的内容,如果不存在则跳过该行 return在模型区中为空。

public function rules(): array
{
    return [
        '0' => 'required_with:*.1,*.2,...', // here to be the others rows if they are populate to trow an validation error, 
        '1' => 'string|nullable|required_with:*.1,*.2,...',',
        // so on
    ];
}

尝试使用 ToCollection 然后尝试 if($row->filter()->isNotEmpty())

public function collection(Collection $rows)
   {
      foreach($rows as $row) {
        if($row->filter()->isNotEmpty()){
            // you logic can go here
           }
        }   
   }

别忘了包括 use Maatwebsite\Excel\Concerns\ToCollection; 它对我来说很完美

可以找到参考 here

您必须创建一个集合并将其与过滤器而不是数组一起使用。首先 trim 作为 space 的值不为空。然后在过滤空行后使其成为一个集合。

    public function collection(Collection $rows)
    {
    foreach($rows as $row) {
        $em1=trim($row[0]);           

        $em = collect([$em1]);
       

        if($em->filter()->isNotEmpty()){
            // you logic can go here

            $user = Content::create([
                'email'     => $row[0],
                'phone'    => $row[1],
                'first_name'    => $row[2],
                'last_name'    => $row[3],
                'zip_code'    => $row[4],
                'address'    => $row[5],
            ]);
        }
    }
}