今までデータのやり取りを解説してきましたが、システムを扱うとなると避けられない強敵。ファイルの取り扱いです。
テーブルの CSV を吐き出したい... PDF を吐き出したい、、、
など要求は多岐にわたると思います。
そんなものたちも、VILT スタックの中で扱うことができます。
大きく二種類ご紹介します。
ファイルをダウンロードさせる場合
用意した PDF ファイルをダウンロードさせたい場面を考えます。
何かしらの PDF を storage/app/private/sample.pdf に配置してください。
それでは、ダウンロードに利用するルートを作成します。
ポイントは GET で行うことです。
Route::get('/test', [TestController::class, 'index'])->name('tests.index');
+ Route::get('/test/download', [TestController::class, 'download'])->name('tests.download');
ではファイルを取得してダウンロードさせます。
既に用意したファイルをダウンロードする場合は、 response()->file() を利用します。
リダイレクトや Inertia は必要ありません。
Content-Type にファイルのMIME属性、Content-Disposition にファイル名を記載します。日本語も大丈夫です。
namespace App\Http\Controllers;
use Inertia\Inertia;
class TestController extends Controller
{
public function index()
{
return Inertia::render('Test');
}
+ public function download()
+ {
+ $path = storage_path('app/private/sample.pdf');
+ return response()->file($path, [
+ 'Content-Type' => 'application/pdf',
+ 'Content-Disposition' => 'attachment; filename="テストファイル.pdf"',
+ ]);
+ }
}
フロント側は <a> リンクと同じような形で、処理を実装します。
別タブで開かせたい場合は window.open() を使いましょう。
<template>
<div class="m-4 flex gap-2">
<Button as="a" :href="download().url" label="直接ダウンロード" />
<Button label="ダウンロード" @click="onDownload" />
</div>
</template>
<script setup lang="ts">
import Button from 'primevue/button'
import { download } from '@/routes/tests'
const onDownload = () => {
window.open(download().url, '_blank')
}
</script>
こんな感じですね。
ボタンを押すと直接ダウンロード処理が実行されます。
PDf などブラウザが直接表示に対応しているものは inline 表示もできます。
return response()->file($path, [
'Content-Type' => 'application/pdf',
- 'Content-Disposition' => 'attachment; filename="テストファイル.pdf"',
+ 'Content-Disposition' => 'inline; filename="テストファイル.pdf"',
]);
inline のときは、window.open() がおススメですが、直接ダウンロードなら、どっちでもいいと思いますね。ただ処理のエラーが出ると Inertia ごとエラー表示となるので、別タブ利用がおススメです。
その場でファイルを生成する場合
これはボタンを押したときにデータベースの値を加工して、ファイルとして出力したい場合ですね。
画像の加工などもこちらのバターンになります。
では分かりやすいように Excel を生成してみます。
生成には PhpSpreadsheet を利用します。
$ composer require phpoffice/phpspreadsheet
そしたら、Excel生成はサンプルをそのまま持ってきます。
その場で生成する場合は response()->streamDownload() というものを利用します。
これは PHP のストリーム(書き込み先)を通信に直接つなぐ方法です。
public function download()
{
$spreadsheet = new Spreadsheet();
$activeWorksheet = $spreadsheet->getActiveSheet();
$activeWorksheet->setCellValue('A1', 'Hello World !');
$writer = new Xlsx($spreadsheet);
return response()->streamDownload(function () use ($writer) {
$writer->save('php://output');
}, null, [
'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'Content-Disposition' => 'attachment; filename="hello_world.xlsx"',
]);
}
ボタンを押してみると、Excel ファイルが落ちてくると思います。
stream で返すことで一時ファイルの処理などいらずで、動的生成が簡単に行えます。
メモリ効率も良いため、いいことだらけです。
ファイル生成ごときでバッジ処理はしたくないんじゃ~
管理項目が増えすぎてバグの元。。。
おわりに
ファイルを扱う際は、あえて Inertia.js の外に出るのがポイントです。
ここさえ気を付ければ、Laravel のお作法通りに利用できます!
なので POST に変えたい場合もいい感じに実現できそうですよね。
あ、ちなみに PDF 出力に関しては、過去記事を書いているので一読の価値ありです!
もう去年の記事だって。と気が進むのは早い...。



