最简单的导出方法是建立一个自定义的导出类, 这里咱们使用发票导出做为示例. 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; }); }