laravel-excel maatwebsite excel 導入的中文文檔

項目裏需要導入了,正好 3.1 版本,也支持導入了,補充下 excel 導入的翻譯文檔。(工作比較忙,大概過了一遍,可能有不少錯誤的地方)

1.5分鐘快速入門
	在 app/Import 創建一個導入類
		php artisan make:import UsersImport --model=User

	會在 app/Imports 發現新創建的文件:
		.
		├── app
		│   ├── Imports
		│   │   ├── UsersImport.php
		│ 
		└── composer.json

	如果你更喜歡手動創建導入,可以在 app/Imports 下創建如下文件:
		<?php

		namespace App\Imports;

		use App\User;
		use Illuminate\Support\Facades\Hash;
		use Maatwebsite\Excel\Concerns\ToModel;

		class UsersImport implements ToModel
		{
		    /**
		     * @param array $row
		     *
		     * @return User|null
		     */
		    public function model(array $row)
		    {
		        return new User([
		           'name'     => $row[0],
		           'email'    => $row[1], 
		           'password' => Hash::make($row[2]),
		        ]);
		    }
		}

	在控制器中調用導入:
		use App\Imports\UsersImport;
		use Maatwebsite\Excel\Facades\Excel;
		use App\Http\Controllers\Controller;

		class UsersController extends Controller 
		{
		    public function import() 
		    {
		        Excel::import(new UsersImport, 'users.xlsx');
		        
		        return redirect('/')->with('success', 'All good!');
		    }
		}

2.基本導入
	如果已經按 5 分鐘快速入門練習,我們已經有了一個 UsersImport 類。
		...

	從默認文件系統導入:
		將 UsersImport 傳遞給 Excel::import() 方法,將告知包如何導入第二個參數傳遞的 excel 文件。導入的 excel 文件需要位於我們的默認文件系統(查看 config/filesystems.php)。
			Excel::import(new UsersImport, 'users.xlsx');

	從另一個文件系統導入:
		我們可以通過傳遞第三個參數,來指定另一個文件系統,例如:Amazon s3 文件系統
			Excel::import(new UsersImport, 'users.xlsx', 's3');

	導入上傳文件:
		如果讓用戶上傳 excel 文件,我們也可以直接傳遞上傳的文件
			Excel::import(new UsersImport, request()->file('excel.xls'));

	導入全路徑:
		如果要指定文件所在的路徑,而不必將其移動到文件系統,我們可以直接將該文件路徑傳遞給 import 方法
			Excel::import(new UsersImport, storage_path('users.xlsx'));

	導入爲數組或集合:
		如果想要省略 ToArray 或 ToCollection concern,並且希望在控制中得到一個導入數據的數組(注意性能),可以使用 ::toArray() 或 ::toCollection() 方法
			$array = Excel::toArray(new UsersImport, 'users.xlsx');
			$collection = Excel::toCollection(new UsersImport, 'users.xlsx');

	指定 'reader' 類型:
		如果通過文件擴展名無法檢測到 reader 類型,我們可以傳遞第 4 個參數來指定一個 reader 類型
			Excel::import(new UsersImport, 'users.xlsx', 's3', \Maatwebsite\Excel\Excel::XLSX);

3.導入到集合
	開始導入的最簡單方式是,創建一個自定義的導入類。我們將使用一個 UsersImport 導入類作爲示例。

	在 App/Imports 下創建一個新的 UsersImport 導入類:
		namespace App\Imports;

		use App\User;
		use Illuminate\Support\Collection;
		use Maatwebsite\Excel\Concerns\ToCollection;

		class UsersImport implements ToCollection
		{
		    public function collection(Collection $rows)
		    {
		        foreach ($rows as $row) 
		        {
		            User::create([
		                'name' => $row[0],
		            ]);
		        }
		    }
		}

	collection() 方法接收一個行集合。每一行是一個由單元格的值填充的數組。

	如果文件有多個工作表,collection() 方法將會被調用多次。

	在控制器中,現在我們可以像下面這樣導入:
		public function import()
		{
			Excel::import(new UsersImport, 'users.xlsx');
		}

	警告:
		不管我們在 collection() 方法中返回什麼內容,都不會返回給控制器

