Laravel 实现文件 导入/导出 功能

时间:2020-03-27 标签: Laravel | PHP

本文推荐使用和 Laravel 契合度很高的 maatwebsite/excel 工具包。

2.x 版本

2.x 版本国内使用率较高,使用简单。

环境要求

  • PHP version >= 5.3.7
  • Laravel >= 4.1

安装配置

安装 maatwebsite/excel 工具包:

composer require maatwebsite/excel ~2.1

在 config/app.php 中注册服务提供者到 providers 数组:

Maatwebsite\Excel\ExcelServiceProvider::class,

在 config/app.php 中注册门面到 aliases 数组:

'Excel' => Maatwebsite\Excel\Facades\Excel::class,

导出示例

use Excel;

$cellData = [
    ['学号','姓名','成绩'],
    ['10001','AAAAA','99'],
    ['10002','BBBBB','92'],
    ['10003','CCCCC','95'],
    ['10004','DDDDD','89'],
    ['10005','EEEEE','96'],
];

Excel::create('学生成绩', function($excel) use ($cellData){
    $excel->sheet('score', function($sheet) use ($cellData){
        $sheet->rows($cellData);
    });
})->export('xls');

导入示例

use Excel;

$filePath = 'filePath';

Excel::load($filePath, function($reader) {
    $data = $reader->all(); 
    dd($data);
});

3.x 版本

3.x 改版较大,基本重构。底层通过 Export 对象驱动,入口自定义 Export 类,实例化 FromCollection 接口,继承Exportale 特性。

环境要求

  • PHP >= 7.0
  • Laravel >= 5.5

安装配置

安装 maatwebsite/excel 工具包:

composer require maatwebsite/excel ~3.1

导出示例

新建导出数据表 user 的文件:

php artisan make:export UsersExport --model=User

app 目录下创建 Exports 目录:

.
├── app
│   ├── Exports
│   │   ├── UsersExport.php
│ 
└── composer.json

UsersExport.php 文件内容:

<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}

业务调用:

<?php

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}

上述示例中,UsersExport 继承了 FromCollection 类,在 collection 方法中查询了 user 表,并导出 user 表数据。

但是在一些业务逻辑中,我们想直接导出自定义数组,这里我们可以用到 maatwebsite/excel 中 FromArray 类来实现此功能。

创建 CommonExport.php 导出文件:

php artisan make:export CommonExport

app 目录下创建 Exports 目录:

.
├── app
│   ├── Exports
│   │   ├── UsersExport.php
│   │   ├── CommonExport.php
│ 
└── composer.json

CommonExport.php 文件内容:

<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromArray;

class CommonExport implements FromArray
{
    public function array(): array
    {
        $data = [
            ['表题1', '表题2', '表题3'],
            ['value1', 'value2', 'value3'],
            ['value1', 'value2', 'value3'],
            ['value1', 'value2', 'value3']
        ];
        return $data;
    }
}

业务调用:

<?php

namespace App\Http\Controllers;

use App\Exports\CommonExport;
use Maatwebsite\Excel\Facades\Excel;

class DemoController
{
    public function demo()
    {
        return Excel::download(new CommonExport(), 'demo.xlsx');
    }
}

上述示例中,CommonExport.php 文件我们可以做下封装:

<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromArray;
# 自动适应单元格宽
use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class CommonExport implements FromArray, ShouldAutoSize
{
    protected $lists;
    protected $headers;

    public function __construct(array $headers, array $lists)
    {
        $this->lists = $lists;
        $this->headers = $headers;
    }

    public function array(): array
    {
        return $this->lists;
    }

    public function headings(): array
    {
        return $this->headers;
    }
}

在业务层调用:

<?php

namespace App\Http\Controllers;

use App\Exports\CommonExport;
use Maatwebsite\Excel\Facades\Excel;

class DemoController
{
    public function demo()
    {
        $headers = ['表题1', '表题2', '表题3'];
        $lists = [
            ['value1', 'value2', 'value3'],
            ['value1', 'value2', 'value3'],
            ['value1', 'value2', 'value3'],
            ['value1', 'value2', 'value3']
        ];
        return Excel::download(new CommonExport($headers, $lists), 'demo.xlsx');
    }
}

注意,在上述的 CommonExport 封装类中,我们同时继承使用了自动适应单元格宽的 ShouldAutoSize 类。

Maatwebsite\Excel 工具包中提供了很多方法,如:自动适应单元格宽、单元格格式化、导出多 sheet、设置单元格高度以及垂直居中,字体颜色、背景色等、导出图片等等方法。这里我们就不一一介绍了,若使用可参考官方提供的文档。

导入示例

新建导入数据库 user 表数据的文件:

php artisan make:import UsersImport --model=User

app 目录下创建 Imports 目录:

.
├── app
│   ├── Imports
│   │   ├── UsersImport.php
│ 
└── composer.json

UsersImport.php 代码内容:

<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1], 
           'password' => Hash::make($row[2]),
        ]);
    }
}

业务调用:

use App\Imports\UsersImport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function import() 
    {
        Excel::import(new UsersImport, 'users.xlsx');
    }
}

需要说明的是,上面所用的模式是 toModel,不需要手动去调用 save 方法,如果需要手动控制存储过程,请使用下列方法:

<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Facades\Hash;
//替换 toModel
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    /**
     * 使用 ToCollection
     * @param array $row
     *
     * @return User|null
     */
    public function ToCollection(Collection $rows)
    {
        //如果需要去除表头
        unset($rows[0]);
        //$rows 是数组格式
        $this->createData($rows);
    }

    public function createData($rows)
    {
        //todo
    }
}

以上示例中,我们使用 UsersImport 类直接添加数据到 user 表。

但是在一些业务逻辑中,我们想直接取出 Excel 表格中的数据,这里我们可以使用到 maatwebsite/excel 中 ToArray 类来实现此功能。

创建 CommonExport.php 导入文件:

php artisan make:import CommonImport

app 目录下创建 Imports 目录:

.
├── app
│   ├── Imports
│   │   ├── UsersImport.php
│   │   ├── CommonImport.php
│ 
└── composer.json

CommonImport.php 文件内容:

<?php

namespace App\Imports;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\ToArray;

class CommonImport implements ToArray
{
    public function Array(Array $tables)
    {
        return $tables;
    }
}

业务调用:

<?php

namespace App\Http\Controllers;

use App\Imports\CommonImport;
use Maatwebsite\Excel\Facades\Excel;

class DemoController
{
    public function demo()
    {
        $file = 'D:\WWW\Study\Laravel\public\data\demo.xlsx';
        $array = Excel::toArray(new CommonImport, $file);
        dd($array);
    }
}

与导出一样,Maatwebsite\Excel 工具包中也提供了很多其他导入功能,如:分块导入、多 sheet 导入等方法。若使用可参考官方提供的文档。

问题汇总

因项目环境配置不同,以下解决方法仅供参考。

导出空文件

date: 2020-04-13

Nginx Version: 1.14.0
PHP Version: v7.1.33
Laravel Version: 5.5
maatwebsite/excel Version: 3.1

主要原因:版本兼容问题。继承使用了自动适应单元格宽的 ShouldAutoSize 类。

© 2020 Lh1010 - 豫ICP备16115435号-1