Dcat admin使用Laravel Excel匯出資料

她來聽我的演唱會發表於2021-08-23

前言

Dcat admin提供了Easy Excel匯出資料(預設未安裝),文件給出的例子為:

$grid->export()->rows(function (array $rows) {
    foreach ($rows as $index => &$row) {
        $row['name'] = $row['first_name'].' '.$row['last_name'];
    }

    return $rows;
});

很一目瞭然,也很簡單,但是假如遇到很複雜的資料處理,就顯得不夠優雅。因此需要把資料匯出提出來,做成單獨的元件,在控制器中引用就可以。例如定義了一個UserExporter,那麼在控制器中使用應該為:

$grid->export(new UserExporter());

在檢視了Easy Excel文件後發現,支援的比較少,文件也相對模糊一些,因此決定使用Laravel Excel,結合框架本身,實現簡單的使用。

開始

1、安裝larave-excel

composer require maatwebsite/excel

注意laravel版本號,目前支援5.8-8以及以上的版本,預設安裝的是3.1版本。

2、釋出配置

php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

生成預設配置類——config/excel.php,一般來說不需要更改配置。

使用

1、新建匯出類:

例如我匯出有關裝置的資訊,新建匯出裝置類DeviceExporter.php,裝置表有id、name、user_id、created_at、updated_at欄位:

<?php

namespace App\Admin\Extensions\Exporter;

use Dcat\Admin\Grid\Exporters\AbstractExporter;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;

class DeviceExporter extends AbstractExporter implements WithMapping, WithHeadings, FromCollection
{
    use Exportable;
    protected $fileName = '表格匯出測試';
    protected $titles = [];

    public function __construct()
    {
        $this->fileName = $this->fileName.'_'.Str::random(6).'.xlsx';//拼接下載檔名稱
        $this->titles = ['id' => 'id', 'user_id' => '所屬使用者' ,'created_at'=>'建立時間','updated_at'=>'更新時間'];
        parent::__construct();
    }

    public function export()
    {
        // TODO: Implement export() method.
        $this->download($this->fileName)->prepare(request())->send();
        exit;
    }

    public function collection()
    {
        // TODO: Implement collection() method.

        return collect($this->buildData());
    }

    public function headings(): array
    {
        // TODO: Implement headings() method.
        return $this->titles();
    }

    public function map($row): array
    {

        // TODO: Implement map() method.
        return [
            $row['id'],
            $row['user_id'],
            $row['created_at'],
            $row['updated_at'],
        ];
    }
}

可以看出,我們僅僅只需要關注maptitle即可。

2、在控制器中使用:

$grid->export(new DeviceExporter());

重新整理頁面就有匯出按鈕在頁面右上角。
這裡又有一個問題,之前使用Easy Excel匯出資料,會有三種選項:全部、當前頁和選中的項,擔心使用laravel-excel會有問題,但是在AbstractExporter.php中發現這樣的程式碼:

public function buildData(?int $page = null, ?int $perPage = null)
    {
        $model = $this->getGridModel();

        // current page
        if ($this->scope === Grid\Exporter::SCOPE_CURRENT_PAGE) {
            $page = $model->getCurrentPage();
            $perPage = $model->getPerPage();
        }

        $model->usePaginate(false);

        if ($page && $this->scope !== Grid\Exporter::SCOPE_SELECTED_ROWS) {
            $perPage = $perPage ?: $this->getChunkSize();

            $model->forPage($page, $perPage);
        }

        $array = $this->grid->processFilter()->toArray();

        $model->reset();

        return $this->normalize($this->callBuilder($array));
    }

匯出依賴於資料,buildData就是在處理資料。檢視SCOPE_CURRENT_PAGE

const SCOPE_ALL = 'all';
const SCOPE_CURRENT_PAGE = 'page';
const SCOPE_SELECTED_ROWS = 'selected';

剛好和我們所擔心的問題一致,因此可以斷定,無論使用什麼匯出擴充套件包,框架自身預設了這三種匯出方式。通過獲得當前頁、條數等資訊達到效果。並且在檢視相關方法時候發現,匯出方法裡的匯出會連同查詢條件一起進行資料匯出,也就是說,查詢完成後匯出的資料,是按照條件查詢的資料。
在測試三種匯出方法後,確定當前匯出沒有問題。

匯出關聯模型資料

上述的方式只能匯出現有的資料,對於需要匯出關聯模型資料來說就不行。那能不能實現匯出資料呢?可以,而且很簡單。
假如我有多臺裝置,例如:

    |  id   | name    | user_id  | created_at  | updated_at  |
    | ----- | ------- | -------- | ----------- | ----------- |
    | 1     | 測試裝置1|   2      | ----------- | ----------- |
    | 2     | 測試裝置2|   0      | ----------- | ----------- |

通過在public function map($row): array{}中列印發現,如果有關聯資料,列印的資料會把關聯模型的資料列印出來,例如:

array:20 ["id" => 1
  "name" => "測試裝置1"
  "user_id" => 2
  "created_at" => "2021-08-23 14:25:46"
  "updated_at" => "2021-08-23 14:26:10"
  "user.id" => 2
  "user.name" => "李大"
  "user.created_at" => "2021-08-13 11:21:05"
  "user.updated_at" => "2021-08-13 11:21:05"
]

而沒有關聯資料的則不顯示:

array:20 ["id" => 2
  "name" => "測試裝置2"
  "user_id" => 0
  "created_at" => "2021-08-23 14:25:46"
  "updated_at" => "2021-08-23 14:26:10"
]

所以,需要匯出關聯模型的資料,我們可以直接修改map程式碼為:

return [
    $row['id'],
    $row['user.name']??"",//為了防止無關聯資料包錯
    $row['created_at'],
    $row['updated_at'],
];

測試匯出,發現資料無誤,搞完手工。

總結

1、多個關聯關係資料依然適用,還是修改map方法中的項;
2、建議複雜的資料處理還是單獨寫一個匯出元件,這樣程式碼層次更加清晰,資料處理也更簡單;
3、至於美化Excel頁面有需要的可以檢視相關文件進行;
4、還有更多複雜用法,例如按照選項進行自定義匯出,那個需要寫好路由和查詢方法,處理好匯出資料即可,這部分等我實驗一下再補充。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章