4.導入到模型
	如果我們想要將一個工作簿導入到一個 Eloquent 模型,可以使用 ToModel concern。ToModel concern 將強制 model() 方法返回一個 model 類型
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;

		class UsersImport implements ToModel
		{
		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row[0],
		        ]);
		    }
		}

	返回的模型將爲我們保存。每行將導致(至少)一次保存,並且還將觸發模型事件。

	警告:
		當使用 ToModel 時,我們不應該自己保存模型,因爲這將破壞批量插入的功能。如果我們需要自己保存模型,可以考慮使用 OnEachRow

	跳過行
		如果想要跳過行,可以返回 null
			public function model(array $row)
			{
			    if (!isset($row[0])) {
			        return null;
			    }

			    return new User([
			        'name' => $row[0],
			    ]);
			}

	可能的列名(導入一個列,可嘗試幾個字段,直到給定的列存在值。例如:用戶名:username -> nick_name -> mobile)
		如果想要通過幾個可能的列名導入行(使用 WithHeadingRow),可以使用 null 合併操作符(??)。如果 first name 的列存在(示例中是 client_name),並且不是 Null,則返回它的值;否則尋找第二個可能的列名(示例中是 client)。
			public function model(array $row) {
			  	return new User([
			    	'name' => $row['client_name'] ?? $row['client'] ?? $row['name'] ?? null
			  	]);
			}

	自己來處理持久化
		在某些情況下,我們可能並沒有一個導入,該導入的每一行都是一個 Eloquent 模型,並且我們想要更多的控制發生了什麼。在這些情況下,我們可以使用 OnEachRow concern
			namespace App\Imports;

			use App\User;
			use Maatwebsite\Excel\Row;
			use Maatwebsite\Excel\Concerns\OnEachRow;

			class UsersImport implements OnEachRow
			{
			    public function onRow(Row $row)
			    {
			        $rowIndex = $row->getIndex();
			        $row      = $row->toArray();
			        
			        $group = Group::firstOrCreate([
			            'name' => $row[1],
			        ]);
			    
			        $group->users()->create([
			            'name' => $row[0],
			        ]);
			    }
			}

		警告:
			當使用 OnEachRow,我們不能使用批量插入,因爲該模型已經在 onRow 方法中持久化的保存。

5.可導入
	在之前的示例中,我們使用 Excel::import facade 來開始一個導入。

	Laravel Excel 也提供了一個 'Maatwebsite\Excel\Concerns\Importable' trait,來使得導入類可導入。
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\Importable;

		class UsersImport implements ToModel
		{
		    use Importable;

		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row[0],
		        ]);
		    }
		}

	導入
		我們現在可以不需要 facade 來導入:
			(new UsersImport)->import('users.xlsx', 'local', \Maatwebsite\Excel\Excel::XLSX);

	隊列
		或隊列導入:
			(new UsersImport)->queue('users.xlsx');

	導入到數組
		導入可以加載到數組:
			$array = (new UsersImport)->toArray('users.xlsx');

	導入到集合
		導入可以加載到集合:
			$collection = (new UsersImport)->toCollection('users.xlsx');

6.導入格式
	默認情況下,導入格式由文件的擴展名決定。如果要顯式配置導入格式,可以將其作爲第 3 個參數傳遞。

	XLSX
		(new UsersImport)->import('users.xlsx', null, \Maatwebsite\Excel\Excel::XLSX);

	CSV
		(new UsersImport)->import('users.csv', null, \Maatwebsite\Excel\Excel::CSV);

	TSV
		(new UsersImport)->import('users.tsv', null, \Maatwebsite\Excel\Excel::TSV);

	ODS
		(new UsersImport)->import('users.ods', null, \Maatwebsite\Excel\Excel::ODS);

	XLS
		(new UsersImport)->import('users.xls', null, \Maatwebsite\Excel\Excel::XLS);

	SLK
		(new UsersImport)->import('users.slk', null, \Maatwebsite\Excel\Excel::SLK);

	XML
		(new UsersImport)->import('users.xml', null, \Maatwebsite\Excel\Excel::XML);

	GUNMERIC
		(new UsersImport)->import('users.gnumeric', null, \Maatwebsite\Excel\Excel::GNUMERIC);

	HTML
		(new UsersImport)->import('users.html', null, \Maatwebsite\Excel\Excel::HTML);

