CakePHP 4 で PhpSpreadsheet を使う方法

はじめに

PhpSpreadsheet は PHP のライブラリで、これを導入するとエクセルファイルの読み書きを簡単に実装できるようになります。

今日はそれを CakePHP 4.0 で使う方法をサンプルコードと併せてご紹介します。
(おそらく CakePHP 3.8 でも同じ手順で使用可能だと思います)

今回ご紹介するのはデータをエクスポートする機能のみです。エクセルファイルの読込み方は扱っていませんのでご注意ください。

CakePHP
4.0.3
PhpSpreadsheet
1.10.1
PHP
7.3.11
OS
Win 10 Home
目次
  1. PhpSpreadsheet のインストール
  2. xlsx ファイルの書き出し
  3. xlsx をダウンロード
  4. 配列で一括入力
  5. データベースの値を簡単に Excel ファイル化
  6. おわりに

1. PhpSpreadsheet のインストール

PhpSpreadsheet は Composer を使ってインストールします。公式ドキュメントにある下記コマンドを実行するだけです。

> cd path\to\cakephp4
> composer require phpoffice/phpspreadsheet

2. xlsx ファイルの書き出し

xlsx ファイルを書き出すためには、コントローラに下記のように実装します。
公式ドキュメントのサンプルを CakePHP 4 に落とし込んだものです。

src/Controller/SampleController.php
<?php
declare(strict_types=1);

namespace App\Controller;

use PhpOffice\PhpSpreadsheet\Spreadsheet; // ← 追加
use PhpOffice\PhpSpreadsheet\Writer\Xlsx; // ← 追加

class SampleController extends AppController
{
  public function index()
  {
    $spreadsheet = new Spreadsheet();
    $sheet = $spreadsheet->getActiveSheet();
    $sheet->setCellValue('A1', 'Hello World !');
    $writer = new Xlsx($spreadsheet);

    // ファイルに保存
    $writer->save('sample.xlsx');
    exit;
  }
}

上記を実行すると、/webroot の中に sample.xlsx が生成されます。

もしうまくいかない場合、Mac や Linux をお使いの方は webroot に書込権限が付与されているかを確認してください。

それ以外の場合は、/tmp/error.log に何か手掛かりが残っているかもしれません。

3. xlsx をダウンロード

サーバ上に保存するのではなく、ファイルをダウンロードする用意したい場合は、下記のように実装します。

CakePHP の機能を使っている箇所は CallbackStream() や withType() などで、CakePHP のレスポンスオブジェクトを返するようにしています。

src/Controller/SampleController.php
...

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Cake\Http\CallbackStream; // ← 追加

class SampleController extends AppController
{
  public function index()
  {
    $spreadsheet = new Spreadsheet();
    $sheet = $spreadsheet->getActiveSheet();
    $sheet->setCellValue('A1', 'Hello World !');
    $writer = new Xlsx($spreadsheet);

    // ▼ここから下を変更
    // xlsx ファイルをダウンロード
    $stream = new CallbackStream(function () use ($writer) {
      $writer->save('php://output');
    });
    $filename = 'sample_'.date('ymd_His');
    $response = $this->response;
    return $response->withType('xlsx')
      ->withHeader('Content-Disposition', "attachment;filename=\"{$filename}.xlsx\"")
      ->withBody($stream);
  }
}

4. 配列で一括入力

これは PhpSpreadsheet の機能紹介になりますが、下記コードのように配列を使って、セルに値を入力することも出来ます。日本語も問題なく使えます。

src/Controller/SampleController.php
public function index()
{
  $spreadsheet = new Spreadsheet();
  $sheet = $spreadsheet->getActiveSheet();
  $data = [
      [null, '名前', '得点', 'Rank'],
      [   1, '太郎',    150,      3],
      [   2, '次郎',    125,      2],
      [   3, '三郎',     61,      1],
  ];
  $sheet->fromArray($data, NULL, 'A1');
  $writer = new Xlsx($spreadsheet);

  $writer->save('sample.xlsx');
  exit;
}

5. データベースの値を簡単に Excel ファイル化

CakePHP 4 の機能と、上記の配列で埋める機能を組みわせることで、データベースの値を下記のように簡単にエクセルファイル化できます。

-- テスト用のテーブル
CREATE TABLE `scores` (
  `id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `score` smallint(6) NOT NULL,
  `rank` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `scores`
  ADD PRIMARY KEY (`id`),
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

INSERT INTO `scores` (`id`, `name`, `score`, `rank`, `created`, `modified`) VALUES
  ('1', '太郎', '150', '3', NOW(), NOW()),
  ('2', '次郎', '125', '3', NOW(), NOW()),
  ('3', '三郎',  '61', '1', NOW(), NOW());
src/Controller/SampleController.php
public function index()
{
  $this->loadModel('Scores');

  $scores = $this->Scores->find()
    ->disableHydration()
    ->toArray();

  $spreadsheet = new Spreadsheet();
  $sheet = $spreadsheet->getActiveSheet();
  $sheet->fromArray($scores, NULL, 'A1');
  $writer = new Xlsx($spreadsheet);
  $writer->save('sample.xlsx');
  exit;
}

disableHydration() は、結果を Entities オブジェクトではなく、配列で取得するための関数です。

余談ですが、CakePHP 3 では hydrate(false) や enableHydration(false) としていましたね。CakePHP 4.0 で試したところ enableHydration(false) でも動くようですが、公式ドキュメントの通り、disableHydration() を使ったほうがいいのかなと思います。

おわりに

CakePHP 4 に PhpSpreadsheet を導入するのはとても簡単です。ダウンロードさせる処理は Component などに分割すると、再利用ができて、Controller のコードがスッキリしそうですね。

また PhpSpreadsheet はとても高機能なライブラリで、罫線や背景色の設定など、様々な装飾も可能です。公式ドキュメントは英語ですが、色々と詳しく掲載されているので一読されることをオススメします。