【Laravel】CSVエクスポートの実装紹介

今回はLaravelでCSVのエクスポート機能の紹介です。
インポートの機能はこちらで紹介しています。
コントローラーの作成
UserControllerを作成します。
既に生成済みのコントローラーにエクスポートを追加する場合は、飛ばしてください。
php artisan make:controller UserController
マイグレーション
users
テーブルを作成するマイグレーションファイルを作成します。
こちらもデータベースやモデルが既にある方は飛ばしてください。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id(); // 自動インクリメントのIDフィールド
$table->string('first_name');
$table->string('last_name');
$table->string('email')->unique();
$table->string('password');
$table->string('gender');
$table->string('account_role');
$table->timestamp('email_verified_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
コントローラー
コントローラーでは、サービスを実行して、返されたデータを使ってCSVをダウンロードするようにします。
<?php
namespace App\Http\Controllers;
use App\Services\UserExportService;
use Illuminate\Http\Request;
class UserController extends Controller
{
protected $userExportService;
// コンストラクタでUserExportServiceを依存注入
public function __construct(UserExportService $userExportService)
{
$this->userExportService = $userExportService;
}
// CSVエクスポート機能を提供するメソッド
public function exportCsv(Request $request)
{
// UserExportServiceのexportメソッドを呼び出してCSVデータを生成
$response = $this->userExportService->export();
// ストリームダウンロードレスポンスを返す
return response()->streamDownload(function() use ($response) {
// CSVの内容を出力
$handle = fopen('php://output', 'w');
fwrite($handle, $response['contents']);
fclose($handle);
},
// ダウンロードされるファイル名
$response['filename'],
// HTTPレスポンスヘッダー
$response['headers']);
}
}
ストリームダウンロードレスポンスを返す
response()->streamDownload
response()->streamDownload
とはストリーミングダウンロードを行うためのメソッドです。
CSVファイルのストリームダウンロードレスポンスを返します。
大きなファイルをサーバーからクライアントにダウンロードする際に役立ちます。
このメソッドを使用すると、サーバー上のメモリ消費を抑えながらファイルをダウンロードすることができます。
return response()->streamDownload(function() use ($response) {
$handle = fopen('php://output', 'w');
fwrite($handle, $response['contents']);
fclose($handle);
},
クロージャ
response()->streamDownloadの引数には、ストリームとして出力したいデータを生成するクロージャ(無名関数)を渡します。
このクロージャ内で、データを逐次出力するコードを書きます。
php://output
ストリーム
php://output
は、直接PHPの出力バッファに書き込むための特殊なストリームラッパーです。
これを使うことで、データを直接クライアントに送信することができます。
fwrite
とfclose
fwrite
関数を使って、CSVデータをphp://output
ストリームに書き込みます。fclose
関数でストリームを閉じます。
ファイル名とヘッダー
第二引数にはダウンロードされるファイル名を指定し、
第三引数にはHTTPレスポンスヘッダーを指定します。
これにより、ブラウザがファイルを正しくダウンロードできるようになります。
fopenとは
fopen
とは、ファイルを読み取り、書き込み、または新しいファイルを作成することができます。
$handle = fopen('ファイル名', 'モード');
'r'
: 読み取り専用 ファイルが存在しなければエラーを出します。'w'
: 書き込み専用 ファイルが存在しなければ新規作成し、存在する場合は内容を削除します。'a'
: 追記専用。ファイルが存在しなければ新規作成し、存在する場合はファイルの末尾に追記します。'x'
: 書き込み専用。ファイルが存在する場合はエラーを出します。
$handle = fopen('php://output', 'w');
fopen
関数を使って、PHPの出力バッファ(php://output
)を開きます。php://output
は、直接PHPの出力バッファに書き込むための特殊なストリームです。
CSVの内容を出力
fwrite
を使用して、php://output
ストリームにCSVデータを書き込みます。fclose
でストリームを閉じます。
fwrite
とは
fwrite
関数は、ファイルやストリームにデータを出力できます。
fwrite ( resource $handle , string $string [, int $length ] )
- handle: 書き込み先のファイルポインタリソース。
fopen
関数で取得します。 - $string: 書き込む文字列データ。
- $length: オプションで、書き込むバイト数を指定します。指定しない場合は、文字列全体が書き込まれます。戻り値: 書き込まれたバイト数を返します
fwrite(
$handle, // 書き込み対象のファイルポインタ(出力バッファを指す 'php://output')
$response['contents']. // 書き込むデータ(生成されたCSVの内容)
);
fwrite
関数を使って、生成されたCSVデータ($response['contents']
)を出力バッファに書き込みます。
fclose
とは
fclose
関数を使って、出力バッファを閉じます。
これにより、書き込み操作が完了し、データがクライアントに送信されます。
fclose($handle); // ファイルを閉じる
モデル
ユーザーモデルを作成します。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'first_name',
'last_name',
'email',
'password',
'gender',
'account_role',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
}
ルーティングの設定
use App\Http\Controllers\UserController;
Route::get('export-users', [UserController::class, 'exportCsv']);
サービス
<?php
namespace App\Services;
use App\Models\User;
class UserExportService
{
// エクスポート処理を実行するメソッド
public function export()
{
// 全ユーザーを取得
$users = User::all();
// CSVデータを生成
$csvData = $this->generateCsv($users);
// ファイル名を生成
$fileName = $this->generateFileName();
// ヘッダーを生成
$headers = $this->generateHeaders($fileName);
// エクスポートデータを返す
return [
'contents' => $csvData, // CSVの内容
'headers' => $headers, // HTTPレスポンスヘッダー
'filename' => $fileName, // ダウンロードされるファイル名
];
}
// ユーザーリストからCSVデータを生成するメソッド
protected function generateCsv($users)
{
// CSVのヘッダー行
$csvHeaders = ['ID', 'FirstName', 'LastName', 'Email', 'Gender', 'Account Role'];
$csv = implode(',', $csvHeaders) . "\n";
// 各ユーザー情報をCSV形式で追加
foreach ($users as $user) {
$csv .= implode(',', [
$user->id, // ユーザーID
$user->first_name, // First Name
$user->last_name, // Last Name
$user->email, // Email
$user->gender, // Gender
$user->account_role, // Account Role
]) . "\n";
}
return $csv; // 生成されたCSVデータを返す
}
// ファイル名を生成するメソッド
protected function generateFileName()
{
// 現在の日付と時刻を含むファイル名を生成
return 'users_' . date('Ymd_His') . '.csv';
}
// HTTPレスポンスヘッダーを生成するメソッド
protected function generateHeaders($fileName)
{
return [
'Content-Type' => 'text/csv', // コンテンツタイプ
'Content-Disposition' => "attachment; filename=\"$fileName\"", // ファイルのダウンロード用ヘッダー
];
}
}
CSVのヘッダー行を作成
implode
関数を使ってCSVのヘッダー行のデータ行を作成します。
// CSVのヘッダー行
$csvHeaders = ['ID', 'FirstName', 'LastName', 'Email', 'Gender', 'Account Role'];
$csv = implode(',', $csvHeaders) . "\n";
implodeとは
- $glue: 配列の各要素を結合するために使う区切り文字。
- $pieces: 結合する配列。
implode(string $glue , array $pieces)
// CSVのヘッダー行
$csvHeaders = ['ID', 'FirstName', 'LastName', 'Email', 'Gender', 'Account Role'];
$csv = implode(',', $csvHeaders) . "\n";
$csvHeadersの各要素(’ID’, 'FirstName’, 'LastName’, 'Email’, 'Gender’, 'Account Role’)をカンマで結合し、文字列に変換します。
結合された文字列の末尾に改行文字(\n
)を追加します。
これにより、CSVのヘッダー行が完成します。
CSVのデータを作成
implode
関数を使ってCSVのデータ行を作成します。
// 各ユーザー情報をCSV形式で追加
foreach ($users as $user) {
$csv .= implode(',', [
$user->id, // ユーザーID
$user->first_name, // First Name
$user->last_name, // Last Name
$user->email, // Email
$user->gender, // Gender
$user->account_role, // Account Role
]) . "\n";
}
ファイル名を作成
現在の日付と時刻を含むファイル名を生成します。
これにより、エクスポートされたファイルがユニークな名前を持つようになります。
return 'users_' . date('Ymd_His') . '.csv';
HTTPレスポンスヘッダーを生成
Content-Type
とContent-Disposition
ヘッダーを設定して、ブラウザがファイルを正しくダウンロードできるようにします。
// HTTPレスポンスヘッダーを生成するメソッド
protected function generateHeaders($fileName)
{
return [
'Content-Type' => 'text/csv', // コンテンツタイプ
'Content-Disposition' => "attachment; filename=\"$fileName\"", // ファイルのダウンロード用ヘッダー
];
}
Content-Type
とContent-Disposition
ヘッダーを設定して、ブラウザがファイルを正しくダウンロードできるようにします。