7.多個工作表
	當一個文件有多個工作表時,每個工作表都將通過導入對象。如果想要單獨處理每個工作表,需要實現 WithMultipleSheets concern。

	sheets() 方法希望返回一個 '工作表導入對象' 的數組。工作表的順序很重要,數組中第一個工作表導入對象,將自動鏈接到 Excel 文件的第一個工作表。
		namespace App\Imports;

		use Maatwebsite\Excel\Concerns\WithMultipleSheets;

		class UsersImport implements WithMultipleSheets 
		{
		   
		    public function sheets(): array
		    {
		        return [
		            new FirstSheetImport()
		        ];
		    }
		}

	工作表導入類可以導入 '與普通導入對象相同的' concerns
		namespace App\Imports;

		use Illuminate\Support\Collection;
		use Maatwebsite\Excel\Concerns\ToCollection;

		class FirstSheetImport implements ToCollection
		{
		    public function collection(Collection $rows)
		    {
		        //
		    }
		}

	通過工作表索引選擇工作表
		如果想要更多地控制,選擇哪些工作表,以及如何將它們映射到指定的工作表導入對象,我們可以使用工作表索引作爲下標。工作表索引從 0 開始。
			namespace App\Imports;

			use Maatwebsite\Excel\Concerns\WithMultipleSheets;

			class UsersImport implements WithMultipleSheets 
			{
			   
			    public function sheets(): array
			    {
			        return [
			            0 => new FirstSheetImport(),
			            1 => new SecondSheetImport(),
			        ];
			    }
			}

	通過工作表名稱選擇工作表
		如果我們只知道工作表名稱,而不知道工作表索引,我們也可以使用工作表名稱作爲選擇器。將工作表名稱作爲數組索引,來將工作表鏈接到工作表導入對象。
			namespace App\Imports;

			use Maatwebsite\Excel\Concerns\WithMultipleSheets;

			class UsersImport implements WithMultipleSheets 
			{
			    public function sheets(): array
			    {
			        return [
			            'Worksheet 1' => new FirstSheetImport(),
			            'Worksheet 2' => new SecondSheetImport(),
			        ];
			    }
			}

		警告:
			未顯式定義在 sheet() 方法中的工作表,將被忽略,因此不會被導入。

	跳過未知的工作表
		當我們定義了不存在的工作表名稱或索引後,將拋出 Maatwebsite\Excel\Exceptions\SheetNotFoundException 異常

		當工作表不存在時,我們不想拋出異常,可以使用 Maatwebsite\Excel\Concerns\SkipsUnknownSheets concern
			namespace App\Imports;

			use Maatwebsite\Excel\Concerns\WithMultipleSheets;
			use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

			class UsersImport implements WithMultipleSheets, SkipsUnknownSheets
			{
			    public function sheets(): array
			    {
			        return [
			            'Worksheet 1' => new FirstSheetImport(),
			            'Worksheet 2' => new SecondSheetImport(),
			        ];
			    }
			    
			    public function onUnknownSheet($sheetName)
			    {
			    	// 例如,我們可以記錄未找到工作表
			        info("Sheet {$sheetName} was skipped");
			    }
			}

		僅跳過指定的工作表
			如果想要一個可選的工作表,並且其他的工作表仍然失敗,還可以讓工作表導入對象實現 SkipsUnknownSheets
				namespace App\Imports;

				use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

				class FirstSheetImport implements SkipsUnknownSheets
				{
				    public function onUnknownSheet($sheetName)
				    {
				    	// 例如,我們可以記錄未找到工作表
				        info("Sheet {$sheetName} was skipped");
				    }
				}

			現在,只有 FirstSheetImport 在沒找到時,會被跳過。任意其他定義的工作表將被跳過(將報錯吧,這裏應該寫錯了)

	有條件地加載工作表
		如果要指定每個導入應該導入哪些工作表,可以使用 Maatwebsite\Excel\Concerns\WithConditionalSheets trait
			namespace App\Imports;

			use Maatwebsite\Excel\Concerns\WithMultipleSheets;
			use Maatwebsite\Excel\Concerns\WithConditionalSheets;

			class UsersImport implements WithMultipleSheets 
			{
			    use WithConditionalSheets;

			    public function conditionalSheets(): array
			    {
			        return [
			            'Worksheet 1' => new FirstSheetImport(),
			            'Worksheet 2' => new SecondSheetImport(),
			            'Worksheet 3' => new ThirdSheetImport(),
			        ];
			    }
			}

		現在可以使用 onlySheets 方法來指定本次導入應該加載哪些工作表
			$import = new UsersImport();
			$import->onlySheets('Worksheet 1', 'Worksheet 3');

			Excel::import($import, 'users.xlsx');

