资讯专栏INFORMATION COLUMN

[译] Laravel-Excel 3.0 文档

canopus4u / 834人阅读

摘要:事件将通过添加关注来激活。自动注册事件监听器通过使用,你可以自动注册事件监听器,而不需要使用。你可以自由使用这个宏,或者创造你自己的语法以上例子可作对于方法可查看文档测试测试下载测试存储导出测试队列导出

Basics

最简单的导出方法是创建一个自定义的导出类, 这里我们使用发票导出作为示例.

App/Exports 下创建一个 InvoicesExport

namespace AppExports;

use MaatwebsiteExcelConcernsFromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}

在控制器中你可以使用如下方式来下载

public function export() 
{
    return Excel::download(new InvoicesExport, "invoices.xlsx");
}

或者存储在 s3 磁盘中

public function storeExcel() 
{
    return Excel::store(new InvoicesExport, "invoices.xlsx", "s3");
}
依赖注入

如果你的导出需要依赖, 你可以注入导出类

namespace AppExports;

use MaatwebsiteExcelConcernsFromCollection;

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");
}
严格的 null 对比

如果你希望 0 在 excel 单元格中就是显示 0, 而不是显示 null(空单元格), 你可以使用 WithStrictNullComparison

namespace AppExports;

use MaatwebsiteExcelConcernsFromCollection;
use MaatwebsiteExcelConcernsWithStrictNullComparison;

class InvoicesExport implements FromCollection, WithStrictNullComparison
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
Collection 全局定义/宏

这个包提供了 laravel collection 的一些额外的方法(宏) 来简单的下载或者是存储到 excel

把 collection 作为 Excel 下载
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
在磁盘上存储 collection
(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);
}
Exportables / 可导出的

在之前的例子中, 我们使用 Excel::download 这个 facade 来开始一个导出.

Laravel-Excel 同样支持  MaatwebsiteExcelConcernsExportable trait, 来让一个类可以直接导出, 当然, 这个类里边需要有 collection 方法.

namespace AppExports;

use MaatwebsiteExcelConcernsFromCollection;
use MaatwebsiteExcelConcernsExportable;

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");
Responsable / 可响应的

之前的例子可以做的简单一点, 例如我们添加 Laravel 的 Responsable 到导出类中

namespace AppExports;

use IlluminateContractsSupportResponsable;
use MaatwebsiteExcelConcernsFromCollection;
use MaatwebsiteExcelConcernsExportable;

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();
From Query / 从查询输出

在之前的例子中, 我们在导出类中进行查询, 当然这个解决方案可以用在小的导出类中. 对于更大一点数据的导出类可能造成比较大的性能开销.

通过使用 FromQuery 关系, 我们可以通过预查询一个导出, 这个场景实现的原理是查询可以分块执行.

InvoicesExport 类中,添加 FromQuery 关系, 并且添加一个查询, 并且确保不要使用 ->get() 来获取到数据!.

namespace AppExports;

use MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsExportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}

我们可以通过同样的方式来下载

return (new InvoicesExport)->download("invoices.xlsx");
自定义查询

这种方式可以通过自定义的参数来进行查询. 简单的作为依赖项传入导出类即可.

作为构造器参数
namespace AppExports;

use MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsExportable;

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 AppExports;

use MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsExportable;

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 AppExports;

use IlluminateContractsViewView;
use MaatwebsiteExcelConcernsFromView;

class InvoicesExport implements FromView
{
    public function view(): View
    {
        return view("exports.invoices", [
            "invoices" => Invoice::all()
        ]);
    }
}

这种方式会导出一个 Html 表格到 Excel 单元表, 例如 users.blade.php:


    @foreach($users as $user)
        
    @endforeach
    
Name Email
{{ $user->name }} {{ $user->email }}
队列

如果你处理更大数据量的数据, 很明智的方法就是使用队列来运行.

例如下边的导出类:

namespace AppExports;

use MaatwebsiteExcelConcernsExportable;
use MaatwebsiteExcelConcernsFromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}

我们只需要调用一个 ->queue() 方法即可.

return (new InvoicesExport)->queue("invoices.xlsx");

后台处理这些查询的方式是通过多任务/多切割的方式来进行. 这些任务使用正确的顺序来执行. 并且保证之前的查询都是正确的.

另一种方式的队列实现

你可以将导出作为一个可以扔到队列中的实现(利用 Laravel), 可以使用 ShouldQueue 约束.

namespace AppExports;

use MaatwebsiteExcelConcernsExportable;
use MaatwebsiteExcelConcernsFromQuery;
use IlluminateContractsQueueShouldQueue;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}

在控制器中可以调用普通的 ->store() 方法. 基于 ShouldQueue, 通过 laravel 的队列方式来实现队列处理. [ps:你需要首先自行配置队列]

