Laravel webアプリケーション作成part2 CRUD操作/ログイン機能

Laravel webアプリケーション作成part1 プロジェクト作成〜ブラウザ表示
からの続きです。
https://qiita.com/machiryu/items/d8f7908a3d07f5c35f17

# ログイン機能実装
```
$ composer require laravel/ui
Using version ^3.2 for laravel/ui
(省略)
Package manifest generated successfully.
74 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
```
```
$ php artisan ui vue --auth
Vue scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.

 The [layouts/app.blade.php] view already exists. Do you want to replace it? (yes/no) [no]:
 と聞かれるので、yes。
 > yes

Authentication scaffolding generated successfully.
[machidaryo CombiOkashi]$ php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
```

```php artisan serve```でサーバ起動しブラウザで確認すると、
Login,Registerが表示される。
がレイアウトいまいち。

レイアウトを整える。上のコマンド実行時に
```Please run "npm install && npm run dev" to compile your fresh scaffolding.```と表示されていたので、そうする。

Vue,Angular,React(フレームワーク)のインストールということ。

```
$ npm install
(省略)
   ╭───────────────────────────────────────────────────────────────╮
   │                                                               │
   │      New major version of npm available! 6.14.10 → 7.5.3      │
   │   Changelog: https://github.com/npm/cli/releases/tag/v7.5.3   │
   │               Run npm install -g npm to update!               │
   │                                                               │
   ╰───────────────────────────────────────────────────────────────╯
```
と出たので、```npm install -g npm```を実行してみる。

が、うまくいかなかったので、次の実行コマンドを実行してみた。

```
$ npm run dev

> @ dev /Users/machidaryo/phpstudy202012/CombiOkashi
> npm run development

> @ development /Users/machidaryo/phpstudy202012/CombiOkashi
> mix

 	Additional dependencies must be installed. This will only take a moment.
 	Running: npm install vue-loader@^15.9.5 --save-dev --legacy-peer-deps
 	Finished. Please run Mix again.
```
エラー。調べてみると、Laravel Mixとういやつをアップグレードしたらいけそうという記事があったので、
```npm install laravel-mix```をして、再度runするといけた。

```
$ npm run dev
(省略)
99% done plugins BuildOutputPlugin

   Laravel Mix v6.0.11

✔ Compiled Successfully in 6941ms
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────┐
│                                                                                                                                             File │ Size    │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────┤
│                                                                                                                                       /js/app.js │ 1.4 MiB │
│                                                                                                                                      css/app.css │ 179 KiB │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────┘
```
デザインがいい感じに。ヘッダー右部分にLogin,Registerボタンが現れた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/0094d23d-c909-b037-7e6c-68a74fa35695.png)
Login画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/a3fafe6b-7acc-92fa-a78f-243f2e893a96.png)
Resistar画面（ユーザー登録画面）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/75c067b2-3d78-de83-3adb-e8c93e895de0.png)



# マイページを作成する
### mypage.blade.php
views\okashisの下に作成。

### routesを修正
```php:routes\web.php
(省略)
Route::get('/mypage', [App\Http\Controllers\OkashiController::class, 'mypage'])->name('mypage');
```

### Controllerを修正
```php:Http\Controllers\OkashiController.php
(省略)
public function mypage() {
   $okashis = Okashi::all();
   return view('okashis.mypage', ['okashis' => $okashis]);
}
```

エラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/499d9d3a-6885-0ed3-9519-b1c9a280b264.png)

mypage.blade.phpのviewで`@endforeach`が抜けてた。凡ミス。修正。
mypage表示成功。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/f4d5a7a1-bef0-d059-5cd2-28ee67199ebb.png)

### ヘッダーにマイページボタンをつける。
```php:views\layouts\app.blade.php
@guest
  (省略)
@else
  #この３行を追加。
  <li class="nav-item">
    <a class="nav-link" href="{{ route('mypage') }}">マイページ</a>
  </li>
　(省略)
@endguest
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/a3e2a9fe-dbdb-93d0-0a29-faed0579398e.png)


# 登録画面を作る create,store
ちなみに、
create：マイページから遷移して、新規登録画面を表示のみ
store：新規登録処理
edit：マイページ一覧から遷移して、修正画面を表示のみ
update：更新処理
destroy：削除処理（削除ボタンはマイページ一覧に表示）

### routes修正
`Route::resource('okashis', OkashiController::class);`を追加。

### view作成
create.blade.phpを作成。

### マイページ内にリンクを貼る
`<a href="{{ route('okashis.create') }}">組み合わせ登録</a>`を追加。

### 登録処理を作る store
```php:APP\Http\Controllers\OkashiController.php
(省略)
public function store(Request $request) {
      $okashi = new Okashi;
      $okashi->name1 = $request->name1;
      $okashi->name2 = $request->name2;
      $okashi->user_id =Auth::user()->id;
      $okashi->save();
      return redirect()->route('okashis.mypage');
    }
