CakePHP 4 で PhpSpreadsheet のダウンロード機能をコンポーネントに実装
はじめに
一昨日の投稿「CakePHP 4 で PhpSpreadsheet を使う方法」では、PhpSpreadsheet を CakePHP 4 で使う方法をご紹介しました。
今日はその中でも少しお話した、ダウンロード機能をコンポーネントに実装する方法をご紹介します。
今回はWindows で試していますが、Mac や Linux などでも同様のコマンドで動くと思います。その場合はパス区切り文字を「\」から「/」に変更してください。
- CakePHP
- 4.0.3
- PhpSpreadsheet
- 1.10.1
- PHP
- 7.3.11
- OS
- Win 10 Home
1. Bake でコンポーネントのベースを作成
今日は Bake を使ってコンポーネントのベースを作成してみましょう。下記コマンドを実行します。
> cd path\to\cake
> bin\cake bake component Excel --no-test
Creating file C:\path\to\cake4\src\Controller\Component\ExcelComponent.php
Wrote `C:\path\to\cake4\src\Controller\Component\ExcelComponent.php`
「--no-test」オプションは、ユニットテスト用のファイルを作らないオプションです。このオプションをつけないと、テスト用の下記ファイルが自動生成されます。
tests\TestCase\Controller\Component\ExcelComponentTest.php
bake が完了すると、下記内容で ExcelComponent.php が生成されます。
<?php
declare(strict_types=1);
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
/**
* Excel component
*/
class ExcelComponent extends Component
{
/**
* Default configuration.
*
* @var array
*/
protected $_defaultConfig = [];
}
この ExcelComponent にダウンロード用の関数を追加します。 今回は下記のように実装しました。 $response の箇所は、Component 内では $this->request が無いため new Response() にしています。 また、ファイル名に日本語が含まれることも考慮し withHeader() の箇所も変更しました。 コントローラからは、こんな感じで呼び出します。 もし複数の箇所で PhpSpreadsheet のダウンロード機能を使う場合には、コンポーネントなどに分割するのがオススメです。このように分割しておけば、開発効率と保守性が向上します。 この機能に限らず、コードを書いていて同じような処理を繰り返し実装しているなー、と感じたら、関数化できないか検討すると良いと思います。2. コンポーネントにダウンロード機能を実装
<php
...
use Cake\Controller\ComponentRegistry;
// ▼この4行を追加
use Cake\Http\CallbackStream;
use Cake\Http\Response;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
...
class ExcelComponent extends Component
{
...
// ▼この関数を追加
/**
* エクセルファイルダウンロード
*
* @param PhpOffice\PhpSpreadsheet\Spreadsheet スプレッドシート
* @param string $filename ファイル名
* @return Cake\Http\Response
*/
public function download(Spreadsheet $spreadsheet, string $filename)
{
$writer = new Xlsx($spreadsheet);
$stream = new CallbackStream(function () use ($writer) {
$writer->save('php://output');
});
$response = new Response();
$encodedName = rawurlencode("{$filename}.xlsx");
return $response->withType('xlsx')
->withHeader('Content-Disposition', "attachment;filename*=UTF-8''{$encodedName}")
->withBody($stream);
}
}
<?php
declare(strict_types=1);
namespace App\Controller;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
class SampleController extends AppController
{
public function index()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');
// xlsx ファイルをダウンロード
$this->loadComponent('Excel');
$filename = 'サンプル_' . date('ymd_His');
return $this->Excel->download($spreadsheet, $filename);
}
}
3. おわりに