return (new InvoicesExport)->store("invoices.xlsx");
追加任务 / jobs

 queue() 方法返回一个 Laravel 的  PendingDispatch 实例, 这意味着你可以把其他的任务串联起来, 仅仅当前一个任务执行成功的时候, 后续的任务才能够被执行.

return (new InvoicesExport)->queue("invoices.xlsx")->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
namespace AppJobs;

use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;

class InvoiceExportCompletedJob implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        // Do something.
    }
}
自定义队列

PendingDispatch 返回的时候, 我们可以改变我们使用的队列.

return (new InvoicesExport)->queue("invoices.xlsx")->allOnQueue("exports");
多单元表

为了能够让导出支持多单元表, 需要使用 WithMultipleSheets 关系来实现. 这个 sheets() 方法需要返回一个单元表数组.

namespace AppExports;

use MaatwebsiteExcelConcernsExportable;
use MaatwebsiteExcelConcernsWithMultipleSheets;

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 可以实现多种关系. 例如 FromQueryFromCollection, ...

namespace AppExports;

use MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsWithTitle;

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 MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsWithMapping;

class InvoicesExport implements FromQuery, WithMapping
{
    /**
    * @var Invoice $invoice
    */
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}
添加表头

可以通过添加一个  WithHeadings 约束来实现. 表头会添加到所有数据的第一行的位置上.

use MaatwebsiteExcelConcernsFromQuery;
use MaatwebsiteExcelConcernsWithHeadings;

class InvoicesExport implements FromQuery, WithHeadings

    public function headings(): array
    {
        return [
            "#",
            "Date",
        ];
    }
}
格式化列

你可以格式化整列, 通过添加 WithColumnFormatting, 如果你想更多范围的自定义. 推荐使用 AfterSheet 事件来直接和地城的 Worksheet 类进行交互.

namespace AppExports;

use PhpOfficePhpSpreadsheetSharedDate;
use PhpOfficePhpSpreadsheetStyleNumberFormat;
use MaatwebsiteExcelConcernsWithColumnFormatting;
use MaatwebsiteExcelConcernsWithMapping;

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,
        ];
    }
}
日期

当操作日期的时候. 推荐使用 PhpOfficePhpSpreadsheetSharedDate::dateTimeToExcel() 来正确的解析你的日期数据.

导出关系
Interface Explanation
MaatwebsiteExcelConcernsFromCollection Use a Laravel Collection to populate the export.
MaatwebsiteExcelConcernsFromQuery Use an Eloquent query to populate the export.
MaatwebsiteExcelConcernsFromView Use a (Blade) view to to populate the export.
MaatwebsiteExcelConcernsWithTitle Set the Workbook or Worksheet title.
MaatwebsiteExcelConcernsWithHeadings Prepend a heading row.
MaatwebsiteExcelConcernsWithMapping Format the row before it"s written to the file.
MaatwebsiteExcelConcernsWithColumnFormatting Format certain columns.
MaatwebsiteExcelConcernsWithMultipleSheets Enable multi-sheet support. Each sheet can have its own concerns (except this one).
MaatwebsiteExcelConcernsShouldAutoSize Auto-size the columns in the worksheet.
MaatwebsiteExcelConcernsWithStrictNullComparison Uses strict comparisions when testing cells for null value.
MaatwebsiteExcelConcernsWithEvents Register events to hook into the PhpSpreadsheet process.
Traits
Trait Explanation
MaatwebsiteExcelConcernsExportable Add download/store abilities right on the export class itself.
MaatwebsiteExcelConcernsRegistersEventListeners Auto-register the available event listeners.
扩展 事件

导出过程有一些事件,你可以利用这些事件与底层类进行交互,以向导出添加自定义行为。

通过使用事件,您可以连接到父包。如果你需要完全控制导出,则不需要使用诸如 "query" 或者 "view" 之类的便利方法。

事件将通过添加 WithEvents 关注来激活。在 registerEvents 方法中,你必须返回一系列事件。Key 是事件的完全限定名(FQN),Value 是可调用的事件监听器。这可以是一个闭包、可调用的数组 或 invokable 类。

namespace AppExports;

use MaatwebsiteExcelConcernsWithEvents;
use MaatwebsiteExcelEventsBeforeExport;
use MaatwebsiteExcelEventsBeforeWriting;
use MaatwebsiteExcelEventsBeforeSheet;

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 AppExports;

