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