Laravel 画像をアップロードして表示する

# 目的

- アプリケーションに画像をアップロードして別画面で表示する方法をまとめる

# 環境

- ハードウェア環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.3) |
| ハードウェア | MacBook Pro (16-inch ,2019) |
| プロセッサ | 2.6 GHz 6コアIntel Core i7 |
| メモリ | 16 GB 2667 MHz DDR4 |
| グラフィックス | AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB |

- ソフトウェア環境

| 項目 | 情報 | 備考 |
| --- | --- | --- |
| PHP バージョン | 7.4.3 | Homwbrewを用いて導入 |
| Laravel バージョン | 7.0.8 | commposerを用いて導入 |
| MySQLバージョン | 8.0.19 for osx10.13 on x86_64 | Homwbrewを用いて導入 |

# 事前情報

- 下記の方法、またはそれに準ずる方法で認証機能のついたLaravelアプリが存在すること。
    - [Mac Laravel 7 Authを用いたユーザ登録 ログイン ログアウトなどの機能を作成する](https://qiita.com/miriwo/items/5d4a94e8d2aa06b61530)
- 既存のマイグレーションファイルがマイグレートされていること。
- ログインユーザ毎に別々の画像のアップロードと表示をすることができる様に実装する。(他のログインユーザがアップロードした画像は表示されない)

# 概要

1. テーブルの作成
1. ルーティングの記載
1. コントローラの記載
1. ビューの記載
1. シンボリックリンクの作成
1. 確認

# 詳細

1. テーブルの作成
    1. アプリ名ディレクトリで下記コマンドを実行してモデルファイルとマイグレーションファイルを同時に作成する。

        ```terminal
        $ php artisan make:model Image --migration
        ```
    1. 下記にファイルが作成された事を確認する。
        - `アプリ名ディレクトリ/app/Image.php`
        - `アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php`
    1. アプリ名ディレクトリで下記コマンドを実行してマイグレーションファイルを開く。

        ```terminal
        $ vi database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php
        ```
    1. 開いたマイグレーションファイルを下記の様に記載する。

        ```アプリ名ディレクトリ/database/migrations/YYYY_MM_DD_XXXXXX_create_images_table.php
        <?php
        
        use Illuminate\Database\Migrations\Migration;
        use Illuminate\Database\Schema\Blueprint;
        use Illuminate\Support\Facades\Schema;
        
        class CreateImagesTable extends Migration
        {
            /**
             * Run the migrations.
             *
             * @return void
             */
            public function up()
            {
                Schema::create('images', function (Blueprint $table) {
                    $table->id();
                    //下記を追記する
                    $table->foreignId('user_id');
                    $table->string('file_name');
                    //上記までを追記する
                    $table->timestamps();
                });
            }
        
            /**
             * Reverse the migrations.
             *
             * @return void
             */
            public function down()
            {
                Schema::dropIfExists('images');
            }
        }
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してマイグレーションを行う。

        ```terminal
        $ php artisan migrate
        ```
1. ルーティングの記載
    1. アプリ名ディレクトリで下記コマンドを実行してシンボリックリンクを作成する。

        ```terminal
        $ php artisan storage:link
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

        ```termianl
        $ vi routes/web.php
        ```
    1. 開いたルーティングファイルを下記の様に修正する。

        ```アプリ名ディレクトリ/routes/web.php
        <?php
        
        use Illuminate\Support\Facades\Route;
        
        /*
        |--------------------------------------------------------------------------
        | 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');
        });
        
        Auth::routes();
        
        Route::get('/home', 'HomeController@index')->name('home');

        //下記を追記
        //画像をアップロードするページ
        Route::get('/upload', 'ImageController@input');
        //画像を保存したり画像名をDBに格納する部分
        Route::post('/upload', 'ImageController@upload');
        //保存した画像を表示するページ
        Route::get('/output', 'ImageController@output');
        //上記までを追記
        ```
1. コントローラの記載
    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。
        
        ```terminal
        $ php artisan make:controller ImageController
        ```
    1. 下記のコントローラファイルが作成される。
        - `アプリ名ディレクトリ/app/Http/Controllers/ImageCotroller.php`

    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを開く。

        ```terminal
        vi app/Http/Controllers/ImageController.php
        ```
    1. 開いたコントローラファイルを下記の様に修正する。

        ```アプリ名ディレクトリ/app/Http/Controllers/ImageCotroller.php
        <?php
        
        namespace App\Http\Controllers;
        //下記を追加する
        use Illuminate\Support\Facades\Auth;
        use Illuminate\Http\Request;
        //下記を追加する
        use App\Image;

        class ImageController extends Controller
        {
            //下記を追加する
            public function input()
            {
                return view('image.input');
            }
        
            public function upload(Request $request)
            {
                $this->validate($request, [
                    'file' => [
                        // 必須
                        'required',
                        // アップロードされたファイルであること
                        'file',
                        // 画像ファイルであること
                        'image',
                        // MIMEタイプを指定
                        'mimes:jpeg,png',
                    ]
                ]);
                
                if ($request->file('file')->isValid([])) {
                    $path = $request->file->store('public');
        
                    $file_name = basename($path);
                    $user_id = Auth::id();
                    $new_image_data = new Image();
                    $new_image_data->user_id = $user_id;
                    $new_image_data->file_name = $file_name;
        
                    $new_image_data->save();
        
                    return redirect('/output');
                } else {
                    return redirect()
                        ->back()
                        ->withInput()
                        ->withErrors();
                }
            }
        
            public function output() {
                $user_id = Auth::id();
                $user_images = Image::whereUser_id($user_id)->get();
                return view('image.output', ['user_images' => $user_images]);
            }
            //上記までを追記
        }
        ```
1. ビューの記載
    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

        ```terminal
        $ mkdir resources/views/image
        ```
    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを作成する。

        ```terminal
        $ touch resources/views/image/input.blade.php
        $ touch resources/views/image/output.blade.php
        ```
    1. アプリ名ディレクトリで下記コマンドを実行して画像をアップロードするビューファイルを開く。

        ```terminal
        $ vi resources/views/image/input.blade.php
        ```
    1. 開いたビューファイルを下記の様に記載する。

        ```アプリ名ディレクトリ/resources/views/image/input.blade.php
        @extends('layouts.app')
        
        @section('content')
        <!-- エラーメッセージ。なければ表示しない -->
        @if ($errors->any())
        <ul>
            @foreach($errors->all() as $error)
            <li>{{ $error }}</li>
            @endforeach
        </ul>
        @endif
        
        <!-- フォーム -->
        <form action="/upload" method="POST" enctype="multipart/form-data">
            @csrf
        
            <label for="photo">画像ファイル:</label>
            <input type="file" class="form-control" name="file">
            <br>
            <input type="submit">
        </form>
        @endsection
        ```
    1. アプリ名ディレクトリで下記コマンドを実行して画像をアップロードするビューファイルを開く。

        ```terminal
        $ vi resources/views/image/output.blade.php
        ```
    1. 開いたビューファイルを下記の様に記載する。

        ```アプリ名ディレクトリ/resources/views/image/output.blade.php
        @extends('layouts.app')
                
        @section('content')
            <a href="/upload">画像のアップロードに戻る</a>
            <br>
            @foreach ($user_images as $user_image)
                <img src="{{ asset('storage/' . $user_image['file_name']) }}">
                <br>
            @endforeach
        @endsection
        ```
1. シンボリックリンクの作成
    1. アプリ名ディレクトリで下記コマンドを実行してstrageディレクトリへのシンボリックリンクを作成する。

        ```terminal
        $ php artisan storage:link
        ```
1. 確認
    1. アプリ名ディレクトリで下記コマンドを実行してローカルサーバを起動する。

        ```terminal
        $ php artisan serve
        ```
    1. 下記にアクセスする。
        - [http://127.0.0.1:8000](http://127.0.0.1:8000)
    1. 画面右上の 「LOGIN」もしくは「REGISTER」からログインもしくは新規登録を行う。

        ![Laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b6f7bc70-f380-71da-48ae-8d1d6f8ecd2a.png)

    1. 下記にアクセスする。
        - [http://127.0.0.1:8000/upload](http://127.0.0.1:8000/upload)
    1. ブラウザ上で下記の様に表示される事を確認する。

        ![Laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/0c708259-3f95-199d-0e73-13dca38188e9.png)
 
    1. 「ファイルを選択」をクリックして任意の画像ファイルを開き、「送信」をクリックする。
    1. 下記の様に送信した画像が表示される事を確認する。

        ![Laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a9a91412-294c-4db8-66c6-51a8efd7dda0.png)

    1. 同アプリで現在ログインしているユーザとは別にユーザを作成しログインを行い、先とは違う画像をアップロードして先の画像とは別の画像表示される事を確認する。