Laravel6 配合 Maatwebsite\Excel 實現 Excel 匯入

sai0556發表於2020-04-05

前一段需要專案中需要通過Excel匯入使用者,之前用過phpexcel,總感覺太過繁瑣,印象中phpexcel也很久沒更新,看到專案中有使用Maatwebsite\Excel,便嘗試使用一下。

安裝

composer require maatwebsite/excel

匯入

生成匯入類

php artisan make:import AdminsImport --model=Admin

會看到app下面生成了Imports資料夾。

完善業務邏輯

<?php

namespace App\Imports;

use App\Models\Admin;
use function EasyWeChat\Kernel\Support\str_random;
use Maatwebsite\Excel\Concerns\ToModel;

class AdminsImport implements ToModel
{
    /**
    * @param array $row
    *
    * @return \Illuminate\Database\Eloquent\Model|null
    */
    public function model(array $row)
    {
        //過濾表頭和空行,我這邊表頭的第一個單元格是id,具體自行調整
        if (empty($row[0]) || $row[0] == 'id') {
            return null;
        }
        return new Admin([
            'username' => $row[2],
            'password' => bcrypt($row[3]),
            'api_token' => str_random(60),
        ]);
    }
}

匯入任務

<?php

namespace App\Console\Commands;

use App\Imports\AdminsImport;
use Illuminate\Console\Command;
use Maatwebsite\Excel\Facades\Excel;

class ImportAdmin extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'importAdmin';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '匯入admin';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Excel::import(new AdminsImport(), storage_path('files/export.xlsx'));
        $this->info($this->description.'完成');
    }
}

其他邏輯

當然,可能業務必不僅僅是寫入資料,可能有一些設計具體業務的操作,那麼你可以這樣操作。

<?php

namespace App\Imports;

use App\Models\Admin;
use function EasyWeChat\Kernel\Support\str_random;
use Maatwebsite\Excel\Concerns\ToCollection;
use Illuminate\Support\Collection;


class AdminsImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        //如果需要去除表頭
        unset($rows[0]);
        //$rows 是陣列格式
        return $this->createData($rows);
    }

    public function createData($rows)
    {
        $success = 0;
        foreach ($rows as $row) {
            $row[0] = (int) $row[0];
            if (empty($row[0])) {
                continue;
            }

            (new Admin())->create(
                [
                    'username' => $row[2],
                    'name' => $row[2],
                    'password' => bcrypt($row[3]),
                    'api_token' => str_random(60),
                ]
            );

            // 其他業務程式碼
            $success++;
        }

        return $success.'-'.count($rows);
    }

}

執行

php7.2 artisan importAdmin

總的來說,使用起來還是簡單明瞭的。

more

具體匯入實現可以搜尋Maatwebsite\Excel\Excel檢視,裡面還有匯出、以佇列方式匯入等,支援的格式也是多種多樣,具體程式碼如下,功能還是很強大的,足夠應付日常需求了。

<?php

namespace Maatwebsite\Excel;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Files\Filesystem;
use Maatwebsite\Excel\Files\TemporaryFile;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\PendingDispatch;
use Maatwebsite\Excel\Helpers\FileTypeDetector;

class Excel implements Exporter, Importer
{
    use RegistersCustomConcerns;

    const XLSX     = 'Xlsx';

    const CSV      = 'Csv';

    const TSV      = 'Csv';

    const ODS      = 'Ods';

    const XLS      = 'Xls';

    const SLK      = 'Slk';

    const XML      = 'Xml';

    const GNUMERIC = 'Gnumeric';

    const HTML     = 'Html';

    const MPDF     = 'Mpdf';

    const DOMPDF   = 'Dompdf';

    const TCPDF    = 'Tcpdf';

    /**
     * @var Writer
     */
    protected $writer;

    /**
     * @var QueuedWriter
     */
    protected $queuedWriter;

    /**
     * @var Filesystem
     */
    protected $filesystem;

    /**
     * @var Reader
     */
    private $reader;

    /**
     * @param Writer       $writer
     * @param QueuedWriter $queuedWriter
     * @param Reader       $reader
     * @param Filesystem   $filesystem
     */
    public function __construct(
        Writer $writer,
        QueuedWriter $queuedWriter,
        Reader $reader,
        Filesystem $filesystem
    ) {
        $this->writer       = $writer;
        $this->reader       = $reader;
        $this->filesystem   = $filesystem;
        $this->queuedWriter = $queuedWriter;
    }

    /**
     * {@inheritdoc}
     */
    public function download($export, string $fileName, string $writerType = null, array $headers = [])
    {
        return response()->download(
            $this->export($export, $fileName, $writerType)->getLocalPath(),
            $fileName,
            $headers
        )->deleteFileAfterSend(true);
    }

    /**
     * {@inheritdoc}
     */
    public function store($export, string $filePath, string $diskName = null, string $writerType = null, $diskOptions = [])
    {
        if ($export instanceof ShouldQueue) {
            return $this->queue($export, $filePath, $diskName, $writerType, $diskOptions);
        }

        $temporaryFile = $this->export($export, $filePath, $writerType);

        $exported = $this->filesystem->disk($diskName, $diskOptions)->copy(
            $temporaryFile,
            $filePath
        );

        $temporaryFile->delete();

        return $exported;
    }

    /**
     * {@inheritdoc}
     */
    public function queue($export, string $filePath, string $disk = null, string $writerType = null, $diskOptions = [])
    {
        $writerType = FileTypeDetector::detectStrict($filePath, $writerType);

        return $this->queuedWriter->store(
            $export,
            $filePath,
            $disk,
            $writerType,
            $diskOptions
        );
    }

    /**
     * {@inheritdoc}
     */
    public function raw($export, string $writerType)
    {
        $temporaryFile = $this->writer->export($export, $writerType);

        $contents = $temporaryFile->contents();
        $temporaryFile->delete();

        return $contents;
    }

    /**
     * {@inheritdoc}
     */
    public function import($import, $filePath, string $disk = null, string $readerType = null)
    {
        $readerType = FileTypeDetector::detect($filePath, $readerType);
        $response   = $this->reader->read($import, $filePath, $readerType, $disk);

        if ($response instanceof PendingDispatch) {
            return $response;
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function toArray($import, $filePath, string $disk = null, string $readerType = null): array
    {
        $readerType = FileTypeDetector::detect($filePath, $readerType);

        return $this->reader->toArray($import, $filePath, $readerType, $disk);
    }

    /**
     * {@inheritdoc}
     */
    public function toCollection($import, $filePath, string $disk = null, string $readerType = null): Collection
    {
        $readerType = FileTypeDetector::detect($filePath, $readerType);

        return $this->reader->toCollection($import, $filePath, $readerType, $disk);
    }

    /**
     * {@inheritdoc}
     */
    public function queueImport(ShouldQueue $import, $filePath, string $disk = null, string $readerType = null)
    {
        return $this->import($import, $filePath, $disk, $readerType);
    }

    /**
     * @param object      $export
     * @param string|null $fileName
     * @param string      $writerType
     *
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @return TemporaryFile
     */
    protected function export($export, string $fileName, string $writerType = null): TemporaryFile
    {
        $writerType = FileTypeDetector::detectStrict($fileName, $writerType);

        return $this->writer->export($export, $writerType);
    }
}

最後,感謝下面這一篇站內文章讓我快速上手。

最後,附上Laravel Excel 文件:

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

分享開發知識,歡迎交流。qq957042781,公眾號:愛好歷史的程式設計師。

相關文章