8.標題行
	如果文件包含標題行,並且希望將這些名稱作爲每一行的數組的鍵,可以實現 WithHeadingRow concern

	假設我們的 Excel 文件如下所示:
		Name 			Email  			@Field
		dongxuemin 		[email protected] 	30

	我們現在可以引用這些標題,來替代之前的數字格式的數組鍵
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithHeadingRow;

		class UsersImport implements ToModel, WithHeadingRow
		{
		    public function model(array $row)
		    {
		        return new User([
		            'name'  => $row['name'],
		            'email' => $row['email'],
		            'at'    => $row['at_field'],
		        ]);
		    }
		}

	標題行在其他行(非第一行)
		如果標題行不在第一行,可以在導入類中簡單地指定:
			namespace App\Imports;

			use App\User;
			use Maatwebsite\Excel\Concerns\ToModel;
			use Maatwebsite\Excel\Concerns\WithHeadingRow;

			class UsersImport implements ToModel, WithHeadingRow
			{
			    public function model(array $row)
			    {
			        return new User([
			            'name'  => $row['name'],
			            'email' => $row['email'],
			        ]);
			    }
			    
			    public function headingRow(): int
			    {
			        return 2;
			    }
			}

		現在第二行將作爲標題行

	標題鍵格式
		默認情況下,標題鍵使用 Laravel 的 str_slug() 幫助函數進行格式化,例如,這意味着所有的空格被轉換爲 _

		如果想要改變該默認行爲,可以通過擴展 HeadingRowFormatter 來實現。

		不格式化
			如果不需要格式化,可以使用 none 格式化程序。數組建將包含標題行中的確切數據。
				use Maatwebsite\Excel\Imports\HeadingRowFormatter;

				HeadingRowFormatter::default('none');

				public function model(array $row)
				{
				    return new User([
				        'name'  => $row['Name'],
				        'email' => $row['Email'],
				    ]);
				}

		自定義格式化程序
			可以在服務提供者中,使用 ::extend() 來定義一個自定義格式化程序
				HeadingRowFormatter::extend('custom', function($value) {
				    return 'do-something-custom' . $value; 
				});

			可以在 config/excel.php 中設置自定義格式化程序
				'imports' => [
				    'heading_row' => [
				        'formatter' => 'custom',
				    ],
				],

			或者之後可以在服務提供者中設置新的格式化程序
				HeadingRowFormatter::default('custom');

	只導入標題行
		有時我們可能希望預先獲取標題行來進行一些驗證,有一個簡單的快捷方式:HeadingRowImport
			use Maatwebsite\Excel\HeadingRowImport;

			class UsersImportController extends Controller 
			{
			    public function import()
			    {
			        $headings = (new HeadingRowImport)->toArray('users.xlsx');
			    }
			}

		標題數組包含每張工作表的一個標題數組