```

登録ボタンを押すとうまくいかず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/976585a3-73f6-0424-5e66-0100c60241c7.png)

クロスサイトリクエストフォージェリ対策が必要だった。
>クロスサイトリクエストフォージェリ（CSRF）とは、Webアプリケーションに存在する脆弱性、もしくはその脆弱性を利用した攻撃方法のことです。掲示板や問い合わせフォームなどを処理するWebアプリケーションが、本来拒否すべき他サイトからのリクエストを受信し処理してしまいます。

@csrfをviewのform内に入れる。

```php:resources\views\okashis\create.blade.php
(省略)
  　</div>
  @csrf
  </form>
```
次のエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/6f156649-9ee9-6b44-a743-9053cbfd357e.png)

ログインユーザー情報をControllerで使うには、
`use Illuminate\Support\Facades\Auth;`が必要だった。

次のエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/88a02573-1289-7711-81c6-529882f8533d.png)

他の項目がNULLなのが問題っぽい、ので仮で入れる。

次のエラー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/01a55b42-6966-e7ea-4faa-9e9e6bf02d44.png)

これが必要だった。

```php:APP\Http\Controllers\OkashiController.php
public function store(Request $request) {
      (省略)
      # return redirect()->route('okashis.mypage');
      $okashis = Okashi::all();
      return view('okashis.mypage', ['okashis' => $okashis]);
    }
```

できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/cd5fccb4-cabb-8cdc-a9ee-04bd2a9debb5.png)

# edit,update
edit：マイページ一覧から遷移して、修正画面を表示のみ
update：更新処理
### edit
マイページにedit画面へのリンクを追加。

```php:resources\views\okashis\mypage.blade.php
<a href="{{ route('okashis.edit', $okashi->id) }}">変更</a>
```

create.blade.phpをコピーして作成し、form部分を少し変更。

```php:resources\views\okashis\edit.blade.php
<form action="/okashis/{{ $okashi->id }}" method="POST" class="form-horizontal">
  @method('PUT')
```

対象のデータが表示されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/ddca1da9-092c-f955-6956-b3d7c8d90c50.png)

editビューのinputタグのvalueを修正する。

```php:resources\views\okashis\edit.blade.php
（省略）
  <input type="text" name="name1" id="name1" class="form-control" value="{{ old('name1', $okashi->name1) }}">
（省略）
<input type="text" name="name2" id="name2" class="form-control" value="{{ old('name2', $okashi->name2) }}">
```

表示された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/d5b931fb-3b64-5c92-4d34-3cf6897cf57d.png)

### update
controllerにstoreとほぼ同じように記述する。

```php:APP\Http\Controllers\OkashiController.php
    public function update(Request $request, $id) {
      $okashi = Okashi::find($id);
      $okashi->name1 = $request->name1;
      $okashi->name2 = $request->name2;
      $okashi->save();
      $okashis = Okashi::all();
      return view('okashis.mypage', ['okashis' => $okashis]);
    }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/cc20aed5-cc07-945e-ee6f-667ed61e06af.png)

できた。

# destroy
controllerに記述。

```php:APP\Http\Controllers\OkashiController.php
    public function destroy($id) {
      $okashi = Okashi::find($id);
      $okashi->delete();
      $okashis = Okashi::all();
      return view('okashis.mypage', ['okashis' => $okashis]);
    }
```
mypageビューにformを仕込む。

```php:resources\views\okashis\mypage.blade.php
（省略）
        <form action="{{ route('okashis.destroy', $okashi->id) }}" method="POST">
          @method('DELETE')
          @csrf
          <button type="submit">削除</button>
        </form>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/eff36492-5c57-6964-69ae-b417797f2aa4.png)

できた！

# 他の項目も表示する
taset,price,surprice：☆×5で表示する
comment：そのまま

星評価をfunctionにしたのと、ビューに仕込んだ。

```php
# Okashi.php
    public function starEva($star) {
        for ($i = 0; $i < 5; $i++) {
            if ($star > $i) :
                echo '<i class="fas fa-star">★</i>';
            else :
                echo '<i class="far fa-star">☆</i>';
            endif;
        }
    }

