3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PHP Laravelを用いてExcel出力を行う

Last updated at Posted at 2022-09-18

概要

PHP(Laravel)を用いてExcel出力を行う方法を共有します。
以前はPHPExcelが主流みたいでしたが、現在はその後継となるPhpspreadsheetというライブラリが一般的です。
(githubのREADMEにも記載されている通りPHPExcelよりもPhpspreadsheetを使うことが望ましいでしょう。)

今回は社員名簿リストをExcelにて出力します。
ゴールイメージは下記のような感じです。
スクリーンショット 2022-09-19 1.22.50.png

今回やること

  • Excel出力/ブラウザからダウンロード
  • 列幅の調整
  • 行の固定

環境

PHP 8.1.10
Laravel 9.30.1

1.Phpspreadsheetをインストールする

まずはPhpspreadsheetをインストールします。

composer require phpoffice/phpspreadsheet

2.PhpSpreadsheetクラスの作成

Serviceクラスとして切り出して、新たにExcel出力するファイルを作成します。
(今回はブラウザからダウンロードすることを想定して作成しています。)

app/Services/PhpSpreadsheetService.php
<?php

namespace App\Services;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;

class PhpSpreadsheetService
{
    private const HEADER_ROW = 1;
    private const BODY_ROW = 2;
    private const HEADER_NAMES = [
        '社員ID',
        '氏名',
        '生年月日',
        '部署',
        '職種',
    ];

    /**
     * Excelファイルを出力.
     *
     * @return void
     */
    public function export(): void
    {
        $this->spreadsheet = new Spreadsheet();

        // ヘッダー部分出力
        $column_index = range('A', 'Z');
        foreach (self::HEADER_NAMES as $key => $header_name) {
            $this->spreadsheet->getActiveSheet()->setCellValue($column_index[$key].self::HEADER_ROW, $header_name);
        }
        
        // 社員名簿部分出力
        $employees = $this->getEmployees();
        foreach ($employees as $key => $employee) {
            $body_index = 0;    
            foreach ($employee as $employ_key => $employee_value) {
                $this->spreadsheet->getActiveSheet()->setCellValue($column_index[$body_index].(self::BODY_ROW + $key), $employee_value);
                $body_index++;
            }
        }

        // 1行目(ヘッダー)を固定
        $this->spreadsheet->getActiveSheet()->freezePane('A2');

        // 列幅を調整
        $this->spreadsheet->getActiveSheet()->getColumnDimension('B')->setWidth(12);
        $this->spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12);
        $this->spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(14);
        $this->spreadsheet->getActiveSheet()->getColumnDimension('E')->setWidth(14);

        // Excelファイルをダウンロード
        $file_name = '社員名簿.xlsx';
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;');
        header("Content-Disposition: attachment; filename=\"{$file_name}\"");
        header('Cache-Control: max-age=0');

        $writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
        $writer->save('php://output');
        exit;
    }
    
    /**
     * 社員名簿を取得.
     *
     * @return array
     */
    private function getEmployees(): array
    {
        return [
            [
                'id' => '1',
                'name' => '山田花子',
                'birthday' => '1990-01-23',
                'department' => '営業部',
                'occupation' => '営業',
            ],
            [
                'id' => '2',
                'name' => '田中太郎',
                'birthday' => '1993-08-01',
                'department' => '人事部',
                'occupation' => '企画',
            ],
            [
                'id' => '3',
                'name' => '高橋二郎',
                'birthday' => '1984-11-01',
                'department' => 'システム部',
                'occupation' => 'エンジニア',
            ],
        ];
    }
}

3. 簡易的なダウンロードページ作成

ブラウザからダウンロードできることを想定して、簡易的なダウンロードページを作成します。今回の本目的とは異なるのでCSSは何も充てておりません。ご了承ください。

resources/views/index.blade.php
<html>
    <body>
        <div>
            <form action="{{ url('/download') }}" method="POST">
                @csrf
                <h2>下記のボタンを押下してExcelファイルをダウンロードしてください。</h2>
                <button>download</button>
            </form>
        </div>
    </body>
</html>

ルーティング設定

routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SpreadsheetController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/index', [SpreadsheetController::class, 'index']);
Route::post('/download', [SpreadsheetController::class, 'download']);

Route::get('/', function () {
    return view('welcome');
});

コントローラー側の表示/Excelダウンロード処理

app/Http/Controllers/SpreadsheetController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Services\PhpSpreadsheetService;
use Illuminate\View\View;

class SpreadsheetController extends Controller
{
    protected $spreadsheet;

    /**
     * 
     * @param PhpSpreadsheetService $spreadsheet
     * 
     * @return void
     */
    public function __construct(PhpSpreadsheetService $spreadsheet)
    {
        $this->spreadsheet = $spreadsheet;
    }
    
    /**
     * Excelダウンロードページを表示.
     *
     * @return View
     */
    public function index(): View
    {
        return view('index');
    }

    /**
     * Excelファイルをダウンロード.
     *
     * @return View
     */
    public function download(): View
    {
        $this->spreadsheet->export();
        return view('index');
    }
}

4. 動作確認

CSSを充てていないので質素な感じですが、ダウンロードボタンを押します。
スクリーンショット 2022-09-19 1.25.54.png

Excelを開くとゴールイメージと同じような内容が出力されました。
これにて終了です。
スクリーンショット 2022-09-19 1.27.16.png

参考

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?