9.批量插入
	將大文件導入到 Eloquent 模型,可能很快會有瓶頸,因爲每一行都會導致一次插入查詢。

	使用 WithBatchInserts concern,我們可以通過指定一個批處理大小,來限制查詢數量。該批處理大小將決定一次將多少模型插入到數據庫。這將大大減少導入時間。
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithBatchInserts;

		class UsersImport implements ToModel, WithBatchInserts
		{
		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row[0],
		        ]);
		    }
		    
		    public function batchSize(): int
		    {
		        return 1000;
		    }
		}

	ToModel
		該 concern 只與 ToModel concern 一起工作時有效。

	批處理大小
		1000 的批處理大小,並不是導入的最佳情況。我們需要根據自己的系統,來找到最佳的數值。

10.分塊讀取
	導入大文件,會佔用很大內存,因爲庫嘗試將整個工作表加載到內存。

	要減少內存使用的增加,我們可以使用 WithChunkReading concern。這將以分塊的方式來讀取工作表,並控制內存使用量。
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithChunkReading;

		class UsersImport implements ToModel, WithChunkReading
		{
		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row[0],
		        ]);
		    }
		    
		    public function chunkSize(): int
		    {
		        return 1000;
		    }
		}

	警告:
		1000 的塊大小,並不是導入的最佳情況。我們需要根據自己的系統,來找到最佳的數值。

	與批量插入一起使用
		(考慮時間和內存的消耗)最完美的解決方案是,將批量插入和分塊讀取結合使用
			namespace App\Imports;

			use App\User;
			use Maatwebsite\Excel\Concerns\ToModel;
			use Maatwebsite\Excel\Concerns\WithBatchInserts;
			use Maatwebsite\Excel\Concerns\WithChunkReading;

			class UsersImport implements ToModel, WithBatchInserts, WithChunkReading
			{
			    public function model(array $row)
			    {
			        return new User([
			            'name' => $row[0],
			        ]);
			    }
			    
			    public function batchSize(): int
			    {
			        return 1000;
			    }
			    
			    public function chunkSize(): int
			    {
			        return 1000;
			    }
			}

11.隊列讀取
	隊列分塊讀取
		當使用 WithChunkReading concern 時,我們也可以選擇將每個分塊放入到隊列中。只需簡單地添加 ShouldQueue contract 即可。
			namespace App\Imports;

			use App\User;
			use Maatwebsite\Excel\Concerns\ToModel;
			use Illuminate\Contracts\Queue\ShouldQueue;
			use Maatwebsite\Excel\Concerns\WithChunkReading;

			class UsersImport implements ToModel, WithChunkReading, ShouldQueue
			{
			    public function model(array $row)
			    {
			        return new User([
			            'name' => $row[0],
			        ]);
			    }
			    
			    public function chunkSize(): int
			    {
			        return 1000;
			    }
			}

		現在,包含 1000 行的塊,將被放入到隊列

		警告:
			ShouldQueue 僅支持和 WithChunkReading 結合使用

		顯式地隊列導入
			通過使用 ::queueImport,我們可以顯式地隊列導入
				Excel::queueImport(new UsersImport, 'users.xlsx');

			當使用 Importable trait 時,我們可以使用 queue 方法:
				(new UsersImport)->queue('users.xlsx');

			警告:
				ShouldQueue 總是需要的

		隱式地隊列導入
			當使用了 ShouldQueue,導入將被自動放入隊列	
				Excel::import(new UsersImport, 'users.xlsx');

	追加任務(注意:這個任務,並不一定是導入任務,可以是任意的任務)
		當隊列導入時,將返回 Laravel 的 PendingDispatch 實例。這意味着我們可以鏈式地將額外的任務添加到隊列的末尾,並且只有在所有導入任務正確執行完畢後,纔會執行追加的任務
			(new UsersImport)->queue('users.xlsx')->chain([
			    new NotifyUserOfCompletedImport(request()->user()),
			]);

			namespace App\Jobs;

			use App\User;
			use Illuminate\Bus\Queueable;
			use Illuminate\Contracts\Queue\ShouldQueue;
			use Illuminate\Queue\SerializesModels;

			class NotifyUserOfCompletedImport implements ShouldQueue
			{
			    use Queueable, SerializesModels;
			    
			    public $user;
			    
			    public function __construct(User $user)
			    {
			        $this->user = $user;
			    }

			    public function handle()
			    {
			        $this->user->notify(new ImportReady());
			    }
			}

	自定義隊列
		由於返回了 PendingDispatch,我們也可以改變使用的隊列
			(new UsersImport)->queue('users.xlsx')->allOnQueue('imports')

	多服務器設置
		如果正在處理多服務器設置(例如:負載均衡),我們可能希望確保每個任務的臨時文件是相同的。我們可以在配置中,配置一個遠程的臨時文件來實現。

		在 config/excel.php:
			'temporary_files' => [
			    'remote_disk' => 's3',
			],

	注意
		警告:
			目前不能隊列 xls 導入。 PhpSpreadsheet 的 Xls 讀取器,包含了一些非 utf8 字符,導致無法隊列

