最簡單的導出方法是建立一個自定義的導出類, 這裏咱們使用發票導出做爲示例. php
在 App/Exports
下建立一個 InvoicesExport
類laravel
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; class InvoicesExport implements FromCollection { public function collection() { return Invoice::all(); } }
在控制器中你能夠使用以下方式來下載web
public function export() { return Excel::download(new InvoicesExport, 'invoices.xlsx'); }
或者存儲在 s3
磁盤中數組
public function storeExcel() { return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3'); }
若是你的導出須要依賴, 你能夠注入導出類閉包
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; class InvoicesExport implements FromCollection { public function __construct(InvoicesRepository $invoices) { $this->invoices = $invoices; } public function collection() { return $this->invoices->all(); } }
public function export(Excel $excel, InvoicesExport $export) { return $excel->download($export, 'invoices.xlsx'); }
若是你但願 0
在 excel 單元格中就是顯示 0, 而不是顯示 null
(空單元格), 你能夠使用 WithStrictNullComparison
app
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithStrictNullComparison; class InvoicesExport implements FromCollection, WithStrictNullComparison { public function __construct(InvoicesRepository $invoices) { $this->invoices = $invoices; } public function collection() { return $this->invoices->all(); } }
這個包提供了 laravel collection 的一些額外的方法(宏) 來簡單的下載或者是存儲到 excel性能
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel( $filePath, $writerType = null, $headings = false )
(new Collection([[1, 2, 3], [1, 2, 3]]))->storeExcel( $filePath, $disk = null, $writerType = null, $headings = false )
導出能夠存儲到任何 Laravel 支持的 文件系統 中測試
public function storeExcel() { // Store on default disk Excel::store(new InvoicesExport(2018), 'invoices.xlsx'); // Store on a different disk (e.g. s3) Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3'); // Store on a different disk with a defined writer type. Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX); }
在以前的例子中, 咱們使用 Excel::download
這個 facade 來開始一個導出. 大數據
Laravel-Excel 一樣支持 Maatwebsite\Excel\Concerns\Exportable
trait, 來讓一個類能夠直接導出, 固然, 這個類裏邊須要有 collection 方法.ui
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\Exportable; class InvoicesExport implements FromCollection { use Exportable; public function collection() { return Invoice::all(); } }
咱們能夠不經過 facade 直接進行類的下載
return (new InvoicesExport)->download('invoices.xlsx');
或者是存儲到磁盤上.
return (new InvoicesExport)->store('invoices.xlsx', 's3');
以前的例子能夠作的簡單一點, 例如咱們添加 Laravel 的 Responsable
到導出類中
namespace App\Exports; use Illuminate\Contracts\Support\Responsable; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\Exportable; class InvoicesExport implements FromCollection, Responsable { use Exportable; /** * It's required to define the fileName within * the export class when making use of Responsable. */ private $fileName = 'invoices.xlsx'; public function collection() { return Invoice::all(); } }
你能夠更簡單的返回導出類,可是不須要調用 ->download()
方法.
return new InvoicesExport();
在以前的例子中, 咱們在導出類中進行查詢, 固然這個解決方案能夠用在小的導出類中. 對於更大一點數據的導出類可能形成比較大的性能開銷.
經過使用 FromQuery
關係, 咱們能夠經過預查詢一個導出, 這個場景實現的原理是查詢能夠分塊執行.
在 InvoicesExport
類中,添加 FromQuery
關係, 而且添加一個查詢, 而且確保不要使用 ->get()
來獲取到數據!.
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\Exportable; class InvoicesExport implements FromQuery { use Exportable; public function query() { return Invoice::query(); } }
咱們能夠經過一樣的方式來下載
return (new InvoicesExport)->download('invoices.xlsx');
這種方式能夠經過自定義的參數來進行查詢. 簡單的做爲依賴項傳入導出類便可.
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\Exportable; class InvoicesExport implements FromQuery { use Exportable; public function __construct(int $year) { $this->year = $year; } public function query() { return Invoice::query()->whereYear('created_at', $this->year); } }
$year
參數能夠傳遞給導出類.
return (new InvoicesExport(2018))->download('invoices.xlsx');
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\Exportable; class InvoicesExport implements FromQuery { use Exportable; public function forYear(int $year) { $this->year = $year; return $this; } public function query() { return Invoice::query()->whereYear('created_at', $this->year); } }
咱們能夠經過 forYear
方法來調全年份.
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');
咱們能夠經過 blade 視圖來建立導出. 經過使用 FromView
關係.
namespace App\Exports; use Illuminate\Contracts\View\View; use Maatwebsite\Excel\Concerns\FromView; class InvoicesExport implements FromView { public function view(): View { return view('exports.invoices', [ 'invoices' => Invoice::all() ]); } }
這種方式會導出一個 Html 表格到 Excel 單元表, 例如 users.blade.php
:
<table> <thead> <tr> <th>Name</th> <th>Email</th> </tr> </thead> <tbody> @foreach($users as $user) <tr> <td>{{ $user->name }}</td> <td>{{ $user->email }}</td> </tr> @endforeach </tbody> </table>
若是你處理更大數據量的數據, 很明智的方法就是使用隊列來運行.
例以下邊的導出類:
namespace App\Exports; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromQuery; class InvoicesExport implements FromQuery { use Exportable; public function query() { return Invoice::query(); } }
咱們只須要調用一個 ->queue()
方法便可.
return (new InvoicesExport)->queue('invoices.xlsx');
後臺處理這些查詢的方式是經過多任務/多切割的方式來進行. 這些任務使用正確的順序來執行. 而且保證以前的查詢都是正確的.
你能夠將導出做爲一個能夠扔到隊列中的實現(利用 Laravel), 能夠使用 ShouldQueue
約束.
namespace App\Exports; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromQuery; use Illuminate\Contracts\Queue\ShouldQueue; class InvoicesExport implements FromQuery, ShouldQueue { use Exportable; public function query() { return Invoice::query(); } }
在控制器中能夠調用普通的 ->store()
方法. 基於 ShouldQueue
, 經過 laravel 的隊列方式來實現隊列處理. [ps:你須要首先自行配置隊列]
return (new InvoicesExport)->store('invoices.xlsx');
queue()
方法返回一個 Laravel 的 PendingDispatch
實例, 這意味着你能夠把其餘的任務串聯起來, 僅僅當前一個任務執行成功的時候, 後續的任務纔可以被執行.
return (new InvoicesExport)->queue('invoices.xlsx')->chain([ new NotifyUserOfCompletedExport(request()->user()), ]);
namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; class InvoiceExportCompletedJob implements ShouldQueue { use Queueable; public function handle() { // Do something. } }
當 PendingDispatch
返回的時候, 咱們能夠改變咱們使用的隊列.
return (new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');
爲了可以讓導出支持多單元表, 須要使用 WithMultipleSheets
關係來實現. 這個 sheets()
方法須要返回一個單元表數組.
namespace App\Exports; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\WithMultipleSheets; class InvoicesExport implements WithMultipleSheets { use Exportable; protected $year; public function __construct(int $year) { $this->year = $year; } /** * @return array */ public function sheets(): array { $sheets = []; for ($month = 1; $month <= 12; $month++) { $sheets[] = new InvoicesPerMonthSheet($this->year, $month); } return $sheets; } }
這個 InvoicesPerMonthSheet
能夠實現多種關係. 例如 FromQuery
, FromCollection
, ...
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\WithTitle; class InvoicesPerMonthSheet implements FromQuery, WithTitle { private $month; private $year; public function __construct(int $year, int $month) { $this->month = $month; $this->year = $year; } /** * @return Builder */ public function query() { return Invoice ::query() ->whereYear('created_at', $this->year) ->whereMonth('created_at', $this->month); } /** * @return string */ public function title(): string { return 'Month ' . $this->month; } }
如下能夠下載 2018 年的全部的發票, 它包含 12 單元表來顯示每月的數據.
public function download() { return (new InvoicesExport(2018))->download('invoices.xlsx'); }
經過添加 WithMapping
, 你能夠遍歷添加到單元行中的每一條數據而後並返回.
這種方法你能夠控制每一列的數據, 假設你使用 Eloquent 的 query builder.
use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\WithMapping; class InvoicesExport implements FromQuery, WithMapping { /** * @var Invoice $invoice */ public function map($invoice): array { return [ $invoice->invoice_number, Date::dateTimeToExcel($invoice->created_at), ]; } }
能夠經過添加一個 WithHeadings
約束來實現. 表頭會添加到全部數據的第一行的位置上.
use Maatwebsite\Excel\Concerns\FromQuery; use Maatwebsite\Excel\Concerns\WithHeadings; class InvoicesExport implements FromQuery, WithHeadings public function headings(): array { return [ '#', 'Date', ]; } }
你能夠格式化整列, 經過添加 WithColumnFormatting
, 若是你想更多範圍的自定義. 推薦使用 AfterSheet
事件來直接和地城的 Worksheet
類進行交互.
namespace App\Exports; use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use Maatwebsite\Excel\Concerns\WithColumnFormatting; use Maatwebsite\Excel\Concerns\WithMapping; class InvoicesExport implements WithColumnFormatting, WithMapping { public function map($invoice): array { return [ $invoice->invoice_number, Date::dateTimeToExcel($invoice->created_at), $invoice->total ]; } /** * @return array */ public function columnFormats(): array { return [ 'B' => NumberFormat::FORMAT_DATE_DDMMYYYY, 'C' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE, ]; } }
當操做日期的時候. 推薦使用 \PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel()
來正確的解析你的日期數據.
Interface | Explanation |
---|---|
Maatwebsite\Excel\Concerns\FromCollection |
Use a Laravel Collection to populate the export. |
Maatwebsite\Excel\Concerns\FromQuery |
Use an Eloquent query to populate the export. |
Maatwebsite\Excel\Concerns\FromView |
Use a (Blade) view to to populate the export. |
Maatwebsite\Excel\Concerns\WithTitle |
Set the Workbook or Worksheet title. |
Maatwebsite\Excel\Concerns\WithHeadings |
Prepend a heading row. |
Maatwebsite\Excel\Concerns\WithMapping |
Format the row before it's written to the file. |
Maatwebsite\Excel\Concerns\WithColumnFormatting |
Format certain columns. |
Maatwebsite\Excel\Concerns\WithMultipleSheets |
Enable multi-sheet support. Each sheet can have its own concerns (except this one). |
Maatwebsite\Excel\Concerns\ShouldAutoSize |
Auto-size the columns in the worksheet. |
Maatwebsite\Excel\Concerns\WithStrictNullComparison |
Uses strict comparisions when testing cells for null value. |
Maatwebsite\Excel\Concerns\WithEvents |
Register events to hook into the PhpSpreadsheet process. |
Trait | Explanation |
---|---|
Maatwebsite\Excel\Concerns\Exportable |
Add download/store abilities right on the export class itself. |
Maatwebsite\Excel\Concerns\RegistersEventListeners |
Auto-register the available event listeners. |
導出過程有一些事件,你能夠利用這些事件與底層類進行交互,以嚮導出添加自定義行爲。
經過使用事件,您能夠鏈接到父包。若是你須要徹底控制導出,則不須要使用諸如 "query" 或者 "view" 之類的便利方法。
事件將經過添加 WithEvents
關注來激活。在 registerEvents
方法中,你必須返回一系列事件。Key 是事件的徹底限定名(FQN),Value 是可調用的事件監聽器。這能夠是一個閉包、可調用的數組 或 invokable 類。
namespace App\Exports; use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Events\BeforeExport; use Maatwebsite\Excel\Events\BeforeWriting; use Maatwebsite\Excel\Events\BeforeSheet; class InvoicesExport implements WithEvents { /** * @return array */ public function registerEvents(): array { return [ // Handle by a closure. BeforeExport::class => function(BeforeExport $event) { $event->writer->getProperties()->setCreator('Patrick'); }, // Array callable, refering to a static method. BeforeWriting::class => [self::class, 'beforeWriting'], // Using a class with an __invoke method. BeforeSheet::class => new BeforeSheetHandler() ]; } public static function beforeWriting(BeforeWriting $event) { // } }
請注意,使用 Closure
將不可能與隊列導出合併,由於PHP不能序列化閉包。在這些狀況下,最好使用 RegistersEventListeners
特性。
經過使用 RegistersEventListeners
trait ,你能夠自動註冊事件監聽器,而不須要使用 registerEvents
。只有在建立方法時,偵聽器纔會被註冊。
namespace App\Exports; use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Concerns\RegistersEventListeners; use Maatwebsite\Excel\Events\BeforeExport; use Maatwebsite\Excel\Events\BeforeWriting; use Maatwebsite\Excel\Events\BeforeSheet; use Maatwebsite\Excel\Events\AfterSheet; class InvoicesExport implements WithEvents { use Exportable, RegistersEventListeners; public static function beforeExport(BeforeExport $event) { // } public static function beforeWriting(BeforeWriting $event) { // } public static function beforeSheet(BeforeSheet $event) { // } public static function afterSheet(AfterSheet $event) { // } }
Event name | Payload | Explanation |
---|---|---|
Maatwebsite\Excel\Events\BeforeExport |
$event->writer : Writer |
Event gets raised at the start of the process. |
Maatwebsite\Excel\Events\BeforeWriting |
$event->writer : Writer |
Event gets raised before the download/store starts. |
Maatwebsite\Excel\Events\BeforeSheet |
$event->sheet : Sheet |
Event gets raised just after the sheet is created. |
Maatwebsite\Excel\Events\AfterSheet |
$event->sheet : Sheet |
Event gets raised at the end of the sheet process. |
Writer
和 Sheet
都是能夠進行宏操做的,這意味着它能夠很容易地擴展以知足你的須要。Writer 和 Sheet都有一個 ->getDelegate()
方法,它返回底層的PhpSpreadsheet 類。這將容許你爲 PhpSpreadsheets 方法添加快捷方法,而這個方法在這個包中是不可用的。
use \Maatwebsite\Excel\Writer; Writer::macro('setCreator', function (Writer $writer, string $creator) { $writer->getDelegate()->getProperties()->setCreator($creator); });
use \Maatwebsite\Excel\Sheet; Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) { $sheet->getDelegate()->getPageSetup()->setOrientation($orientation); });
你還能夠爲樣式單元添加一些快捷方法。你能夠自由使用這個宏,或者創造你本身的語法!
use \Maatwebsite\Excel\Sheet; Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array style) { $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style); });
以上例子可做:
namespace App\Exports; use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Events\BeforeExport; use Maatwebsite\Excel\Events\AfterSheet; class InvoicesExport implements WithEvents { /** * @return array */ public function registerEvents(): array { return [ BeforeExport::class => function(BeforeExport $event) { $event->writer->setCreator('Patrick'); }, AfterSheet::class => function(AfterSheet $event) { $event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE); $event->sheet->styleCells( 'B2:G8', [ 'borders' => [ 'outline' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK, 'color' => ['argb' => 'FFFF0000'], ], ] ] ); }, ]; } }
對於 PhpSpreadsheet 方法, 可查看文檔: https://phpspreadsheet.readthedocs.io/
The Excel facade can be used to swap the exporter to a fake.
/** * @test */ public function user_can_download_invoices_export() { Excel::fake(); $this->actingAs($this->givenUser()) ->get('/invoices/download/xlsx'); Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) { // Assert that the correct export is downloaded. return $export->collection()->contains('#2018-01'); }); }
/** * @test */ public function user_can_store_invoices_export() { Excel::fake(); $this->actingAs($this->givenUser()) ->get('/invoices/store/xlsx'); Excel::assertStored('filename.xlsx', 'diskName'); Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) { return true; }); // When passing the callback as 2nd param, the disk will be the default disk. Excel::assertStored('filename.xlsx', function(InvoicesExport $export) { return true; }); }
/** * @test */ public function user_can_queue_invoices_export() { Excel::fake(); $this->actingAs($this->givenUser()) ->get('/invoices/queue/xlsx'); Excel::assertQueued('filename.xlsx', 'diskName'); Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) { return true; }); // When passing the callback as 2nd param, the disk will be the default disk. Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) { return true; }); }