当我使用 Maatwebsite\Excel 包并且它是 ToCollection 问题时,如何正确验证 Excel 文件的内容?

How to validate content of Excel file properly, when I use Maatwebsite\Excel package and it's ToCollection concern?

我正在尝试使用 Maatwebsite\Excel 包将新用户导入系统。默认包关注 ToModel 不适合我,因为我需要为每个导入的用户分配默认角色并为 him/her 发送电子邮件。我正在尝试使用 ToCollection 关注点,如本文档页面的最后一章所述: https://docs.laravel-excel.com/3.1/imports/validation.html 。问题是我无法正确验证 Excel 文件的内容:根本不会出现错误消息。当我使用 Maatwebsite\Excel 包并且它是 ToCollection 问题时,如何正确验证 Excel 文件的内容?

也许您知道如何为用户设置角色并在导入每个用户后发送电子邮件的不同方法?

<?php

/* My controller and action which calls import of users: */


/* used namespaces go here */

class ProfileController extends Controller
{
    public function updateClient(UserClientRequest $request)
    {
        /* Client entity is being updated here, instead of this comment */

        // here I try to import users from *.xls file:
        $errors = [];
        if ($request->hasFile('file_to_import_users')) {
            $usersImport = new UsersImport($client->id);
            $usersImport->import($request->file('file_to_import_users'));
            foreach ($usersImport->failures() as $failure) {
                foreach ($failure->errors() as $error) {
                    $errors[] = $error;
                }
            }
        }

        return redirect()->route('profile.view_client')
            ->with('message', trans('client.updated'))
            ->with('validation_errors', $errors);
    }
}

/* My current UsersImport class: */

namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\ToCollection;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UsersImport implements WithValidation, SkipsOnFailure, ToCollection
{
    use Importable, SkipsFailures;

    private $clientId;

    public function __construct($clientId)
    {
        $this->clientId = $clientId;
    }


    public function collection(Collection $rows)
    {
        /* this does not work properly: */
        Validator::make($rows->toArray(), $this->rules())->validate();


        /* maybe I need to do something like this: */
        if ($validator->fails()) {
            return redirect()->route('profile.view_client')->with('validation_errors', $validator);
        }

        foreach ($rows as $row) {
            $user = new User();
            $user->first_name = $row[0];
            $user->last_name = $row[1];
            $user->email = $row[2];
            $user->password = Hash::make(Str::random(16));
            $user->client_id = $this->clientId;
            $user->save();

            DB::table('model_has_roles')->insert([
                'role_id' => 4,
                'model_type' => 'App\User',
                'model_id' => $user->id
            ]);
        }
    }

    public function rules(): array
    {
        return [
            '*.0' => 'required|max:255',
            '*.1' => 'required|max:255',
            '*.2' => 'required|unique:users,email|email|max:255',
        ];
    }

}

编辑:这个问题被标记为"possible duplicate",但我对此表示怀疑。我试着在UsersImportclass中写了这样的代码,采集方法:

    $validator = Validator::make($rows->toArray(), $this->rules());

    if ($validator->fails()) {
        return redirect()->route('profile.view_client')
            ->with('validation_errors', $validator->errors());
    }

而且根本不起作用。我想我知道如何在 Laravel 中编写验证器,我希望我在某处犯了一个非常简单的错误。

终于自己解决了这个问题:

<?php

class ProfileController extends Controller
{

    public function updateClient(UserClientRequest $request)
    {
        if (!Auth::user()->hasRole('super-admin') && !Auth::user()->hasRole('admin')) {
            return redirect()->route('profile');
        }

        $client = Auth::user()->client;
        $client->name = $request->name;
        $client->type = $request->type;
        $client->save();

        $errors = [];

        if ($request->hasFile('file_to_import_companies')) {
            $companiesImport = new CompaniesImport($client->id);
            $companiesImport->import($request->file('file_to_import_companies'));
            foreach ($companiesImport->failures() as $failure) {
                foreach ($failure->errors() as $error) {
                    $errors[] = $error;
                }
            }
        }

        // this was changed:
        if ($request->hasFile('file_to_import_users')) {
            $usersImport = new UsersImport($client->id);
            $usersImport->import($request->file('file_to_import_users'));

            // I made function getErrors on UsersImport class:
            $usersValidationErrors = $usersImport->getErrors();
        } else {
            $usersValidationErrors = [];
        }

        $errors = array_merge($errors, $usersValidationErrors);

        return redirect()->route('profile.view_client')
            ->with('message', trans('client.updated'))
            ->with('validation_errors', $errors);
    }
}


/* Here is my UsersImport class: */

namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Validators\Failure;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UsersImport implements WithValidation, SkipsOnFailure, ToCollection
{
    use Importable, SkipsFailures;

    private $clientId;
    private $errors = []; // array to accumulate errors

    public function __construct($clientId)
    {
        $this->clientId = $clientId;
    }

    public function collection(Collection $rows)
    {
        $rows = $rows->toArray();

        // iterating each row and validating it:
        foreach ($rows as $key=>$row) {
            $validator = Validator::make($row, $this->rules(), $this->validationMessages());
            if ($validator->fails()) {
                foreach ($validator->errors()->messages() as $messages) {
                    foreach ($messages as $error) {
                        // accumulating errors:
                        $this->errors[] = $error;
                    }
                }
            } else {
                $user = new User();
                $user->first_name = $row[0];
                $user->last_name = $row[1];
                $user->email = $row[2];
                $user->password = Hash::make(Str::random(16));
                $user->client_id = $this->clientId;
                $user->locale = 'no';
                $user->save();

                DB::table('model_has_roles')->insert([
                    'role_id' => 4,
                    'model_type' => 'App\User',
                    'model_id' => $user->id
                ]);
            }
        }
    }

    // this function returns all validation errors after import:
    public function getErrors()
    {
        return $this->errors;
    }

    public function rules(): array
    {
        return [
            '0' => 'required|max:255',
            '1' => 'required|max:255',
            '2' => 'required|unique:users,email|email|max:255',
        ];
    }

    public function validationMessages()
    {
        return [
            '0.required' => trans('user.first_name_is_required'),
            '1.required' => trans('user.last_name_is_required'),
            '2.required' => trans('user.email_is_required'),
            '2.unique' => trans('user.email_must_be_unique'),
            '2.email' => trans('user.email_must_be_valid'),
        ];
    }

}