12.行驗證
	有時候我們想要在插入數據庫之前,驗證每一行。通過實現 WithValidation concern,我們可以指定每一行需要遵從的規則。

	rule() 方法,希望返回一個 Laravel Validation 規則
		<?php

		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\Importable;
		use Maatwebsite\Excel\Concerns\WithValidation;

		class UsersImport implements ToModel, WithValidation
		{
		    use Importable;

		    public function model(array $row)
		    {
		        return new User([
		            'name'     => $row[0],
		            'email'    => $row[1],
		            'password' => 'secret',
		        ]);
		    }

		    public function rules(): array
		    {
		        return [
		            '1' => Rule::in(['[email protected]']),

		             // Above is alias for as it always validates in batches
		             '*.1' => Rule::in(['[email protected]']),
		             
		             // Can also use callback validation rules
		             '0' => function($attribute, $value, $onFailure) {
		                  if ($value !== 'Patrick Brouwers') {
		                       $onFailure('Name is not Patrick Brouwers');
		                  }
		              }
		        ];
		    }
		}

	使用標題行進行驗證
		當使用 WithHeadingRow concern,我們可以使用標題行名稱作爲規則屬性
			<?php

			namespace App\Imports;

			use App\User;
			use Maatwebsite\Excel\Concerns\ToModel;
			use Maatwebsite\Excel\Concerns\Importable;
			use Maatwebsite\Excel\Concerns\WithValidation;
			use Maatwebsite\Excel\Concerns\WithHeadingRow;

			class UsersImport implements ToModel, WithValidation, WithHeadingRow
			{
			    use Importable;

			    public function model(array $row)
			    {
			        return new User([
			            'name'     => $row['name'],
			            'email'    => $row['email'],
			            'password' => 'secret',
			        ]);
			    }

			    public function rules(): array
			    {
			        return [
			            'email' => Rule::in(['[email protected]']),

			             // Above is alias for as it always validates in batches
			             '*.email' => Rule::in(['[email protected]']),
			        ];
			    }
			}

	自定義驗證消息
		通過給導入添加 customValidationMessages() 方法,我們可以爲每個失敗的驗證指定自定義消息
			/**
			* @return array
			*/
			public function rules(): array
			{
			    return [
			        '1' => Rule::in(['[email protected]']),
			    ];
			}

			/**
			 * @return array
			 */
			public function customValidationMessages()
			{
			    return [
			        '1.in' => 'Custom message for :attribute.',
			    ];
			}

	自定義驗證屬性
		通過給導入添加 customValidationAttributes() 方法,我們可以爲每一列指定自定義屬性名
			/**
			* @return array
			*/
			public function rules(): array
			{
			    return [
			        '1' => Rule::in(['[email protected]']),
			    ];
			}

			/**
			 * @return array
			 */
			public function customValidationAttributes()
			{
			    return ['1' => 'email'];
			}

	處理驗證錯誤
		數據庫事務
			整個導入會自動包裝到一個數據庫事務中,這意味着每個錯誤將回滾整個導入。當使用批量插入時,只會回滾當前批次。

		禁用事務
			如果你更希望在導入(或塊導入)時,沒有任何數據庫事務,可以在配置中,改變想要的事務處理器:

			在 config/excel.php
				'transactions' => [
				    'handler' => 'db',
				],

			目前支持的處理器有:null 或 db

		自定義事務處理器
			如果想要自定義一個事務處理器(例如:MongoDB 數據庫),可以如下添加我們自己的處理器:
				$this->app->make(\Maatwebsite\Excel\Transactions\TransactionManager::class)->extend('your_handler', function() {
				    return new YourTransactionHandler();
				});

			處理器應該實現 \Maatwebsite\Excel\Transactions\TransactionManager

		在最後收集所有錯誤
			當與批處理一起使用時,我們可以在導入結束後,收集所有的驗證失敗。我們可以 try-catch ValidationException。在此異常中,我們可以獲得所有失敗詳情。

			每個失敗詳情是 Maatwebsite\Excel\Validators\Failure 的一個實例。Failure 包含的信息有:哪一行,哪一列,以及單元格的驗證錯誤
				try {
				    $import->import('import-users.xlsx');
				} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
				     $failures = $e->failures();
				     
				     foreach ($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.
				     }
				}

		跳過失敗
			有時候我們可能想要跳過失敗。通過使用 SkipsOnFailure concern,我們可以控制驗證失敗發生時的情況。使用 SkipsOnFailure,當發生失敗時,不會回滾整個導入
				<?php

				namespace App\Imports;

				use App\User;
				use Maatwebsite\Excel\Concerns\ToModel;
				use Maatwebsite\Excel\Validators\Failure;
				use Maatwebsite\Excel\Concerns\Importable;
				use Maatwebsite\Excel\Concerns\SkipsOnFailure;
				use Maatwebsite\Excel\Concerns\WithValidation;

				class UsersImport implements ToModel, WithValidation, SkipsOnFailure
				{
				    use Importable;

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

			如果想要自動跳過所有失敗的行,並在導入最後收集所有的失敗,可以使用 Maatwebsite\Excel\Concerns\SkipsFailures trait。
				<?php

				namespace App\Imports;

				use App\User;
				use Maatwebsite\Excel\Concerns\ToModel;
				use Maatwebsite\Excel\Validators\Failure;
				use Maatwebsite\Excel\Concerns\Importable;
				use Maatwebsite\Excel\Concerns\SkipsOnFailure;
				use Maatwebsite\Excel\Concerns\WithValidation;
				use Maatwebsite\Excel\Concerns\SkipsFailures;

				class UsersImport implements ToModel, WithValidation, SkipsOnFailure
				{
				    use Importable, SkipsFailures;
				}

			已經跳過了,驗證規則失敗的每一行。現在我們可以在最後收集所有失敗:
				$import = new UsersImport();
				$import->import('users.xlsx');

				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.
				}

		跳過錯誤
			有時候我們可能想要跳過所有錯誤,例如:重複的數據庫記錄。通過使用 SkipOnError concern,我們可以控制模型導入失敗時的前那股看。使用 SkipOnError,當發生數據庫異常時,不會回滾整個導入
				<?php

				namespace App\Imports;

				use App\User;
				use Maatwebsite\Excel\Concerns\ToModel;
				use Maatwebsite\Excel\Concerns\Importable;
				use Maatwebsite\Excel\Concerns\SkipsOnError;
				use Maatwebsite\Excel\Concerns\WithValidation;

				class UsersImport implements ToModel, WithValidation, SkipsOnError
				{
				    use Importable;

				    /**
				     * @param \Throwable $e
				     */
				    public function onError(\Throwable $e)
				    {
				        // Handle the exception how you'd like.
				    }
				}

			如果想要自動跳過所有異常,並在導入最後收集所有它們,可以使用 Maatwebsite\Excel\Concerns\SkipsErrors trait。
				<?php

				namespace App\Imports;

				use App\User;
				use Maatwebsite\Excel\Concerns\ToModel;
				use Maatwebsite\Excel\Validators\Failure;
				use Maatwebsite\Excel\Concerns\Importable;
				use Maatwebsite\Excel\Concerns\SkipsOnError;
				use Maatwebsite\Excel\Concerns\WithValidation;
				use Maatwebsite\Excel\Concerns\SkipsErrors;

				class UsersImport implements ToModel, WithValidation, SkipsOnError
				{
				    use Importable, SkipsErrors;
				}

			已經跳過了,發生錯誤的每一行。現在我們可以在最後收集所有錯誤:
				$import = new UsersImport();
				$import->import('users.xlsx');

				dd($import->errors());

	沒有 ToModel 的行驗證
		如果沒有使用 ToModel concern,我們可以通過使用 Laravel Validator 非常簡單地進行行驗證。
			<?php

			namespace App\Imports;

			use App\User;
			use Illuminate\Support\Collection;
			use Illuminate\Support\Facades\Validator;
			use Maatwebsite\Excel\Concerns\ToCollection;

			class UsersImport implements ToCollection
			{
			    public function collection(Collection $rows)
			    {
			         Validator::make($rows->toArray(), [
			             '*.0' => 'required',
			         ])->validate();

			        foreach ($rows as $row) {
			            User::create([
			                'name' => $row[0],
			            ]);
			        }
			    }
			}

		驗證規則
			所有的驗證規則,參考 Laravel 驗證規則文檔