# mypage.blade.php
       味：{{ $okashi->starEva($okashi->taste) }}
        値段：{{ $okashi->starEva($okashi->price) }}
        驚き：{{ $okashi->starEva($okashi->surprice) }}
        {{ $okashi->comment }}

# index.blade.php
　　　　上と同じ
```
いい感じに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/b3c8307b-7751-b387-0c9d-a5a3c75ba916.png)

合わせて、create,storeとedit,updateも上記項目を表示、動作できるようにした。

おまけで、投稿を降順に。index,mypageページ共に。

```php
# web.php
 # なぜかindexはroute側で効いていた。のでそちらを修正。
Route::get('/', function () {
    # $okashis = Okashi::all();
    $okashis = Okashi::orderBy('id', 'desc')->get();
    return view('okashis.index', ['okashis' => $okashis]);
});

# OkashiController
 # orderByを追加
    public function mypage() {
       # $okashis = Okashi::all()->where('user_id', Auth::id());
       $okashis = Okashi::orderBy('id', 'desc')->get()->where('user_id', Auth::id());
       return view('okashis.mypage', ['okashis' => $okashis]);
    }
```

# マイページを自分の投稿のみにする
controllerのmypageを修正。

```php:APP\Http\Controllers\OkashiController.php
    public function mypage() {
       # $okashis = Okashi::all();
       $okashis = Okashi::all()->where('user_id', Auth::id()); # 自分の投稿のみに
       return view('okashis.mypage', ['okashis' => $okashis]);
    }
```
# TOPページに投稿者名も表示する
リレーションを設定する。
modelを修正。
userは単数形、okashisは複数形にするのがポイント。

```php
# Okashi.php
    public function user() {
        return $this->belongsTo('App\Models\User');
    }
# User.php
    public function okashis() {
        return $this->hasMany('App\Models\Okashi');
    }

```

mypageビューを修正

できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/cb614c7a-1016-7c53-aeeb-ff044e34735a.png)

# img1,2を画像にする
### まずはedit,updateに実装
edit修正。
`enctype="multipart/form-data"`をformタグに追加。

update修正。

```php:APP\Http\Controllers\OkashiController.php
public function update(Request $request, $id) {

      if ($file = $request->img1) {
         $fileName1 = time() . $file->getClientOriginalName();
         $target_path = public_path('uploads/');
         $file->move($target_path, $fileName1);
      }else {
         $fileName1 = "";
      }
      if ($file = $request->img2) {
         $fileName2 = time() . $file->getClientOriginalName();
         $target_path = public_path('uploads/');
         $file->move($target_path, $fileName2);
      }else {
         $fileName2 = "";
      }

      $okashi = Okashi::find($id);
      $okashi->img1 = $fileName1;
      $okashi->img2 = $fileName2;
（省略）
}
```

変更画面に画像登録ボタンが表示された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/0459c56f-7d9e-6c77-ebf3-6efaf4412b5d.png)
登録と当時に、public\uploadsフォルダが自動で作成された。
シンボリックリンクをこのフォルダに貼る必要があるらしい。でないと、アクセスできず表示できない。

```
$ php artisan storage:link

The [/Users/machidaryo/phpstudy202012/CombiOkashi/public/storage] link has been connected to [/Users/machidaryo/phpstudy202012/CombiOkashi/storage/app/public].
The links have been created.
```

表示できるようにmypageを修正。

```php
# mypage.blade.php
<img src="../../uploads/{{ $okashi->img1 }}" width="100px" height="100px">
<img src="../../uploads/{{ $okashi->img2 }}" width="100px" height="100px">
```
見栄えは悪いが一応表示できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/b0086f12-4f05-36fa-460e-e65f6f823fef.png)

### create,storeも同じく
indexページも同じように表示修正で、できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1007978/fbbcf629-d75c-03aa-dfdd-d9c39e5d2118.png)

# おわり
次は、フロント整えていく。
いいね機能もつけたい。Ajaxか？

参考
https://qiita.com/apricotcomic/items/07f172a957c1f342fd91
https://qiita.com/ryo-program/items/35bbe8fc3c5da1993366