Export checkin to CSV
This commit is contained in:
		@@ -3,6 +3,7 @@
 | 
			
		||||
namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\DeactivatedUser;
 | 
			
		||||
use App\Services\CheckinCsvExporter;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
@@ -71,6 +72,36 @@ class SettingController extends Controller
 | 
			
		||||
        return redirect()->route('setting.privacy')->with('status', 'プライバシー設定を更新しました。');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function export()
 | 
			
		||||
    {
 | 
			
		||||
        return view('setting.export');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function exportToCsv(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $validated = $request->validate([
 | 
			
		||||
            'charset' => ['required', Rule::in(['utf8', 'sjis'])]
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $charsets = [
 | 
			
		||||
            'utf8' => 'UTF-8',
 | 
			
		||||
            'sjis' => 'SJIS-win'
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $filename = tempnam(sys_get_temp_dir(), 'tissue_export_tmp_');
 | 
			
		||||
        try {
 | 
			
		||||
            $exporter = new CheckinCsvExporter(Auth::user(), $filename, $charsets[$validated['charset']]);
 | 
			
		||||
            $exporter->execute();
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            unlink($filename);
 | 
			
		||||
            throw $e;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
            ->download($filename, 'TissueCheckin_' . date('Y-m-d_H-i-s') . '.csv')
 | 
			
		||||
            ->deleteFileAfterSend(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function deactivate()
 | 
			
		||||
    {
 | 
			
		||||
        return view('setting.deactivate');
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								app/Services/CheckinCsvExporter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/Services/CheckinCsvExporter.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Services;
 | 
			
		||||
 | 
			
		||||
use App\User;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use League\Csv\Writer;
 | 
			
		||||
 | 
			
		||||
class CheckinCsvExporter
 | 
			
		||||
{
 | 
			
		||||
    /** @var User Target user */
 | 
			
		||||
    private $user;
 | 
			
		||||
    /** @var string Output filename */
 | 
			
		||||
    private $filename;
 | 
			
		||||
    /** @var string Output charset */
 | 
			
		||||
    private $charset;
 | 
			
		||||
 | 
			
		||||
    public function __construct(User $user, string $filename, string $charset)
 | 
			
		||||
    {
 | 
			
		||||
        $this->user = $user;
 | 
			
		||||
        $this->filename = $filename;
 | 
			
		||||
        $this->charset = $charset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function execute()
 | 
			
		||||
    {
 | 
			
		||||
        $csv = Writer::createFromPath($this->filename, 'wb');
 | 
			
		||||
        $csv->setNewline("\r\n");
 | 
			
		||||
        if ($this->charset === 'SJIS-win') {
 | 
			
		||||
            $csv->addStreamFilter('convert.mbstring.encoding.UTF-8:SJIS-win');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $header = ['日時', 'ノート', 'オカズリンク'];
 | 
			
		||||
        for ($i = 1; $i <= 32; $i++) {
 | 
			
		||||
            $header[] = "タグ{$i}";
 | 
			
		||||
        }
 | 
			
		||||
        $csv->insertOne($header);
 | 
			
		||||
 | 
			
		||||
        DB::transaction(function () use ($csv) {
 | 
			
		||||
            // TODO: そんなに読み取り整合性を保つ努力はしていないのと、chunkの件数これでいいか分からない
 | 
			
		||||
            $this->user->ejaculations()->with('tags')->orderBy('ejaculated_date')
 | 
			
		||||
                ->chunk(1000, function ($ejaculations) use ($csv) {
 | 
			
		||||
                    foreach ($ejaculations as $ejaculation) {
 | 
			
		||||
                        $record = [
 | 
			
		||||
                            $ejaculation->ejaculated_date->format('Y-m-d H:i'),
 | 
			
		||||
                            $ejaculation->note,
 | 
			
		||||
                            $ejaculation->link,
 | 
			
		||||
                        ];
 | 
			
		||||
                        foreach ($ejaculation->tags as $tag) {
 | 
			
		||||
                            $record[] = $tag->name;
 | 
			
		||||
                        }
 | 
			
		||||
                        $csv->insertOne($record);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,6 +10,8 @@
 | 
			
		||||
                       href="{{ route('setting') }}"><span class="oi oi-person mr-1"></span> プロフィール</a>
 | 
			
		||||
                    <a class="list-group-item list-group-item-action {{ Route::currentRouteName() === 'setting.privacy' ? 'active' : '' }}"
 | 
			
		||||
                       href="{{ route('setting.privacy') }}"><span class="oi oi-shield mr-1"></span> プライバシー</a>
 | 
			
		||||
                    <a class="list-group-item list-group-item-action {{ Route::currentRouteName() === 'setting.export' ? 'active' : '' }}"
 | 
			
		||||
                       href="{{ route('setting.export') }}"><span class="oi oi-data-transfer-download mr-1"></span> データのエクスポート</a>
 | 
			
		||||
                    <a class="list-group-item list-group-item-action {{ Route::currentRouteName() === 'setting.deactivate' ? 'active' : '' }}"
 | 
			
		||||
                       href="{{ route('setting.deactivate') }}"><span class="oi oi-trash mr-1"></span> アカウントの削除</a>
 | 
			
		||||
                    {{--<a class="list-group-item list-group-item-action {{ Route::currentRouteName() === 'setting.password' ? 'active' : '' }}"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								resources/views/setting/export.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								resources/views/setting/export.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
@extends('setting.base')
 | 
			
		||||
 | 
			
		||||
@section('title', 'データのエクスポート')
 | 
			
		||||
 | 
			
		||||
@section('tab-content')
 | 
			
		||||
    <h3>データのエクスポート</h3>
 | 
			
		||||
    <hr>
 | 
			
		||||
    <p>チェックインデータをCSVファイルとしてダウンロードすることができます。</p>
 | 
			
		||||
    <form class="mt-4" action="{{ route('setting.export.csv') }}" method="get">
 | 
			
		||||
        {{ csrf_field() }}
 | 
			
		||||
        <div class="mb-2"><strong>文字コード</strong></div>
 | 
			
		||||
        <div class="form-check">
 | 
			
		||||
            <label><input class="form-check-input" type="radio" name="charset" value="utf8" checked>UTF-8</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-check">
 | 
			
		||||
            <label><input class="form-check-input" type="radio" name="charset" value="sjis">Shift_JIS</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <button type="submit" class="btn btn-primary mt-3">ダウンロード</button>
 | 
			
		||||
    </form>
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@push('script')
 | 
			
		||||
@endpush
 | 
			
		||||
@@ -36,6 +36,8 @@ Route::middleware('auth')->group(function () {
 | 
			
		||||
    Route::post('/setting/profile', 'SettingController@updateProfile')->name('setting.profile.update');
 | 
			
		||||
    Route::get('/setting/privacy', 'SettingController@privacy')->name('setting.privacy');
 | 
			
		||||
    Route::post('/setting/privacy', 'SettingController@updatePrivacy')->name('setting.privacy.update');
 | 
			
		||||
    Route::get('/setting/export', 'SettingController@export')->name('setting.export');
 | 
			
		||||
    Route::get('/setting/export/csv', 'SettingController@exportToCsv')->name('setting.export.csv');
 | 
			
		||||
    Route::get('/setting/deactivate', 'SettingController@deactivate')->name('setting.deactivate');
 | 
			
		||||
    Route::post('/setting/deactivate', 'SettingController@destroyUser')->name('setting.deactivate.destroy');
 | 
			
		||||
//    Route::get('/setting/password', 'SettingController@password')->name('setting.password');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user