Master Multi-Sheet Imports with Laravel Excel
1
through N
will be handled the exact same way as sheet 0
. We can specify how multiple sheets are handled, and we will in this
.
Importing Multiple Sheets with the Same Format
We’ll use our user mock data from the previous article and create a couple of excel sheets to store the user data. We now have user_data_1
and user_data_2
sheets. Each sheet stores the exact same type of data, both with headers (first_name
, last_name
, email
, password
) and 19 rows of user data. The MOCK_DATA.xlsx
file is placed in our public
directory.
php artisan make:import MultiSheetSingleFormatImport --model=User
<?php
namespace App\Imports;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class MultiSheetSingleFormatImport implements ToModel, WithHeadingRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new User([
'name' => $row['first_name'] . " " . $row['last_name'],
'email' => $row['email'],
'password' => Hash::make($row['password']),
]);
}
}
We now need our Controller. We made the controller in our previous article, so we’ll continue to use our UserController
and add our method so that it can call our MultiSheetSingleFormatImport
importer.
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Imports\UsersImport; use Maatwebsite\Excel\Facades\Excel; class UserController extends Controller { //... public function import_multiple_single_format() { Excel::import( new MultiSheetSingleFormatImport, 'MOCK_DATA.xlsx' ); return redirect('/')->with('success', 'Users Import Successfully!'); } }
All we need now is our route and we’ll be good to start the test.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
//...
Route::get(
'/import-multiple-sheets-single-format',
[UserController::class, 'import_multiple_single_format']
);
mysql> select * from users;
+----+------------------------+---------------------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| id | name | email | email_verified_at | password | remember_token | created_at | updated_at |
+----+------------------------+---------------------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| 1 | Patrick Spinnace | pspinnace0@nsw.gov.au | NULL | $2y$10$FhrBy9t3YyAU1N3ejDYgluhDGrGdUOwtftarhBkoiLd9H8oSEFEFm | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 2 | Verla Petersen | vpetersen1@edublogs.org | NULL | $2y$10$QD1zt7ZpMJCYkEDUN0e3Cu/MA7NEoWDr7pGzylvO69jLtWCZIflMC | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 3 | Alicea Hobbema | ahobbema2@unicef.org | NULL | $2y$10$gcpiaqZ6tdj49QXNfaZsxuPnE8egwONNv2iJ4CgnZSzpIob.9mT4O | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 4 | Roma Mapstone | rmapstone3@sfgate.com | NULL | $2y$10$gp2E.KFqeZu9AIYB34R8wequuH8WheeDOmWmQjW2grM8N1K0vGHYW | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 5 | Karol Stucke | kstucke4@vk.com | NULL | $2y$10$D5XaM3qg0XcJMibZHZ.baOg.DJkpXDw/y6TCMh.6bPACk7dxHhkSe | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 6 | Alick Isles | aisles5@paypal.com | NULL | $2y$10$XOU0T1fKY1bRfmOTxO.eT.gGTVarSeu5.Ls/tGqhKloYIQBDGzRX. | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 7 | Brandtr Kenwell | bkenwell6@xinhuanet.com | NULL | $2y$10$JVknCCTH4ARR.nsHKhn/q.IaX3AjiUgHLy99JQ158esKY9QIiCFtm | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 8 | Sabine Ewer | sewer7@sakura.ne.jp | NULL | $2y$10$KmM8ngj25U6YRt6eHgVGr.toDfuH/zz.TXBzUEKV9XWxUrdwQenH. | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 9 | Maude Harmeston | mharmeston8@ezinearticles.com | NULL | $2y$10$kzkmRV/kY10vCtDQu1q1a.GkEUNtx17dUAx8QnQFysKBMFzs3Kl36 | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 10 | Hillel Gogin | hgogin9@bravesites.com | NULL | $2y$10$Ki1/PyYDfsQ5R9VggwAR1uGu4RSL09VQHIWWBR3YW3oFA0VHEIgri | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 11 | Mohandis Drydale | mdrydalea@patch.com | NULL | $2y$10$NHuSBQmT1T38YlsR5M4ISeK6IWa2pQGKeXqXf5HTm65pvu17KgNzG | NULL | 2022-10-02 12:13:01 | 2022-10-02 12:13:01 |
| 12 | Lil Caff | lcaffb@squarespace.com | NULL | $2y$10$QBWSk.Jacf14CHqenHXsROnmz7K0/2NTmZKPrH7fwX.dIYPQ4rKGu | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 13 | Robinette Chamberlayne | rchamberlaynec@amazon.de | NULL | $2y$10$soF3Ta2xV7aP0yu1Zk.cn.kFTDJtuFGCPCoO322BdFoGD4eLgZGjy | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 14 | Stinky Very | sveryd@google.ru | NULL | $2y$10$5EG1plVF2qHSLYCaH7KHxO/8rWw5P2Qw0JDsMkJTA65H0WTyUGPD6 | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 15 | Tressa Dubique | tdubiquee@istockphoto.com | NULL | $2y$10$UpdQd/Wti5Ztzm4IOb8zpuKjCxKoNqtOh6dbWdMV9JlxsCJtBmqmm | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 16 | Bernie Dubarry | bdubarryf@gravatar.com | NULL | $2y$10$YHfLtJbDPlKZKx9WWaet4u4gVuodd2FDpzEpqhI5jiDimj4rLRTIW | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 17 | Orville Dauber | odauberg@squarespace.com | NULL | $2y$10$cIyPRCy3to0PfnVy9emjL.zDSpSuT/1YO2yzCeUJWWy6PoEPQBfjO | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 18 | Oran Freckelton | ofreckeltonh@furl.net | NULL | $2y$10$QsFogzKmpX3mXqAD30sAK.fWT6fZ9LdJtWFLA0K9aXst/G7zYv7um | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 19 | Kelsy Hilliam | khilliami@icio.us | NULL | $2y$10$UGDET/OYXOLkA8osxPPl8eF63SPzheY9hZZwpnujTPnJKYzMYj0aG | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 20 | Theresita Penelli | tpenellij@amazon.com | NULL | $2y$10$vfq7nC4YGZZgrMa1xrfon.M2uibTKmoG6k08h25ZA0NBzz58QYuL2 | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 21 | Reeva Vivien | rvivienk@nih.gov | NULL | $2y$10$Wa4mrYnlTGT58BjLyoWciuQ.S1L6QMMxghgUCs7riLyd1650ANMMa | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 22 | Roxine Lathe | rlathel@cbsnews.com | NULL | $2y$10$nOX6AzoEvp4INss2gXGzd.WfKB.OcubI.a5wAxt7xqo8W0Te5CG12 | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 23 | Ernst Spiby | espibym@google.com | NULL | $2y$10$LHbpL0ZYYkqrK08YgysOVupdsOSRNhFa1p5kjXoED6CefHGfupa.e | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 24 | Bowie Willerton | bwillertonn@acquirethisname.com | NULL | $2y$10$NrKd9DXZa2HwkCS9A4JwpeZYvukIbsP8uGmshH7HF7/Q1Rt5nQNW. | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 25 | Tasha Hapke | thapkeo@booking.com | NULL | $2y$10$iCkjlY6pOlA3PLyIwA2vxudPV6HV7ev8v/VgyEv.qITN/eT9lkXJS | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 26 | Blair Filchagin | bfilchaginp@alexa.com | NULL | $2y$10$GKD3vUpl1cS8sLzl9CmRxeS3TzzGrvhCZvnLgroVclGOAekUO6Bp. | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 27 | Roda Costigan | rcostiganq@360.cn | NULL | $2y$10$rYzMYxhG6cdO87LNkck8IulfY3PGn8Isvw3QSrZClLxq1UEmHX.Qq | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 28 | Twila Mc Combe | tmccomber@freewebs.com | NULL | $2y$10$8agoainCcmEUVkeReuMPEeAP8vjcqa6VkRerNSOPOljExnBDT4AmC | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 29 | Maressa Lancaster | mlancasters@nifty.com | NULL | $2y$10$lORYemSZqhtCnXLafSiHV.GGTrZfRKALAZHnnVG/6SF1tpFB7GLfe | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 30 | Domini Pietzke | dpietzket@cargocollective.com | NULL | $2y$10$1KxGb5tRfKpmBqgSrm1dj.tC.1n7u7rzMRmVOw1a/hrxwjIkxHN4. | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 31 | Arlana Weatherhead | aweatherheadu@nsw.gov.au | NULL | $2y$10$N3ecZcExthMn25hXy.1Yh.RQCaN.NaOT70h3jQn6NIpAKUMcln/V2 | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 32 | Christean Grastye | cgrastyev@ezinearticles.com | NULL | $2y$10$XPQFlMf5PQ.ejpC1gXg1M.y7fus7X6e6wHcmIHPS6xhNpyN.tNdMS | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 33 | Siegfried Chawkley | schawkleyw@wsj.com | NULL | $2y$10$ZQjYQTEm1WEuij68QqhnZeUsKqkL1o.vZk4YoxmBjItoAZHM4Axma | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 34 | Loralyn Fibbens | lfibbensx@vinaora.com | NULL | $2y$10$ptR/JxXRAlF0rr7kJ78KAOLlR95rG0E3s0rqXqMaxMMOu8d3dWfO2 | NULL | 2022-10-02 12:13:02 | 2022-10-02 12:13:02 |
| 35 | Uriel Janusik | ujanusiky@delicious.com | NULL | $2y$10$h1snThHuCHionop8nm6RC.b6/.AZqzXG3GUFXKXc5saSgsywV/U.. | NULL | 2022-10-02 12:13:03 | 2022-10-02 12:13:03 |
| 36 | Kennie Skaife | kskaifez@webnode.com | NULL | $2y$10$XsWQl41e0IzHavsMs8yH5ejoY.bFgeHlYHNa.ATjSf4S/VTcpFJKG | NULL | 2022-10-02 12:13:03 | 2022-10-02 12:13:03 |
| 37 | Dill Oakshott | doakshott10@google.co.jp | NULL | $2y$10$cbtilNygQyymXcWFSXuduOiwelmqQHRBvAJ0Il.SX6aQkkGDH9QQy | NULL | 2022-10-02 12:13:03 | 2022-10-02 12:13:03 |
| 38 | Jens Dibdin | jdibdin11@stanford.edu | NULL | $2y$10$2IpqblagpnCHhaWcvrrLqeaDUbz4gJQbSjp7hLh6Z2oY8zMeDnxey | NULL | 2022-10-02 12:13:03 | 2022-10-02 12:13:03 |
+----+------------------------+---------------------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
38 rows in set (0.00 sec)
mysql>
We get the result that we were expecting. Laravel-Excel reads the data from the first sheet and imports the 19 rows. It skips the first row since we added the WithHeadingRow
concern. Once it completes the import, it then goes to the next sheet. It again assumes that the first row is the header and reads the 19 rows from sheet 2.
Importing Multiple Sheets with Different Formats
What if each sheet had different formats? For example, let’s say that sheet 1 had the following header:
first_name | last_name | email | password
email | password | first_name | last_name | phone_number | dob
Will our importer still work? The answer is…yes! Our importer is using the WithHeadingRow
concern, so it knows which column to select the data from.
What if sheet 2 had different names in the header?
email_address | pass | name_first | name_last
php artisan make:import MultiSheetSelector
php artisan make:import FirstSheetImporter --model=User
php artisan make:import SecondSheetImporter --model=User
Let’s configure our FirstSheetImporter
and SecondSheetImporter
first.
<?php
namespace App\Imports;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class FirstSheetImporter implements ToModel, WithHeadingRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new User([
'name' => $row['first_name'] . " " . $row['last_name'],
'email' => $row['email'],
'password' => Hash::make($row['password']),
]);
}
}
<?php
namespace App\Imports;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class SecondSheetImporter implements ToModel, WithHeadingRow
{
/**
* @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']),
]);
}
}
Notice that we specified different keys for our $row
to match the header for each sheet.
Next, we’ll need to implement our multi-sheet selector. Laravel-Excel requires that the WithMultipleSheets
concern is implemented along with the sheets()
method.
<?php
namespace App\Imports;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class MultiSheetSelector implements WithMultipleSheets
{
public function sheets(): array
{
return [
new FirstSheetImporter(),
new SecondSheetImporter(),
];
}
}
The sheets()
method returns an array of importers. The order is important. We know that the FirstSheetImporter
is linked to the first Excel sheet and the SecondSheetImporter
is linked to the second Excel sheet.
We can also remove the collection()
method and ToCollection
concern since we’re not going to be processing anything with this class. It’s just there to select between the two imports.
We just need to add a method to our UserController
and create a route that calls that method and we’ll be ready to test.
<?php
namespace App\Http\Controllers;
use App\Imports\MultiSheetSelector;
use App\Imports\MultiSheetSingleFormatImport;
use Illuminate\Http\Request;
use App\Imports\UsersImport;
use Maatwebsite\Excel\Facades\Excel;
class UserController extends Controller
{
//...
public function import_multiple_different_formats()
{
Excel::import(
new MultiSheetSelector, 'MOCK_DATA_2.xlsx'
);
return redirect('/')->with('success', 'Users Import Successfully!');
}
}
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
//...
Route::get(
'/import-multiple-sheets-different-formats',
[UserController::class, 'import_multiple_different_formats']
);
Time for testing…and success. We were able to import both sheets with different headers. You can imagine that if sheet 2 needed some additional cleanup, this could be done in the SecondSheetImporter
.
Explicitly Stating Which Sheets to Import
There are all sort of possibilities and one of those is that there are a few sheets that you want to import, but others that you don’t want to import. Let’s pretend that we have 5 sheets inside of our Excel document.
user_data_1
user_data_1_salary
user_data_2
user_data_2_salary
salary_totals
We only want to extract the data out of the user_data_1
and user_data_2
sheets. However, if we use our existing importer, it will attempt to import data from user_data_1
and user_data_1_salary
.
The only modification that we’ll need to specify is which sheets to use. This can be done with the sheet number or the sheet name. The numbering system starts at 0
.
<?php
namespace App\Imports;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class MultiSheetSpecificSelectorByIndex implements WithMultipleSheets
{
public function sheets(): array
{
return [
0 => new FirstSheetImporter,
2 => new SecondSheetImporter,
];
}
}
We can also use the sheet name if we wanted to by replacing the index with the sheet name.
<?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,
];
}
}
Laravel Series
Continue your Laravel Learning.
Effortless Data Handling with Laravel Excel
Laravel Excel – P1: Setup And Basic Import
Kickstart your journey with Laravel Excel! This guide walks you through the setup process and demonstrates how to perform a basic data import.
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.