1

I'm trying to import new users to the system, using Maatwebsite\Excel package. Default package concern ToModel is not suitable for me, because I need to assign default role for each imported user and to send an email for him/her. I am trying to use ToCollection concern, as it is described in the last chapter of this documentation page: https://docs.laravel-excel.com/3.1/imports/validation.html . The problem is that I can't validate the contents of Excel file properly: error messages don't appear at all. How can I validate the contents of Excel file properly, when I use Maatwebsite\Excel package and it's ToCollection concern?

Maybe do you know different approaches how to set a role for the user and send email after import of each user?

<?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',
        ];
    }

}

Edit: this question was marked as "possible duplicate", but I doubt about it. I tried to write such code in UsersImport class, collection method:

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

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

And it does not work at all. I think I know how to write validators in Laravel, and I expect I made very simple mistake somewhere.

1

1 Answer 1

6

Finally, I have solved this problem on myself:

<?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'),
        ];
    }

}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.