LaravelでCSVファイル形式でダウンロードする機能を紹介します。データベースに保存されているすべてのデータをCSVと、キーワードで絞り込んだデータをCSVファイル形式でダウンロード出来る機能を実装します。
本編では、ソースコードの紹介だけでなく、新しくプロジェクトを作成して進めます。ソースコードだけ必要な方はRoutesから読み進めていって下さい。
なお、開発環境は紹介してませんので、開発環境をご用意ください。
目次
完成イメージ
まずは完成イメージを紹介します。
Sampleデータベースの一覧表示画面
サンプルテーブルのデータを一覧で表示しています。絞り込み機能でSample1、Sample2、Sample3のいずれかにテキストでHitした記事を表示出来るようになっています。
※データはダミーです。
CSV形式でダウンロードしたファイル
Export to CSVをクリックするとCSVファイルが出力されます。
環境
LaravelでLAMP環境を構築しています。
Laravel: 5.7
PHP: 7.2.13
Mysql: 5.7.24
CentOS Linux: 7.4.1708
Apache: 2.4.6
Vagrant: 2.2.2
Laravelのインストール
それでは早速進めていきましょう。まずは新規プロジェクトを作成します。
Composerをダウンロード
1 |
composer global require laravel/installer |
export名称でプロジェクトを作成
1 |
composer create-project --prefer-dist laravel/laravel export |
データベースを作成
データベース名称はexportでデータベースを作成します。
Vagrantにsshでログインして、mysql -u root -pでmysqlにログインしてから以下のコマンドを実行します。
※この記事でのコマンドの実行は、全てvagrantでsshしてディレクトリまで移動した状態で実行してください。
1 |
CREATE DATABASE export CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; |
Samplesテーブルの作成
次にSamplesテーブルを作成します。
migrationファイルの作成
migrationファイルを作成します。
1 |
php artisan make:migration create_samples_table |
migrationファイルの変更
作成したらファイルを以下のようにします。ファイルはdatabase/migrations/2019_02_25_111508_create_samples_table.phpです。
※migrationファイルは日付や時間によってファイル名が変わります。
Sampleテーブルのデータ構成
id(Auto Increments)
sample1(Text形式)
sample2(Text形式)
sample3(Text形式)
created_at(Laravelが持つtimestamp機能)
updated_at(Laravelが持つtimestamp機能)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateSamplesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('samples', function (Blueprint $table) { $table->increments('id'); $table->text('sample1')->nullable(); $table->text('sample2')->nullable(); $table->text('sample3')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('samples'); } } |
migrationを実行します。
1 |
php artisan migrate |
Seederを使ってテストデータの登録
Seederを使ってテスト用のデータを登録します。
seederファイルを作成
以下のコマンドを実行して、SamplesTableSeederを作成してください。
1 |
php artisan make:seeder SamplesTableSeeder |
seederファイルの編集
作成したらファイルを以下のようにします。ファイルはdatabase/seeds/SamplesTableSeeder.phpです。6つのカラムを作成しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<?php use Illuminate\Database\Seeder; class SamplesTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { DB::table('samples')->insert([ [ "sample1" => "田中太郎", "sample2" => "男性", "sample3" => "あなたはほかとにかくその病気者というものの時を違えないた。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], [ "sample1" => "山田太郎", "sample2" => "男性", "sample3" => "おもに今を永続目は近頃この実在でしでだけがしのでしまったには反抗しゃべっうますて、こうにはやっつけですんんない。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], [ "sample1" => "佐藤花子", "sample2" => "女性", "sample3" => "双方に離れたのはさぞ今朝をまずますたない。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], [ "sample1" => "田中太郎", "sample2" => "男性", "sample3" => "あなたはほかとにかくその病気者というものの時を違えないた。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], [ "sample1" => "山田太郎", "sample2" => "男性", "sample3" => "おもに今を永続目は近頃この実在でしでだけがしのでしまったには反抗しゃべっうますて、こうにはやっつけですんんない。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], [ "sample1" => "佐藤花子", "sample2" => "女性", "sample3" => "双方に離れたのはさぞ今朝をまずますたない。", "created_at" => new DateTime(), "updated_at" => new DateTime() ], ]); } } |
DatabaseSeederを編集
seederを実行させるためにDatabaseSeederを以下のようにします。ファイルはdatabase/seeds/DatabaseSeeder.phpです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(SamplesTableSeeder::class); } } |
Seederの実行
1 |
composer dump-autoload |
1 |
php artisan db:seed |
以上でテストデータの登録が完了です。
Routes
routeを設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php /* |-------------------------------------------------------------------------- | 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('/', function () { return view('welcome'); }); Route::get('/sample', 'SampleController@index')->name('index.sample'); Route::get('/sample/export{keyword?}', 'SampleController@export')->name('export.sample'); |
最後の2行を追加します。
Route::get(‘/sample’, ‘SampleController@index’)->name(‘index.sample’);
Route::get(‘/sample/export{keyword?}’, ‘SampleController@export’)->name(‘export.sample’);
View
続いて、Viewファイルを作成します。Viewファイルはlayouts/app.blade.phpをベースファイルとし、ベースファイルをextendsして/sample/index.blade.phpを使います。
レイアウトを作成
レイアウトを作成します。ファイルはresources/views/layouts/app.blade.phpです。
layoutsフォルダを作成してからapp.blade.phpファイルを作成してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Export</title> <link rel="stylesheet" href="css/app.css"> </head> <body> <section class="frame"> <div class="container"> @yield('content') </div> </section> </body> </html> |
Viewを作成
viewファイルを作成します。ファイルはresources/views/sample/index.blade.phpです。
sampleディレクトリを作成してからindex.blade.phpを作成してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
@extends('layouts.app') @section('content') <h1 class="my-5">This is Sample Index Page</h1> <form method="get" action=""> <div class="row"> <div class="col-9"> <div class="form-group"> <input type="text" class="form-control" id="keyword" name="keyword" placeholder="Search..." value=""> </div> </div> <div class="col-3"> <button id="s" type="submit" class="btn btn-primary btn-block font-weight-bold">Search</button> </div> </div> </form> <div class="mb-3"> <a href="{{ route('export.sample', ['keyword' => $keyword]) }}" class="btn btn-primary font-weight-bold"><i class="fas fa-download"></i> Export to CSV</a> </div> <div class="small"> <table class="table table-striped"> <thead> <tr> <th>ID</th> <th>Sample1</th> <th>Sample2</th> <th>Sample3</th> <th>Created</th> <th>Updated</th> </tr> </thead> <tbody> @foreach( $sample_list as $sample ) <tr> <td>{{ $sample->id }}</td> <td>{{ $sample->sample1 }}</td> <td>{{ $sample->sample2 }}</td> <td>{{ $sample->sample3 }}</td> <td>{{ $sample->created_at }}</td> <td>{{ $sample->updated_at }}</td> </tr> @endforeach </tbody> </table> </div> @endsection |
18行目の{{ route(‘export.sample’, [‘keyword’ => $keyword]) }}でボタンを押すと、/sample/exportへリンクするようにしています。Keywordを渡しているのは、CSV出力する際に、キーワードで絞り込んでリストのみを出力するためです。
Model
モデルを作成します。
以下のコマンドを実行してSampleモデルファイルを作成してください。
1 |
php artisan make:model Sample |
作成したファイルを以下に変更します。ファイルはapp/Sample.phpです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; class Sample extends Model { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'sample1', 'sample2', 'sample3', ]; public function scopeSearch($query, $keyword) { return $query->where('sample1','like', '%'. $keyword .'%') ->orWhere('sample2','like', '%'. $keyword .'%') ->orWhere('sample3','like', '%'. $keyword .'%') ->get(); } } |
キーワードで検索された場合に、sample1、sample2、sample3のいずれかにテキストが含まれるデータを取得します。これにより絞り込み機能を実装しています。
Controller
以下のコマンドを実行して、SampleControllerを作成してください。
1 |
php artisan make:controller SampleController |
作成したファイルを以下に変更します。ファイルはapp/Http/Controllers/SampleController.phpです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<?php namespace App\Http\Controllers; use Symfony\Component\HttpFoundation\StreamedResponse; use Illuminate\Http\Request; use App\Sample; use DB; class SampleController extends Controller { /** * Show Sample List. * * @return \Illuminate\Http\Response */ public function index( Request $request ) { // キーワードで検索 $keyword = $request->keyword; $sample_list = Sample::search($keyword); return view('sample.index',['sample_list'=>$sample_list, 'keyword' => $keyword]); } /** * Export Sample List with csv * @return Symfony\Component\HttpFoundation\StreamedResponse */ public function export( Request $request ) { $response = new StreamedResponse (function() use ($request){ // キーワードで検索 $keyword = $request->keyword; $stream = fopen('php://output', 'w'); // 文字化け回避 stream_filter_prepend($stream,'convert.iconv.utf-8/cp932//TRANSLIT'); // タイトルを追加 fputcsv($stream, ['id','sample1','sample2','sample3','created_at','updated_at']); Sample::where('sample1', 'LIKE', '%'.$keyword.'%')->chunk( 1000, function($results) use ($stream) { foreach ($results as $result) { fputcsv($stream, [$result->id,$result->sample1,$result->sample2,$result->sample3,$result->created_at,$result->updated_at]); } }); fclose($stream); }); $response->headers->set('Content-Type', 'application/octet-stream'); $response->headers->set('Content-Disposition', 'attachment; filename="SampleList.csv"'); return $response; } } |
以上で完了となります。もし不明点などがあればコメント欄からお願いします。
LEAVE A REPLY