前言
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
字段:
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'], | |
]; | |
} | |
} |
可以看出,我们仅仅只需要关注map
和title
即可。
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、还有更多复杂用法,例如按照选项进行自定义导出,那个需要写好路由和查询方法,处理好导出数据即可,这部分等我实验一下再补充。