maatwebsite/excel使用:导出(二)

在磁盘上存储导出

存储原始内容

要接收导出文件的原始内容,可以使用 raw() 方法:

$contents = Excel::raw(new InvoicesExport, \Maatwebsite\Excel\Excel::XLSX);

默认磁盘

public function storeExcel() 
{
    // Store on default disk
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
}

自定义磁盘

public function storeExcel() 
{
    // 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::store()

public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, [
        'visibility' => 'private',
    ]);
}

Laravel 有一个私有文件的快捷方式:

public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, 'private');
}

导出格式

默认情况下,导出格式由文件的扩展名决定。如果要明确配置导出格式,可以将其作为第二个参数传递。

XLSX

return Excel::download(new InvoicesExport, 'invoices.xlsx', \Maatwebsite\Excel\Excel::XLSX);

CSV

return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV);

默认情况下,CSV 下载的 Content Type 是使用 text/plain,如果您想自定义 Content Type 标头,可以通过将其作为第三个参数传递来实现。

return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV, [
      'Content-Type' => 'text/csv',
]);

Laravel CSV
你也可以查看我们的Laravel CSV包。

TSV

return Excel::download(new InvoicesExport, 'invoices.tsv', \Maatwebsite\Excel\Excel::TSV);

ODS

return Excel::download(new InvoicesExport, 'invoices.ods', \Maatwebsite\Excel\Excel::ODS);

XLS

return Excel::download(new InvoicesExport, 'invoices.xls', \Maatwebsite\Excel\Excel::XLS);

HTML

return Excel::download(new InvoicesExport, 'invoices.html', \Maatwebsite\Excel\Excel::HTML);

导出为 PDF
如果您想导出为 PDF,您现在必须自己安装一个 PDF 渲染库。请参考PhpSpreadsheet 文档了解更多信息。

MPDF

return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::MPDF);

DOMPDF

return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::DOMPDF);

TCPDF

return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::TCPDF);

队列

如果您正在处理大量数据,则整个过程排队可能是明智的选择。

假设我们有以下导出类:

namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

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

现在只需调用 ->queue() 方法即可。

(new InvoicesExport)->queue('invoices.xlsx');
return back()->withSuccess('Export started!');

在幕后,查询将被分块,并将链接多个作业。这些作业将按正确的顺序执行,仅在之前的作业没有失败的情况下才会执行。

隐式导出队列

还可以将导出隐式标记为队列导出。您可以使用 LaravelShouldQueue合约 来实现此目的。

namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

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

现在在控制器中,你可以调用正常的 ->store() 方法。基于 ShouldQueue 合约的存在,导出将被排队。

(new InvoicesExport)->store('invoices.xlsx');

添加队列

queue() 方法返回 Laravel 的 PendingDispatch 实例。这意味着您可以链接额外的作业,这些作业将被添加到队列的末尾,并且仅在所有导出作业正确执行时才会执行。

(new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
namespace App\Jobs;

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

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

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

处理队列导出中的失败

在排队导出时,你可能希望有一种处理失败导出的方法。你可以通过向导出类添加 failed 方法来实现此目的。

use Throwable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{
    public function failed(Throwable $exception): void
    {
        // handle failed export
    }
}

自定义队列

由于返回了 PendingDispatch,我们也可以更改应该使用的队列。

Laravel 8+:

(new InvoicesExport)->queue('invoices.xlsx')->onQueue('exports');

旧版本的 Laravel:

(new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');

多服务器设置

如果你正在处理多服务器设置(例如使用负载均衡器),你可能希望确保用于存储每个数据块的临时文件对于每个作业都是相同的。你可以通过在配置中配置远程临时文件来实现这一点。

config/excel.php 中:

'temporary_files' => [
    'remote_disk' => 's3',
],

作业中间件

如果您正在使用 Laravel 6,可以使用middleware 方法将作业中间件作业中间件附加到导出类:

namespace App\Exports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ExportClass implements FromQuery
{
    use Exportable;

    public function middleware()
    {
        return [new RateLimited];
    }

    public function query()
    {
        // ...
    }
}

本地化导出队列

如果要本地化导出队列,则应在导出类上实现 HasLocalePreference 契约:

namespace App\Exports;

use Illuminate\Contracts\Translation\HasLocalePreference;
use Maatwebsite\Excel\Concerns\Exportable;

class ExportClass implements HasLocalePreference
{
    use Exportable;

    public function __construct(string $locale)
    {
        $this->locale = $locale;
    }

    public function preferredLocale()
    {
        return $this->locale;
    }
}

自定义查询大小

队列的可导出内容将被分块处理;每个块都是由 QueuedWriter 推送到队列的作业,对于实现FromQuery 作业的数量通过将通过将 $query->count() 除以块大小来计算的。

何时使用

根据 query() 方法的实现(例如,使用 groupBy 子句时),前面提到的计算可能不正确。

如果是这种情况你应该使用 WithCustomQuerySize 来提供查询大小的自定义计算。

多工作表

为了允许导出有多个工作表,应使用 WithMultipleSheetssheets()方法需要返回一个工作表导出对象的数组。

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, FromView 等关注点…

注意: WithTitle 关注点需要使用 title() 方法为每个工作表命名。

namespace App\Exports\Sheets;

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

下面的代码可以在任何类中实现,以下载今年所有发票的 xlsx 文件,其中包括 12个 工作表,每个工作表代表一年中的一个月。

public function downloadInvoices() 
{
    return (new InvoicesExport(2018))->download('invoices.xlsx');
}

Mapping data

映射行

通过添加 WithMapping ,你可以映射需要作为行添加的数据。这样您就可以控制每列的实际来源。如果使用 Eloquent 查询构建器:


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,
            $invoice->user->name,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}

多行

你还可以在 map 函数中返回多行:


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements FromQuery, WithMapping
{
    /**
    * @var Invoice $invoice
    */
    public function map($invoice): array
    {
        // This example will return 3 rows.
        // First row will have 2 column, the next 2 will have 1 column
        return [
            [
                $invoice->invoice_number,
                Date::dateTimeToExcel($invoice->created_at),
            ],
            [
                $invoice->lines->first()->description,
            ],
            [
                $invoice->lines->last()->description,
            ]
        ];
    }
}

添加标题行

通过添加 WithHeadings 可以轻松添加标题行。标题行将添加为工作表的第一行。


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{
    public function headings(): array
    {
        return [
            '#',
            'User',
            'Date',
        ];
    }
}

如果需要有多个标题行,可以从 headings() 方法返回多行:


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{   
    public function headings(): array
    {
        return [
           ['First row', 'First row'],
           ['Second row', 'Second row'],
        ];
    }
}

准备行

如果需要在将这些行附加到工作表之前准备行,可以将方法 prepareRows 添加到导出类。在展开查询输出并调用 map() 之前,将调用此方法。


use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function prepareRows($rows)
    {
        return $rows->transform(function ($user) {
            $user->name .= ' (prepared)';

            return $user;
        });
    }
}

原文 docs.laravel-excel.com/3.1/exports...

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!