use MaatwebsiteExcelConcernsWithEvents;
use MaatwebsiteExcelConcernsRegistersEventListeners;
use MaatwebsiteExcelEventsBeforeExport;
use MaatwebsiteExcelEventsBeforeWriting;
use MaatwebsiteExcelEventsBeforeSheet;
use MaatwebsiteExcelEventsAfterSheet;

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
MaatwebsiteExcelEventsBeforeExport $event->writer : Writer Event gets raised at the start of the process.
MaatwebsiteExcelEventsBeforeWriting $event->writer : Writer Event gets raised before the download/store starts.
MaatwebsiteExcelEventsBeforeSheet $event->sheet : Sheet Event gets raised just after the sheet is created.
MaatwebsiteExcelEventsAfterSheet $event->sheet : Sheet Event gets raised at the end of the sheet process.

WriterSheet 都是可以进行宏操作的,这意味着它可以很容易地扩展以满足你的需要。Writer 和 Sheet都有一个 ->getDelegate() 方法,它返回底层的PhpSpreadsheet 类。这将允许你为 PhpSpreadsheets 方法添加快捷方法,而这个方法在这个包中是不可用的。

Writer / 写入
use MaatwebsiteExcelWriter;

Writer::macro("setCreator", function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});
Sheet / 单元表
use MaatwebsiteExcelSheet;

Sheet::macro("setOrientation", function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});

你还可以为样式单元添加一些快捷方法。你可以自由使用这个宏,或者创造你自己的语法!

use MaatwebsiteExcelSheet;

Sheet::macro("styleCells", function (Sheet $sheet, string $cellRange, array style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});

以上例子可作:

namespace AppExports;

use MaatwebsiteExcelConcernsWithEvents;
use MaatwebsiteExcelEventsBeforeExport;
use MaatwebsiteExcelEventsAfterSheet;

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(PhpOfficePhpSpreadsheetWorksheetPageSetup::ORIENTATION_LANDSCAPE);

                $event->sheet->styleCells(
                    "B2:G8",
                    [
                        "borders" => [
                            "outline" => [
                                "borderStyle" => PhpOfficePhpSpreadsheetStyleBorder::BORDER_THICK,
                                "color" => ["argb" => "FFFF0000"],
                            ],
                        ]
                    ]
                );
            },
        ];
    }
}

对于 PhpSpreadsheet 方法, 可查看文档: https://phpspreadsheet.readthedocs.io/

测试 / Testing

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;
    });
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30731.html

相关文章

  • 关于laravel5的excel包maatwebsite/excel的使用笔记_v1.0_byKL

    摘要:关于的包的使用笔记关于安装官网已经很详细了不再描述关于导入导入的话只有几个小地方需要注意导入的时候会有产生一些的在循环遍历导入的数据的时候主动忽略关于中文或者乱码问题或者在配置文件在安装这个模块的文档有介绍怎么生成这个文件 关于laravel5的excel包maatwebsite/excel的使用笔记 关于安装 官网已经很详细了,不再描述.http://www.maatwebsite....

    MkkHou 评论0 收藏0
  • Laravel不权威导航

    摘要:版微信第三方登陆包括微信微博等等,查看支持列表扩展好用的图片处理,也方便使用百度版百度版支付集合,包含支付宝等支付宝在的封装各国语言包,包含简体中文生成二维码工具,亲测好用未完大家可以向我推荐,直接在本文下留言即可。 Laravel不权威导航 Hi 这里是Roy整理的Laravel相关索引,希望能帮到大家showImg(http://static.segmentfault.com/bu...

    focusj 评论0 收藏0
  • Laravel之Excel导入、导出

    摘要:介绍是经常会使用的,里有非常好的组件,能够实现文件的导入和导出。 1.介绍 Excel是经常会使用的,Laravel里有非常好的Excel组件,能够实现Excel/CSV文件的导入和导出 。 组件项目地址: composer: https://packagist.org/packages/maatwebsite/excel。 GitHub: https://github.com/M...

    nodejh 评论0 收藏0
  • []不要在UI主线程中进行耗时的操作

    摘要:比如说,平台检测到线程中有网络请求时,会抛出的异常网站文档中也对此进行了很好的解释当应用试图在主线程中进行网络操作,会被抛出。问题的主要来源是在线程进行了耗时的操作。 原文: Why Ice Cream Sandwich Crashes your App 问题 自Android Ice Cream Sandwich发布后, 这个问题就开始在StackOverflow弥散开来: ...

    lowett 评论0 收藏0
  • 」Android Animation in Honeycomb by Chet Haase(3.

    摘要:本文非全文翻译,亦非逐字逐句翻译,作为我自己的学习笔记,可谓是总结式翻译,梳理备忘。想了解新机制工作的更多细节,就去研读译注参考我这篇文章从中学习的用法是新动画机制中的超类。 原文 2011-02-24 Animation in Honeycomb 发表于 2011.02(和3.0发布的时间同步),作者是 Chet Haase,一个致力于图形和动画研究的 Android 开发者,可以...

    HackerShell 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<