13.映射單元格
	如果有一個更加自定義化的電子表格,並且只想訪問指定的單元格,可以實現 WithMappedCells concern

	我們可能有如下的電子表格:
		name 		Patrick Brouwers
		email 		[email protected]

	現在我們可以將 name 映射到 B1,將 email 映射到 B2。這些座標的值,之後將在給定的數組鍵下可用。
		namespace App\Imports;

		use App\User;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithMappedCells;

		new UsersImport implements WithMappedCells, ToModel 
		{
		    public function mapping(): array
		    {
		        return [
		            'name'  => 'B1',
		            'email' => 'B2',
		        ];
		    }
		    
		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row['name'],
		            'email' => $row['email'],
		        ]);
		    }
		}

	警告:
		該 concern 並不意味着映射列,只允許引用指定的單元格。

14.自定義 CSV 配置
	默認情況下,Laravel Excel 使用配置文件(config/excel.php)的默認配置。我們可以通過添加 WithCustomCsvSettings 接口來改變該行爲。
		namespace App\Imports;

		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

		class UsersImport implements ToModel, WithCustomCsvSettings
		{
		    public function model(array $row)
		    {
		        return new User([
		            'name' => $row['0'],
		            'email' => $row['1']
		        ]);
		    }
		    
		    public function getCsvSettings(): array
		    {
		        return [
		            'input_encoding' => 'ISO-8859-1'
		        ];
		    }
		}

	可用的配置有:
		delimiter
		enclosure
		line_ending
		use_bom
		include_separator_line
		excel_compatibility
		escape_character
		contiguous
		input_encoding

