Laravel-Excel — P3: Importing Multiple Sheets and Handling Unknown Defined Sheets

Effortlessly handle multi-sheet imports in Laravel-Excel

Ideally you receive the Excel sheet properly formatted and it’s a piece of cake when it comes to creating your import script, but when is that ever the case? You always have quirks and you have to devise methods to handle those. Luckily, Laravel-Excel has thought of quite a few of those quirks and provides great ways to handle them. This is a continuation of the Multiple Sheets Basics.

https://blog.devgenius.io/laravel-excel-p2-importing-multiple-sheets-basics-2d20994770b

Skipping Unknown Sheets

When you receive an Excel workbook with multiple sheets, you may devise for import functionality for each sheet, but what happens if you need to know when one of those sheets is missing? Do you want the entire import to crash or do you want to handle it more elegantly and just get a notification that the sheet that you’re expecting is not there?

Laravel-Excel has the SkipsUnknownSheets concern that allows you to implement the onUnknownSheet method. The $sheetName is passed to the method so that you can log it.

For this example, our workbook is going to contain the following sheets.

  • user_data_1
  • user_data_2

Our importer is going to recognize those and be able to import them.

<?php

namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class MultiSheetSpecificSelectorByName implements WithMultipleSheets
{
    public function sheets(): array
    {
        return [
            'user_data_1' => new FirstSheetImporter,
            'user_data_2' => new SecondSheetImporter,
        ];
    }
}

To implement the logging functionality for sheets that are defined, but missing, we need to implement the SkipsUnknownSheets concern.

<?php

namespace App\Imports;

use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class MultiSheetSkipUnknownSheet implements WithMultipleSheets, SkipsUnknownSheets
{
    public function sheets(): array
    {
        return [
            'user_data_1' => new FirstSheetImporter,
            'user_data_2' => new SecondSheetImporter,
            'user_data_3' => new SecondSheetImporter,
        ];
    }

    public function onUnknownSheet($sheetName)
    {
        Log::error("Sheet " . $sheetName . " was skipped from import.");
    }
}

In this case, we have a user_data_3 sheet defined, but in our workbook, we don’t have it listed. Our onUnknownSheet method will recognize and log that error. Let’s create our route and add a method to our UserController class and then run that import and check the log file in app/storage/logs/laravel.log.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

//...

Route::get(
    '/import-multiple-sheets-skip-unknown',
    [UserController::class, 'import_multiple_sheet_skip_unknown']
);
<?php

namespace App\Http\Controllers;

//...
use App\Imports\MultiSheetSkipUnknownSheet;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;

class UserController extends Controller
{
    // ...

    public function import_multiple_sheet_skip_unknown() {
        Excel::import(
            new MultiSheetSkipUnknownSheet, 'mock_data/MOCK_DATA_3.xlsx'
        );

        return redirect('/')->with('success', 'Users Import Successfully!');
    }
}

After we call the route, we get the following error logged, which is what we expected since our Excel workbook does not contain the user_data_3 sheet.

[2022-10-03 20:08:21] local.ERROR: Sheet user_data_3 was skipped from import.

Skipping Specific Sheets and Failing Others

What if some sheets are more important than others? In other words, you want to stop code execution when certain sheets fail, and silently handle other less important sheets. Laravel-Excel has you covered again.

In the previous example, we implemented the SkipsUnknownSheets concern on the Multi-Sheet Selector class, but this time we’ll implement it on a specific Import.

We’ll create a new Multi-Sheet Selector. This time, it will not have the SkipsUnknownSheets concern.

<?php

namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class MultiSheetSkipUnknownSheetTwo implements WithMultipleSheets
{
    public function sheets(): array
    {
        return [
            'user_data_1' => new FirstSheetImporter,
            'user_data_2' => new SecondSheetImporter,
            'user_data_3' => new ThirdSheetImporter,
        ];
    }

}

We’ll also need to create our ThirdSheetImporter class. This importer will have the SkipsUnknownSheets concern. The FirstSheetImporter and the SecondSheetImporter will not.

<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class ThirdSheetImporter implements ToModel, WithHeadingRow, SkipsUnknownSheets
{
    /**
    * @param array $row
    *
    * @return \Illuminate\Database\Eloquent\Model|null
    */
    public function model(array $row)
    {
        return new User([
            'name'     => $row['name_first'] . " " . $row['name_last'],
            'email'    => $row['email_address'],
            'password' => Hash::make($row['pass']),
        ]);
    }

    public function onUnknownSheet($sheetName)
    {
        Log::error("Sheet " . $sheetName . " was skipped from import.");
    }
}

If we run this code now, and user_data_1 or user_data_2 sheets are missing, the code will break. If user_data_3 is missing, Laravel-Excel will handle it with the onUnknownSheet method and Log it to the file. Time to create a new route, method in our UserController, and test.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

//...

Route::get(
    '/import-multiple-sheets-skip-unknown-sometimes',
    [UserController::class, 'import_multiple_sheet_skip_unknown_sometimes']
);
<?php

namespace App\Http\Controllers;

//...
use App\Imports\MultiSheetSkipUnknownSheetTwo;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;

class UserController extends Controller
{
    //...

    public function import_multiple_sheet_skip_unknown_sometimes() {
        Excel::import(
            new MultiSheetSkipUnknownSheetTwo, 'mock_data/MOCK_DATA_3.xlsx'
        );

        return redirect('/')->with('success', 'Users Import Successfully!');
    }
}

We’ll get the same error message if we omit user_data_3.

[2022-10-03 20:44:31] local.ERROR: Sheet user_data_3 was skipped from import.

If user_data_1 is missing, we get the out of bounds exception thrown.

Laravel Series

Continue your Laravel Learning.

Laravel-Excel — P2: Importing Multiple Sheets Basics

Master Multi-Sheet Imports with Laravel Excel

Laravel Excel – P2: Importing Multiple Sheets Basics

Discover how to efficiently import multiple sheets using Laravel Excel. Manage complex data with ease and streamline your workflows.

Laravel-Excel — P3: Importing Multiple Sheets and Handling Unknown Defined Sheets

Effortlessly handle multi-sheet imports in Laravel-Excel

Laravel-Excel — P3: Importing Multiple Sheets & Handling Unknown Sheets

In part three of our Laravel-Excel series, discover how to import multiple sheets while gracefully handling unknown or undefined sheets. Learn practical techniques for adapting your import process, ensuring data accuracy, and preventing import errors.

Laravel-Excel — P4: Importing Multiple Sheets Conditional Loading

Streamline multi-sheet imports with advanced conditional loading

Laravel-Excel — P4: Importing Multiple Sheets Conditional Loading

In part four of our Laravel-Excel series, explore advanced techniques for importing multiple sheets with conditional loading. Learn how to selectively process data based on custom criteria, reducing resource usage, and optimizing overall performance.

Leave a Reply