【Laravel】laravelでユーザー管理（ログイン、新規登録）、ファイルのアップロード機能の実装


作成にあたって、参考にしたサイト
[laravle学習帳](https://reffect.co.jp/laravel/how_to_upload_file_in_laravel)

#要件定義

ユーザー管理機能（新規登録、ログイン）を実装。

ログインしたら
画像投稿、投稿画像一覧の機能が使えるようにする。


その他
・ログインしているユーザーidと投稿画像のidを紐つけて、どのユーザーが投稿したか管理する。

#データベース設計

- プロジェクト名：laravel_fileup
- 画像投稿のモデル、テーブルはPost、postsとする
　
##postsテーブルのカラム設計

- id
- tile:画像のタイトル
- path:画像の保存先のパス
- user_id：どのユーザーが投稿したかのため

##usersテーブルのカラム設計

こちらは自動で作成されるので割愛

#プロジェクトの作成

```
$ composer create-project --prefer-dist laravel/laravel='5.8' laravel_fileup
```

#.envファイルの編集


#database.sqliteの作成

#ログイン機能の実装

##make::authを使う

```
$ php artisan make:auth
```

##ログイン時とログアウト時の遷移先を変更する

参考記事：https://qiita.com/LowSE01/items/ffa256439f665740cc8f

```php:app/Http/controllers/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

+ use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
+    protected $redirectTo = '/posts/create';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

+    public function logout(Request $request)
+   {
+       $this->guard()->logout();
+       $request->session()->flush();
+       $request->session()->regenerate();

+       return redirect('/login');//ログアウト時の遷移先
+  }

}

```

##fileのアップロード用モデルとマイグレーションを作成

```
$ php artisan make:model Post -m
Model created successfully.
Created Migration: 2019_12_30_005951_create_posts_table
```

##migrationファイルの修正（タイトルとパスのカラムを作成）

```php:database/migrations/2019_12_30_005951_create_posts_table.php
            $table->bigIncrements('id');
+           $table->unsignedInteger('user_id');
+           $table->string('title');
+           $table->text('path');
            $table->timestamps();
+           $table->foreign('user_id')->references('id')->on('users');
```

##マイグレーションの実行

```
$ php artisan migrate
```

##Post.php（ポストモデルの修正）

postsテーブルへの書き込み権限を付与
Userモデルとの紐付けを記載

```php:app/Post.php
class Post extends Model
{
+    protected $fillable = ['title','path'];

+    public function user() {
+    return $this->belongTo('App\User');}
```

##Userモデルの修正

Postモデルとの紐付けを記載

```php:app/User.php
+  public function posts() {
+    return $this->hasMany('App\Post');
+    }
```

#ファイルのアップロード等を管理するコントローラーの作成

```
$ php artisan make:controller PostsController
Controller created successfully.
```


#ファイル操作に関連するroutesを作成

参考記事
https://qiita.com/sympe/items/9297f41d5f7a9d91aa11

```php:routes/web.php
// Route::get('/', function () {return view('welcome');});
Auth::routes();
// Route::get('/home', 'HomeController@index')->name('home');
+ Route::resources('posts','PostsController');
```

#新規投稿〜画像保存までの流れを作成



##ファイルアップロード用のフォームを作成

```php:resources/views/posts/create.blade.php
@extends('layouts.app')

@section('content')

<div class="container">
  <form method="post" action="/posts" enctype="multipart/form-data">
	{{ csrf_field() }}
  <div class="form-group">
  <label>投稿する画像のタイトルを入力してください</label>
  <input type="text" name="title" class="form-control col-sm-4" value="{{ old('title')}}">
  </div>

  <div class="form-group">
  <label>投稿する画像を選んでください</label>
	<input type="file" id="file" name="file" class="form-control col-sm-4">
  </div>
  <div class="form-group">
	<button type="submit" class="btn btn-primary">アップロード</button>
  </div>
	</form>

  @if ($errors->has('title'))
  <div class="alert alert-danger" role="alert">{{$errors->first('title')}}</div>
  @endif


  @if ($errors->has('file'))
  <div class="alert alert-danger" role="alert">{{$errors->first('file')}}</div>
  @endif


  @if (session('flash_message'))
  <div class="alert alert-success" role="alert">{{ session('flash_message')}}</div>
  @endif

</div>


@endsection

```


コントローラーの設定

```php:app
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Post;
use App\User;
use App\Http\Requests\CreatePostRequest;
use Carbon\Carbon;

class PostsController extends Controller
{
    //ログインしていないと、PostsController内の処理ができないようにする。
    public function __construct() {
      $this->middleware('auth');
    }

    public function index() {
      $posts = Post::all();
      return view('posts.index')->with('posts',$posts);
    }

    public function create() {
      return view('posts.create');
    }

    public function store(CreatePostRequest $request) {
            $nowtime = Carbon::now();
      //ログインしているユーザーを取得
      $user = Auth::user();
      //ファイル名取得
      $filename = $user->id . "_".$nowtime."_". $request->file('file')->getClientOriginalName();
      //storage/app/publicにファイルを保存する
      $request->file('file')->storeAs('public',$filename);

      $post = new Post();
      $post->title = $request->title;
      $post->path = '/storage/'.$filename;
      $user->posts()->save($post);
      session()->flash('flash_message', '投稿が完了しました');
      return redirect('posts/create');
    }
}
```

##バリデーションの設定をする。

バリデーション用のファイルを作成する。

```
$ php artisan make:request CreatePostRequest
Request created successfully.
```

CreatePostRequestを編集する。

```php:app/Http/Request/CreatePostRequest.php
    public function rules()
    {
        return [
+         'title' => 'required',
+         'file' => 'required|image',
        ];
    }

+    public function messages() {
+    return [
+       'title.required' => 'タイトルが入力されていません',
+        'file.required' => '画像を選択してください',
+        'file.image' => '画像ファイルを選択してください',
+    ];

```

##コントローラーに適用する

作成したCreatePostRequestを読み込む
store()メソッドの引数に入れる。

```php:app/Http/controllers/PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Post;
use App\User;
+ use App\Http\Requests\CreatePostRequest;
use Carbon\Carbon;
・
・
・

+ public function store(CreatePostRequest $request) {
```


##シンボリックリンクの作成

```
$ php artisan storage:link
The [public/storage] directory has been linked.
```

#取得した画像をの一覧表示を実装する。

・やりたいこと画像のタイトルと画像の表示

```php:resources/views/posts/index.blade.php
@extends('layouts.app')

@section('content')

<div class="container">
  <div class="row">
    @foreach($posts as $post)
    <div class="col-md-3" style="margin-top:10px;">
      <img src="{{$post->path}}" width="95%">
    <h3 style="margin-top:3px;text-align:center;">タイトル：{{ $post->title}}</h3>
  </div>
    @endforeach
</div>

@endsection
```

##編集モードにて削除コマンドをつける

##editメソッドの作成

index.blade.phpに編集モードへのリンクを作成

```php:resources/views/posts/index.blade.php
    @foreach($posts as $post)
    <div class="col-md-3" style="margin-top:10px;">
+      <a href="{{ action('PostsController@edit',$post) }}"><img src="{{$post->path}}" width="95%"></a>
    <h3 style="margin-top:3px;text-align:center;">「{{ $post->title}}」</h3>
  </div>
    @endforeach
```

PostsControlerのeditメソッドを作成

```php:app/Http/Controllers/PostsController.php
    public function edit(Post $post) {
      return view('posts.edit')->with('post',$post);
    }
```

編集ビューの作成
編集ビューに削除ボタン作成

```php:resources/views/posts/edit.blade.php
@extends('layouts.app')

@section('content')

<div class="container">
  <div>
  <img src="{{$post->path}}" width="80%">
  </div>


  <form action="{{ action('PostsController@destroy',$post)}}" method="post">
  {{csrf_field()}}
  {{method_field('delete')}}
      <div class="row" style="margin-top:30px;">
    <button type="submit" class="btn btn-danger col-sm-3">削除する</button>
    </div>
  </form>

</div>

@endsection
```

PostsControllerにdestroyメソッド（削除メソッド）作成

```php:app/Http/controllers/PostsCotnroller.php
public function destroy(Post $post) {
      $post->delete();
      session()->flash('flash_message', '投稿画像を削除しました');
      return redirect('/');
    }
```

#auth関連で作成したビューを日本語化する

参考記事
https://qiita.com/miya-krow/items/05170462b2f092c95dfa

##config/appを変更する

```php:config/app.php
'locale' => 'ja',
'fallback_locale' => 'ja',
```
en:Engilish
ja:Japanese

##ja.jsonファイルを作成して対応する

```
$ vi resources/lang/ja.json
```



```json:resources/lang/ja.json
{  "Login"    :"ログイン",
   "Register" :"新規登録",
   "Password" : "パスワード",
   "E-Mail Address": "メールアドレス",
   "Logout":"ログアウト",
   "Name": "ニックネーム",
   "Confirm Password": "パスワード（もう一度入力）"
}
```

#その他

##パスワードリセット機能は実装しないので、使えないようにする。

対象部をコメントアウトする

```html:resources/views/auth/login.blade.php
                        <!-- <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div> -->

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>

                                <!-- @if (Route::has('password.request'))
                                    <a class="btn btn-link" href="{{ route('password.request') }}">
                                        {{ __('Forgot Your Password?') }}
                                    </a>
                                @endif -->
                            </div>
```

##urlに直接入力してら、indexに飛ばすようにする。

```php:routes/web.php
Route::get('/', 'PostsController@index');
Auth::routes();
+ Route::get('/password/email', function() {return redirect('/');});
+ Route::get('/password/reset', function() {return redirect('/');});
// Route::get('/home', 'HomeController@index')->name('home');
Route::resource('posts','PostsController');
```


以上です。