15.進度條	
	當通過 console 來導入一個 Excel 文件,我們可以實現 WithProgressBar concern 來顯示一個進度條。

	例如,我們的導入類如下所示:
		<?php

		namespace App\Imports;

		use App\User;
		use Illuminate\Support\Facades\Hash;
		use Maatwebsite\Excel\Concerns\Importable;
		use Maatwebsite\Excel\Concerns\ToModel;
		use Maatwebsite\Excel\Concerns\WithProgressBar;

		class UsersImport implements ToModel, WithProgressBar
		{
		    use Importable;

		    public function model(array $row)
		    {
		        return new User([
		            'name'     => $row[0],
		            'email'    => $row[1],
		            'password' => Hash::make($row[2]),
		        ]);
		    }
		}

	在我們的 console 命令中,如下使用:
		<?php

		namespace App\Console\Commands;

		use App\Imports\UsersImport;
		use Illuminate\Console\Command;

		class ImportExcel extends Command
		{
		    protected $signature = 'import:excel';

		    protected $description = 'Laravel Excel importer';

		    public function handle()
		    {
		        $this->output->title('Starting import');
		        (new UsersImport)->withOutput($this->output)->import('users.xlsx');
		        $this->output->success('Import successful');
		    }
		}

	在命令行,通過調用 php artisan import:excel,開始導入。現在應該就會看到開始信息,進度條,以及完成後的成功信息

16.導入 concern
	看文檔

17.擴展
	看文檔

18.測試
	Excel facade 可用於將導入器變換爲 fake,來進行測試??

	看文檔

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章