［Laravel］CRUD基礎☆レストランメニュー作成アプリのチュートリアル

（※ この記事は、Laravel8が出るより結構前に書いて、他のブログに載せていました。それを転載したものなので、Laravel7で解説しています。ご了承くださいませ。。(m´・ω・｀)m ｺﾞﾒﾝ…）

環境：XAMPP

前回は、Laravelで作った初めてのアプリとして、簡単なタスク管理アプリのチュートリアル記事を投稿しました。
今回は、もうちょっと色々機能をつけて、レストランのメニュー作成アプリを作ってみようと思います！完成品は以下画像のような感じです。
管理画面で情報を入力して画像をアップロードすると、メニューページに反映されるというものです。今回のアプリで基本的なCRUD機能の作成はマスターできるのかな～と思います。

お客さん用画面はこちら。『おすすめメニュー』とか、『ランチメニュー』とかのカテゴリー別にメニューが表示されます。（カテゴリーも自由に設定できます。）

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/69d20401-3744-22ef-226e-b7111269c9a3.png">

サイト管理者は管理画面のログインページからログインします。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/248807cc-d0f8-ae07-8356-de263809af49.png">

ログインするとダッシュボードに飛びます。メニューを追加する場合は、右上ボタンから追加できます。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/30d3cfb6-c958-9302-028d-8a9f11faf672.png">

メニュー追加フォームはこちら。カテゴリーは、別ボタンを用意して別ページから追加できる仕様です。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/299ac3ca-d391-5d8b-9970-c02df5a21f3f.png">

ちなみに私、Webデザインは全然できませんので、フロント側はBootstrapで作ったデザイン性のないシンプル画面です。。。悪しからず。(;'∀') 汗

全体のソースコードはGitHubにアップしております。
必要な方は、以下のリンクからご確認ください。
https://github.com/Tomochan-taco/restaurant_menu

それでは早速スタート！

#1 : プロジェクトの作成

手順１： XAMPPのインストール後、C:\xampp\htdocs に移動して、composerでプロジェクトを作成します。プロジェクト名は restaurant_menu にします。（※ 7系で解説しているので、バージョン指定してください。）

```
composer create-project --prefer-dist laravel/laravel restaurant_menu "7.*"
```

手順２： プロジェクトを作成したら、cd コマンドでプロジェクト内『C:\xampp\htdocs\restaurant_menu』に移動します。因みに今回のLaravelのバージョンを確認したら下記のようになりました。

```
php artisan --version  //Laravelバージョン確認用コマンド
Laravel Framework 7.28.3
```

#2 : BootstrapとFont Awesomeのインストール

今回も前回同様、BootstrapとFont Awesomeでフロント側を作成しています。ですので、BootstrapとFont Awesomeのインストールを先にやっちゃいます。

手順１： Laravelで用意されているBootstrapのscaffoldingは、laravel/uiパッケージに含まれています。その為、まずはcomposerでlaravel/uiパッケージをインストールします。

```
composer require laravel/ui:^2.4
```

手順２： 今回は認証機能も使うので、--authオプションをつけてBootstrapのscaffoldingをインストールします。

```
php artisan ui bootstrap --auth
```

C:\xampp\htdocs\restaurant_menu\package.json（以後、package.json と略して表記します。） の "devDependencies"箇所に、以下のようにBootstrapが追加されます。

```restaurant_menu\package.json
    "devDependencies": {
       "axios": "^0.19",
       "bootstrap": "^4.0.0", // Bootstrapが追加されています。
       "cross-env": "^7.0",
       "jquery": "^3.2",
       "laravel-mix": "^5.0.1",
       "lodash": "^4.17.19",
       "popper.js": "^1.12",
       "resolve-url-loader": "^3.1.0",
       "sass": "^1.15.2",
       "sass-loader": "^8.0.0"
   }
```

手順３： npmでインストールします。

```
npm install && npm run dev
```

これで、C:\xampp\htdocs\restaurant_menu\public\css\app.css にコンパイルされてBootstrapが使えるようになります！

手順４： 次はFont Awesomeをインストールします。まずはnpmでfree versionをインストールします。

```
npm install --save @fortawesome/fontawesome-free
```

package.json の "dependencies" の箇所に、以下のようにFont Awesomeが追加されます。

```restaurant_menu\package.json
    "dependencies": {
       "@fortawesome/fontawesome-free": "^5.14.0"
   }
```

手順５： C:\xampp\htdocs\restaurant_menu\resources\sass\app.scss に下記を追記してインポートします。

```restaurant_menu\resources\sass\app.scss
// Font Awesome
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';
```

手順６： npmで実行します。

```
npm run dev
```

これでBootstrapとFont Awesomeが使えるようになります！

手順７： ブラウザ確認します。artisanコマンドでサーバを起動後、http://127.0.0.1:8000/ にアクセスしてみてください。
すると、以下画像のように表示されるはずです。LOGINとREGISTERが右上に表示されます！

```
php artisan serve
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/83529f8b-dcf1-ab57-f44f-949f927bddcc.png)


#3 : ロケールの設定

C:\xampp\htdocs\restaurant_menu\config\app.php で、
'timezone' と 'locale' を以下のように変更します。

```restaurant_menu\config\app.php
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
```

#4 : データベースの作成と、.envファイルの設定

手順１： XAMPPでデータベースを作成します。データベース名は、restaurant_menu にします。（XAMPPでのデータベースの作り方がわからない方は、ご自身で調べてみてください。）

手順２： データベースを作ったら、C:\xampp\htdocs\restaurant_menu\\.env
で、 APP_NAME を Restaurant Menu に、DB_DATABASE を restaurant_menu に変更します。（* 空白を含む値を環境変数に定義する場合は、ダブル引用符で囲む必要があります。）
DB_USERNAME と DB_PASSWORD はそのままにします。XAMPP側でデータベースユーザーを設定した人は、こちらも変更してください。

```restaurant_menu\.env
APP_NAME="Restaurant Menu"

｜
｜途中省略

DB_DATABASE=restaurant_menu
DB_USERNAME=root
DB_PASSWORD=
```

#5 : モデルとマイグレーションファイル (テーブル) の作成

データベースを作成したら、お次はテーブルを作成していきます。
データベースに入力する必要があるデータは、ダッシュボードの以下黄色枠の部分です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/568cd49c-c60f-68e0-49d7-7e2973e007c2.png)

但し、カテゴリーは、例えば『グランドメニュー』の場合に、デミグラスハンバーグやさんま定食など、一つのカテゴリーに対して複数のメニューがあるので、別テーブルにしていきます。

手順１： artisanコマンドで、『Category』と『Product』の二つのモデルを作成します。-mオプションをつけて同時にマイグレーションファイルも作成します。

```
php artisan make:model Category -m
```

```
php artisan make:model Product -m
```

手順２：『Category』モデルのマイグレーションファイル（C:\xampp\htdocs\restaurant_menu\database\migrations\2020_09_19_235630_create_categories_table.php）（2020_09_19 の部分は、作成した日付ですので、作成日によって変わります。）へ移動します。カテゴリーテーブルに追加するカラムは、カテゴリー名だけですので、18行目辺りに1行だけ追記します。

```restaurant_menu\database\migrations\2020_09_19_235630_create_categories_table.php
    public function up()
   {
       Schema::create('categories', function (Blueprint $table) {
           $table->id();
           $table->string('name');  // 追記
           $table->timestamps();
       });
   }
```

手順３：『Category』モデルの複数代入設定をします。複数代入設定は、意図しないデータを書き換えさせない為に、入力できるデータベーステーブルのカラムを指定するものです。今回は、ホワイトリスト方式である『$fillable方式』を使って、入力できるカラムを指定します。
Categoryモデルファイル（C:\xampp\htdocs\restaurant_menu\app\Category.php *←以後、Category.php と略して表記します。）へ移動します。今回はnameカラム一個だけです。

```restaurant_menu\app\Category.php
class Category extends Model
{
   protected $fillable=['name'];
}
```

手順４： Productモデルのマイグレーションファイル（C:\xampp\htdocs\restaurant_menu\database\migrations\2020_09_19_235644_create_products_table.php）へ移動します。
18行目辺りから、以下のように追記します。category_id が、Categoryテーブルとの外部キーです。

```restaurant_menu\database\migrations\2020_09_19_235644_create_products_table.php
    public function up()
   {
       Schema::create('products', function (Blueprint $table) {
           $table->id();
           $table->string('name');  // ここから追記
           $table->text('description');
           $table->integer('price');
           $table->string('image');
           $table->integer('category_id');  // ここまで追記
           $table->timestamps();
       });
   }
```

手順５： Productモデルの複数代入設定をします。モデルファイル
（C:\xampp\htdocs\restaurant_menu\app\Product.php　*←以後、Product.phpと略して表記します。） へ移動して、下記の通りカラムを指定します。

```restaurant_menu\app\Product.php
class Product extends Model
{
   protected $fillable=['name', 'description', 'price', 'image', 'category_id'];
}
```

手順６：artisanコマンドでマイグレーションします。

```
php artisan migrate
```

データベースに戻り、categories テーブルと、products テーブルが作成されていることをご確認ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/6fdc5620-bee4-26fe-5fe0-a5fb07f65d78.png)

#6 : コントローラーの作成

普通だったらコントローラーより先にルーティングを設定すると思うのですが、ちょっとルーティングの部分でご説明申し上げたい箇所がありまして、それを説明する為に、コントローラーを先に作成します。
artisanコマンドで CategoryController と ProductController を作成します。
-r オプションをつけると、基本的なCRUDルーティングのアクションが自動で入った状態でコントローラーが作成されます！

```
php artisan make:controller CategoryController -r
```

```
php artisan make:controller ProductController -r
```

作成されたコントローラーファイル（C:\xampp\htdocs\restaurant_menu\app\Http\Controllers\CategoryController.php *←以後、CategoryController.php と略して表記します。また、ProductController の方も同様に略して表記します。）の中身を見てみると、-r オプションをつけたので、以下のようにindex() やらcreate() やら、７つのコントローラーアクションが自動で入力されています！​

```restaurant_menu\app\Http\Controllers\CategoryController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class CategoryController extends Controller
{
   /**
    * Display a listing of the resource.
    *
    * @return \Illuminate\Http\Response
    */
   public function index()
   {
       //
   }

   /**
    * Show the form for creating a new resource.
    *
    * @return \Illuminate\Http\Response
    */
   public function create()
   {
       //
   }
   
   以下省略
   ｜
   ｜
```

#7 : ルーティングの設定

今回のルーティングは、リソースルーティングを使います。
これは、先ほど-r オプションをつけて、７つのアクションが自動で入った状態のコントローラーを作りましたが、そのそれぞれのアクションに対して、典型的なCRUDルーティングをたった一行のコードで割り当てることができるものです。
ルーティングファイル（C:\xampp\htdocs\restaurant_menu\routes\web.php 　*←以後、web.phpと略して表記します。）にて、以下のように、下二行を追記します。

```restaurant_menu\routes\web.php
Route::get('/', function () {
   return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

Route::resource('category','CategoryController');  //追記
Route::resource('product','ProductController');  //追記
```

追記後、artisanコマンドでルーティングを確認してみてください。

```
php artisan route:list
```

以下のように表示されます。

```
C:\xampp\htdocs\restaurant_menu>php artisan route:list
+--------+-----------+--------------------------+------------------+------------------------------------------------------------------------+------------+
| Domain | Method    | URI                      | Name             | Action                                                                 | Middleware |
+--------+-----------+--------------------------+------------------+------------------------------------------------------------------------+------------+
|        | GET|HEAD  | /                        |                  | Closure                                                                | web        |
|        | GET|HEAD  | api/user                 |                  | Closure                                                                | api        |
|        |           |                          |                  |                                                                        | auth:api   |
|        | POST      | category                 | category.store   | App\Http\Controllers\CategoryController@store                          | web        |
|        | GET|HEAD  | category                 | category.index   | App\Http\Controllers\CategoryController@index                          | web        |
|        | GET|HEAD  | category/create          | category.create  | App\Http\Controllers\CategoryController@create                         | web        |
|        | DELETE    | category/{category}      | category.destroy | App\Http\Controllers\CategoryController@destroy                        | web        |
|        | PUT|PATCH | category/{category}      | category.update  | App\Http\Controllers\CategoryController@update                         | web        |
|        | GET|HEAD  | category/{category}      | category.show    | App\Http\Controllers\CategoryController@show                           | web        |
|        | GET|HEAD  | category/{category}/edit | category.edit    | App\Http\Controllers\CategoryController@edit                           | web        |
|        | GET|HEAD  | home                     | home             | App\Http\Controllers\HomeController@index                              | web        |

　　　　　　　　　以下省略
　　　　　　　　　｜
　　　　　　　　　｜
```

createメソッドやら、updateメソッドやらに自動でルーティングが設定されています！（これを説明する為に、コントローラーを先に作成したのです！）これで、
『 Route::get('/category/create', 'CategoryController@create'); 』
とか、
『 Route::put('/category/{category}', 'CategoryController@update'); 』
とかをいちいち書かずに済みます！便利！

#８：作成手順の説明

さて、土台となるものを一通り作成し終えたところで、これからの開発手順をざっくり説明します。そうじゃないと色々と混乱してくると思うので。。(;^_^A

**その１： カテゴリーの追加フォーム及び一覧ページの作成**
メニュー追加フォームで、予め作られたカテゴリーをプルダウンから選ぶ項目を作ります。ですので、何が何でもカテゴリーを一番先に作らなくてはいけません。

**その２： メニュー追加フォーム及びダッシュボードの作成**
カテゴリー関連のページを作り終えたら、メニュー追加フォームと、その追加されたメニューを一覧表示するダッシュボードを作ります。

**その３： お客さん用画面の作成**
ダッシュボードまで作り終えたら、最後にお客さん用画面に情報を反映させて完成です。

#９：Viewページの作成（カテゴリー）

それでは、カテゴリーの追加フォーム及び一覧ページを作っていきます。一覧では、各カテゴリーの編集と削除もできるようにします。

手順１： まずは、追加フォームのViewを作ります。C:\xampp\htdocs\restaurant_menu\resources\views にcategoryというフォルダを作って、create.blade.php という名前でファイルを作ります。コードは以下の通りです。

```C:\xampp\htdocs\restaurant_menu\resources\views\category\create.blade.php

@extends('layouts.app')

@section('content')
<div class="container mt-3" style="max-width: 720px;">
  <div class="text-right">
  <a href="{{ url('/product/create') }}">＜ 戻る</a>
  </div>
  
  <form>
    <div class="form-group">
      <label for="categoryAdd" class="font-weight-bold">新規カテゴリー追加</label>
      <input type="text" class="form-control" id="categoryAdd" name="name" />
    </div>
    <button type="submit" class="btn btn-primary">追加</button>
  </form>
  
  <div class="my-4">
    <a href="{{ url('/category/') }}">＞ 一覧・編集ページへ</a>
  </div>
</div>
@endsection
```

『@extends('layouts.app') 』の箇所で使われているlayouts.appのページは、特に編集せずにデフォルトのものをそのまま使っています。
@extends() や @section() の使い方等、laravelのbladeに関する基本的な説明は省きますので、ご存知でない方はご自身で調べてみてください。

手順２： ブラウザで表示確認する為に、コントローラーを設定します。
CategoryController.phpで、以下のようにcreate()メソッドを設定します。

```restaurant_menu\app\Http\Controllers\CategoryController.php
    public function create()
   {
       return view('category.create');
   }
```

ブラウザで、『 http://127.0.0.1:8000/category/create 』へアクセスします。すると以下のように表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/1f5301e0-0907-2f7c-144b-591bf7d60254.png)

手順３： お次は、一覧ページのViewを作ります。
categoryフォルダに index.blade.php という名前でファイルを作ります。
コードは以下の通りです。（＊データベースからデータを引っ張ってきて表示させる箇所は、現段階ではサンプル値の手入力です。）

```restaurant_menu\resources\views\category\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container" style="max-width: 720px">

<div class="text-right">
  <a href="{{ url('/product/create') }}">＜ 戻る</a>
</div>

 <table class="table table-bordered mt-2">
   <thead class="table-dark">
     <tr>
       <th scope="col">
         #
       </th>
       <th scope="col">
         作成日
       </th>
       <th scope="col">
         カテゴリー
       </th>
       <th scope="col">
         編集
       </th>
       <th scope="col">
         削除
       </th>
     </tr>
   </thead>
   <tbody>
     <tr>
       <th scope="row">
         1
       </th>
       <td>
         2020/2/11
       </td>
       <td>
         グランドメニュー
       </td>
       <td>
         <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
       </td>
       <td>
         <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button>
       </td>
     </tr>
   </tbody>
 </table>

 <div class="my-4">
   <a href="{{ url('/category/create') }}">＞ カテゴリー新規追加ページへ</a>
 </div>

</div>
@endsection
```

手順４： ブラウザで表示確認する為に、コントローラーを設定します。
CategoryController.phpで、以下のようにindex()メソッドを設定します。

```restaurant_menu\app\Http\Controllers\CategoryController.php
    public function index()
   {
       return view('category.index');
   }
```

ブラウザで、『 http://127.0.0.1:8000/category/ 』へアクセスします。すると以下のように表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/494a3bb7-48aa-1b6c-d209-e33c4083547e.png)

#10：  データベースへの挿入（カテゴリー）

カテゴリー情報をデータベースに挿入していきます。

手順１： 前回作ったcategoryのviewファイル（create.blade.php）を編集します。ソースコードは以下の通りです。

```restaurant_menu\resources\views\category\create.blade.php
    
    <form action="{{ route('category.store') }}" method="POST">  //追記
     @csrf  //追記
     <div class="form-group">
       <label for="categoryAdd" class="font-weight-bold">新規カテゴリー追加</label>
       <input type="text" class="form-control" id="categoryAdd" name="name" />
     </div>
     <button type="submit" class="btn btn-primary">追加</button>
   </form>
```

9行目辺りの、\<form\>タグにaction属性とmethod属性を追記します。POSTデータを送信してデータベースに挿入するので、CategoryControllerのstoreメソッドをヒットするようにします。laravelに限らずなのかもしれませんが、フォーム入力されたデータを保存するにはstore()メソッドを使います。
リソースルーティングを設定しているので、category.storeという名前のルーティングが既についています。ですので、action属性には {{ route('category.store') }} と書くことができます。bladeのroute関数についてご存知でない方は、ご自身で調べてみてください。
また、Laravelでお約束ですが、formタグの下には『@csrf 』をつけることを忘れないようにします。CSRF対策の為です。これを書かないと、419｜Page Expired エラー等が起きます。

手順２： 正常にデータが送信できるかを確認します。ここではひとまずdd()関数を利用してチェックしてみます。
CategoryController.phpで、store()メソッドを以下のように設定します。
※ フォームから飛んでくるデータはRequest型で渡ってきます。その為、コールバック関数の引数には、Implicit Bindingを利用して、(Request $request) とします。この辺りがよくわからない方は、『Laravel フォーム Request Implicit Binding』等で検索してみてください。

```restaurant_menu\app\Http\Controllers\CategoryController.php

    public function store(Request $request)
   {
       return dd($request->all());
   }
```

手順３：『 http://127.0.0.1:8000/category/create 』にアクセスします。何でもいいのですが、とりあえず『グランドメニュー』と入力して、追加ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/42e119e2-45a7-56bf-7233-5ee4151ebd2d.png)

すると、以下のように表示されて、CSRFのトークンと、カテゴリー情報（inputタグの値）が送られてきているのがわかります！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/e52c5a91-ee7f-0f62-7e17-0ed82bfcc364.png)

手順４： データベースに挿入していきます。dd()メソッドはコメントアウトして、Eloquentモデルのcreate()メソッドを使って挿入します。
その際、Categoryモデルを使うので、コントローラーに『 use App\Category; 』を追記しておくことを忘れないようにします。
コードは以下の通りです。

```restaurant_menu\app\Http\Controllers\CategoryController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Category;  //追記

以下省略
｜
｜

    public function store(Request $request)
  {
      // return dd($request->all());
      
      Category::create([
          'name'=>request('name')
      ]);
  }
```

手順５： データがきちんと挿入されるか確認します。先程と同じようにブラウザで『 グランドメニュー』と入力して追加ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/2e75580a-3cea-ee0f-f6ae-fe5661026bf6.png)

categoriesテーブルを確認すると、以下の通りグランドメニューが追加されています！データベースへの挿入ができました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/9390a2bd-5711-d3d2-e33e-82a5b1156e76.png)

#11：フラッシュメッセージの表示とリダイレクト（カテゴリー）

カテゴリーを追加した際に、直前のページ（要は、カテゴリーを追加した同じページのこと。）にリダイレクトして、フラッシュメッセージを出すようにします。

手順１： まずは、View側でフラッシュメッセージを出すコードを追記します。categoryのviewファイル（create.blade.php）へ移動して、9行目辺りから追記していきます。コードは以下の通りです。

```restaurant_menu\resources\views\category\create.blade.php

@extends('layouts.app')

@section('content')
<div class="container mt-3" style="max-width: 720px;">
  <div class="text-right">
  <a href="{{ url('/product/create') }}">< 戻る</a>
  </div>

  @if (session('message'))  //ここから追記
   <div class="alert alert-success" role="alert">{{ session('message') }}</div>
  @endif  //ここまで追記

  <form action="{{ route('category.store') }}" method="POST">
    @csrf
    
    以下省略
    　｜
    　｜
```

グローバルなsession()ヘルパ関数を使います。引数を一つにすることで、キーに対する値を取得することができます。if文にすることで、'message'というキー名でsessionデータがあれば表示しないさい、と書いています。

手順２： 次に、コントローラーに設定していきます。
CategoryControllerのstore()メソッドに、『 return redirect() ~~ 』部分を追記します。

```restaurant_menu\app\Http\Controllers\CategoryController.php

       public function store(Request $request)
   {
       // return dd($request->all());
       
       Category::create([
           'name'=>request('name')
       ]);
       
       return redirect()->back()->with('message', 'カテゴリーが追加されました。');  //追記
   }
```

直前のページにリダイレクトするには、back()メソッドを使います。フラッシュメッセージを出すには、セッションデータを返す必要があるので、with()メソッドを使います。with()メソッドは、リダイレクトする場合や、viewを返す時などにデータを渡せるメソッドです。view側に変数を渡す場合等によく使われます。今回は、『 with('キー', 'バリュー'); 』のように2つ引数を渡すことで、配列としてセッションデータをview側に渡します。

手順３： ブラウザで確認してみます。
再度『 http://127.0.0.1:8000/category/create 』にアクセスして、カテゴリーを入力後に追加ボタンを押すと、リダイレクトされて、以下のようにフラッシュメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/d1e92f7f-7fa7-6311-7825-206363008996.png)

#12：一覧ページへ反映させる（カテゴリー）
カテゴリーを無事データベースに追加できたので、それを一覧ページに表示させます。

手順１： まずは、コントローラーに一覧情報を表示させるためのデータ受け渡しの設定を行います。
CategoryController.phpで、元々書いてあった『return view('category.index');』はコメントアウトして、index() メソッドに下二行を追記します。

```restaurant_menu\app\Http\Controllers\CategoryController.php
    public function index()
   {
       // return view('category.index');
       
       $categories = Category::latest()->get();  //追記
       return view('category.index', ['categories' => $categories]);  //追記
   }
```

latest()は、新しいもの順でデータを取ってくる際に使えるように、Laravelが用意してくれている便利なメソッドです。クエリビルダで言う所の、orderBy('created_at', 'desc')と同じ意味になります。その為、『Category::latest()->get();』は、『Category::orderBy('created_at', 'desc')->get();』と同じ結果になります。

手順２： 先程作った一覧ページのView（index.blade.php）へ移動して、30行目辺りの<tbody>以下に、//追記 もしくは //変更 と書かれている部分を追記・変更してください。

```restaurant_menu\resources\views\category\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container" style="max-width: 720px">

<div class="text-right">
 <a href="{{ url('/product/create') }}">< 戻る</a>
</div>

<table class="table table-bordered mt-2">
  <thead class="table-dark">
    <tr>
      <th scope="col">
        #
      </th>
      <th scope="col">
        作成日
      </th>
      <th scope="col">
        カテゴリー
      </th>
      <th scope="col">
        編集
      </th>
      <th scope="col">
        削除
      </th>
    </tr>
  </thead>
  <tbody>
  @if (count($categories) > 0)  //追記
   @foreach ($categories as $key=>$category)  //追記
     <tr>
       <th scope="row">
       {{ $key+1 }}  //変更
       </th>
       <td>
       {{ $category->created_at->format('Y/m/d') }}  //変更
       </td>
       <td>
       {{ $category->name }}  //変更
       </td>
       <td>
         <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
       </td>
       <td>
         <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button>
       </td>
     </tr>
   @endforeach  //追記
   
   @else  //追記
     <tr>  //追記
     <td colspan="5">追加されたカテゴリーはありません。</td>  //追記
     </tr>  //追記

  @endif  //追記
  </tbody>
</table>

<div class="my-4">
  <a href="{{ url('/category/create') }}">> カテゴリー新規追加ページへ</a>
</div>

</div>
@endsection
```

31行目辺りの @if (count($categories) > 0)  の部分で、カテゴリーが1つ以上あればテーブルを表示して、そうでなければ、51行目辺りの、@else 部分で『追加されたカテゴリーはありません。』という文言を表示するようにします。

手順３： @else 部分が正常に表示されるかを確認する為に、データを全部消去します。artisanコマンドで以下の通りmigrate:freshを行います。

```
php artisan migrate:fresh
```

手順４： ブラウザで確認します。『 http://127.0.0.1:8000/category 』にアクセスします。すると、以下の通り表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/d53548e2-f425-d4b1-c476-cb72f9000133.png)

手順５：『> カテゴリー新規追加ページへ』 のリンクをクリックして、追加ページへ移動します。そこで、『ランチメニュー』『グランドメニュー』『おすすめメニュー』を追加してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/b7daf89a-d0f5-9d81-9efc-59ad61a2d6ce.png)

手順６：『> 一覧・編集ページへ のリンク』をクリックすると、以下のようにデータが表示されます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/1030f7c8-3529-6c71-d938-0a0f87820c13.png)

＊おまけで解説です。↓↓
index.blade.phpの、『 @foreach (\$categories as \$key=>\$category) 』の部分ですが、これは、通し番号の部分（ {{ \$key+1 }} のとこ。）を表示させる為に、このように書いています。Laravelではモデルを使った場合に、データベースから返ってくる値は常にCollectionインスタンスになるので、$key変数に、連想配列の”キー”の部分を入れ込むことができます。
＊ LaravelのCollectionが分からない方は、結構豊富に記事が出ているので調べてみてください！また、PHPの連想配列を取り出す方法に関しては、この記事がわかりやすかったです。

[【やさしいPHP】foreach文の基礎を知ってかんたんな応用を試してみる](https://www.sejuku.net/blog/47603)

実際に確認してみます。CategoryController.phpのindex()メソッドに、以下のようにdd() ヘルパ関数を追記してみてください。

```restaurant_menu\app\Http\Controllers\CategoryController.php

    public function index()
   {
       // return view('category.index');
       $categories = Category::latest()->get();
       dd($categories);  //追記
       return view('category.index', ['categories' => $categories]);
   }
```

『 http://127.0.0.1:8000/category 』にアクセスすると、以下のように表示されます。Collectionインスタンスが返されて、”キー”の部分には、配列で言う所の配列番号が入っています。これを表示させることで、一覧表の通し番号を表示させています。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/e7110235-9d3d-2e9a-5b69-531c4a621816.png">


#13：編集機能をつける（カテゴリー）

次は、カテゴリー一覧ページの編集ボタンから、カテゴリーを編集できるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/0c33f1a9-d13a-fcfd-41d0-56af03a907a4.png)

手順１： 一覧ページ（index.blade.php）へ移動して、編集ボタンの箇所を\<a\>タグで囲みます。

```restaurant_menu\resources\views\category\index.blade.php
<a href="{{ route('category.edit', [ 'category' => \$category->id ]) }}">  //追記
  <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
</a>  //追記
```

『 route('category.edit', [ 'category' => $category->id ]) 』の箇所で、該当するカテゴリーのidをつけたURLへ遷移します。ブラウザで実際に編集ボタンを押してみると、URLが『 http://127.0.0.1:8000/category/1/edit 』や『 http://127.0.0.1:8000/category/2/edit 』へ飛びます。
php artisan route:list を今一度確認してみてください。
『 category.edit 』 という名前のついたルーティングは、『 category/{category}/edit  』へ遷移するように設定されています。route関数の第二引数につけたパラメーターは、自動的にURLの正しい場所へ埋め込まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/06493b7d-9b22-60af-3744-2d6a33036147.png)

手順２： お次は、編集ボタンを押した先にeditページを表示させるようにコントローラーに設定していきます。（editページ自体はこの後作ります。）
CategoryController.phpで、edit() メソッドを以下のように編集します。indexページの編集ボタンを押したときに渡ってきたパラメーターが(\$id)の部分に入ります。

```restaurant_menu\app\Http\Controllers\CategoryController.php

    public function edit($id)
   {
       $category = Category::find($id);
       return view('category.edit', ['category' => $category]);
   }
```

手順３： editページを作成します。C:\xampp\htdocs\restaurant_menu\resources\views\category に『 edit.blade.php 』という名前でファイルを作ります。同じフォルダのcreate.blade.phpファイルとほぼ中身は一緒なので、まずはそれを全てコピペします。そのうえで、以下『//追記 』もしくは 『//変更』と書かれている部分を追記・変更します。

```restaurant_menu\resources\views\category\edit.blade.php

@extends('layouts.app')

@section('content')
<div class="container mt-3" style="max-width: 720px;">
  <div class="text-right">
  <a href="{{ url('/product/create') }}">< 戻る</a>
  </div>

  <form action="{{ route('category.update', [ 'category' => $category->id ]) }}" method="POST">  // 変更
    @csrf
    @method('PUT')  //追記
    <div class="form-group">
      <label for="categoryAdd" class="font-weight-bold">カテゴリー編集</label>  // 変更
      <input type="text" class="form-control" id="categoryAdd" name="name" value="{{ $category->name }}" />  // 変更
    </div>
    <button type="submit" class="btn btn-primary">編集</button>  // 変更
  </form>

  <div class="my-4">
    <a href="{{ url('/category/') }}">> 一覧ページへ</a>  // 変更
  </div>
</div>
@endsection
```

何点か説明します。
『 \<form action="{{ route('category.update', [ 'category' => $category->id ]) }}" method="POST"\> 』の箇所は、アップデートしたデータをデータベースに反映させる為に、update() メソッドをヒットするように設定します。また、update() メソッドはPUTリクエストで送信するため、『 @method('PUT') 』という記述を書く必要があります。これは、現段階ではブラウザがGETかPOSTしか理解することができないため、これはPOSTじゃなくて、PUTだよ、ということをブラウザ側に伝える為です。これは、DELETEリクエストの時も同様です。 
また、編集ページのため、編集する前のデータがフォームに残った状態で表示させます。その為、inputタグにvalue属性を追記します。

これで、一覧ページの編集ボタンをクリックしてみてください。以下のように該当するカテゴリーが入力された状態で編集フォームが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/11bb656d-a0c9-85d2-e88e-85eeba6563e0.png)

手順４： 編集されたデータをデータベースに保存していきます。CategoryController.php へ移動して、update()メソッドを、以下のように設定します。

```restaurant_menu\app\Http\Controllers\CategoryController.php
    public function update(Request $request, $id)
   {
       $category = Category::find($id);
       $category->name = request('name');
       $category->save();
       return redirect('/category')->with('message', 'カテゴリーが編集されました。');
   }
```

コードの中身を説明します。
① 『\$category = Category::find(\$id);』で、フォームから渡ってきたデータをidで探します。
② 『\$category->name = request('name');』で、該当するidのデータのnameカラムを、フォームから渡ってきたRequest型の値に変更します。
③ ②のデータを保存します。
④ 一覧ページにリダイレクトして、そこで編集完了のフラッシュメッセージを出します。

手順５： 一覧ページ（index.blade.php）にフラッシュメッセージを表示させるコードを書いていなかったので、追記しておきます。

```restaurant_menu\resources\views\category\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container" style="max-width: 720px">
<div class="text-right">
 <a href="{{ url('/product/create') }}">＜ 戻る</a>
</div>

@if (session('message'))  //ここから追記
 <div class="alert alert-success" role="alert">{{ session('message') }}</div>
@endif  //ここまで追記

<table class="table table-bordered mt-2">
  <thead class="table-dark">
```

手順６： 編集ページで、『おすすめメニュー』を『夏のおすすめメニュー』と変更して、編集ボタンを押してみます。そうすると、一覧ページにリダイレクトして、編集された旨のフラッシュメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/4f202d6c-b8fc-7472-d954-0718c95279b7.png)

#14：削除機能をつける（カテゴリー）

一覧ページでカテゴリーを削除できるようにします。削除する機能は、delete()メソッド一発で実現できるので簡単です！

手順１：  CategoryController.php のdestroy()メソッドを以下のように設定します。

```restaurant_menu\app\Http\Controllers\CategoryController.php
    public function destroy($id)
   {
       $category = Category::find($id);
       $category->delete();
       return redirect('/category')->with('message', 'カテゴリーが削除されました。');
   }
```

コードの説明をします。
① 『 \$category = Category::find(\$id); 』で、パラメーターから渡ってきたidを元にデータを探します。
② 『 \$category->delete(); 』では、①のデータをdelete()メソッド一発でデータベースから削除しています。
③ 一覧ページにリダイレクトして、フラッシュメッセージ用のデータをwith()関数でbladeに送ります。

手順２： 次は、View側の設定をしていきます。削除する際に、モーダルを使って確認画面を出してみようと思います。一覧ページ（index.blade.php）で、元々削除ボタンがあった<td>タグ箇所に、Bootstrapのモーダルのコードをとりえあえずコピペします。コピペするのは、以下サイトの『Live demo』のコードです。

[BootStrapドキュメント](https://getbootstrap.jp/docs/4.5/components/modal/#live-demo)

手順３： コピペしたら、以下『//変更』もしくは 『//追記 』と書かれている部分を変更・追記します。コードは以下の通りです。

```restaurant_menu\resources\views\product\index.blade.php

<td>
 <!-- <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button> -->  //コメントアウト
 <!-- Button trigger modal -->
 <button type="button" class="btn btn-outline-primary" data-toggle="modal" data-target="#exampleModal{{$category->id}}"><i class="far fa-trash-alt"></i> 削除</button>  //変更

 <!-- Modal -->
 <div class="modal fade" id="exampleModal{{$category->id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">  //変更
   <div class="modal-dialog" role="document">
     <form action="{{ route('category.destroy', [ 'category' => $category->id ]) }}" method="POST">  //追加
       @csrf  //追加
       @method('DELETE')  //追加
       <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">カテゴリー削除</h5>  //変更
           <button type="button" class="close" data-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">&times;</span>
           </button>
         </div>
         <div class="modal-body">
           本当に削除しますか？  //変更
         </div>
         <div class="modal-footer">
           <button type="button" class="btn btn-secondary" data-dismiss="modal">キャンセル</button>  //変更
           <button type="submit" class="btn btn-primary">削除</button>  //変更
         </div>
       </div>
     </form>
   </div>
 </div>
</td>
```

53行目辺りに、元々あった削除ボタンのコード『 \<button type="button" class="btn btn-outline-primary"\>\<i class="far fa-trash-alt"\>\</i\> 削除\</button\> 』はコメントアウトします。
次に、\<div class="modal-dialog" role="document"\> の直下、60行目辺りにformタグを追加します。formタグでは、destroy()メソッドをヒットさせるようにします。@csrf と @method('DELETE') をつけるのを忘れないようにしてください。また、55行目あたりの『data-target="#exampleModal{{\$category->id}}"\>』と58行目辺りの『id="exampleModal{{\$category->id}}"』の箇所には『{{\$category->id}}』を追加しています。
続いて、『カテゴリー削除』『本当に削除しますか？』『キャンセル』『削除』の文言を変更します。『削除』文言の\<button\>タグは、type="submit" に変更してください。

手順４： ブラウザで確認してみます。削除ボタンを押すとモーダルで確認画面が出てきて、更に削除ボタンを押すとフラッシュメッセージと共に一覧から削除されます。また、データベースからも削除されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/a415b638-efc6-a19d-333c-d1c80baafb3b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/0acdcf32-dcda-3e60-bcb8-6f558a2ff082.png)

#15：バリデーションをつける（カテゴリー）

フォームにバリデーションを付けていなかったので、追加ページと一覧ページにつけていきます。

手順１： まずは追加ページの方からです。コントローラの設定を先に行います。CategoryController.phpで、store()メソッドに、request()->validate 箇所を追記します。

```restaurant_menu\app\Http\Controllers\CategoryController.php

    public function store(Request $request)
   {
       // return dd($request->all());
       
        request()->validate(
           ['name' => 'required|unique:categories'],
           ['name.required' => 'カテゴリーを入力してください。',
           'name.unique' => 'そのカテゴリーは既に追加されています。']
       );
       
       Category::create([
           'name'=>request('name')
       ]);
       
       return redirect()->back()->with('message', 'カテゴリーが追加されました。');
   }
```

手順２： 追加ページ（create.blade.php）に移動して、以下『//変更』もしくは 『//追記 』と書かれている部分を変更・追記します。

```restaurant_menu\resources\views\product\create.blade.php

  <form action="{{ route('category.store') }}" method="POST">
   @csrf
   <div class="form-group">
     <label for="categoryAdd" class="font-weight-bold">新規カテゴリー追加</label>
     <input type="text" class="form-control @error('name') is-invalid @enderror" id="categoryAdd" name="name" />  //変更
     @error('name')  //追記
       <p class="text-danger">{{ $message }}</p>  //追記
     @enderror  //追記
   </div>
   <button type="submit" class="btn btn-primary">追加</button>
 </form>
```

17行目辺りのinputタグのclass名には、『 @error('name') is-invalid @enderror 』を追記しています。これは、@errorディレクティブを利用をして、エラーメッセージがあったらis-invalidクラスを付けてね、ということを表しています。また、その後の18行目から20行目にかけても@errorディレクティブを使って、$message変数を表示させるようにしています。

手順３： カテゴリー追加ページに行って、何も入力せずに追加ボタンを押すと、以下のようにエラーメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/844264ac-dc62-2a47-9ff7-aa1fe0ae11ef.png)

重複して追加しようとすると、既に登録されている旨のエラーが出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/cf0f15b8-c1b4-8b6b-55fa-6570dc134fd2.png)

手順４： 編集ページも同様にバリデーションをかけていきます。
CategoryController.phpのupdate()メソッドにrequest()->validate()部分を追記します。

```restaurant_menu\app\Http\Controllers\CategoryController.php

    public function update(Request $request, $id)
   {
        request()->validate(
           ['name' => 'required|unique:categories'],
           ['name.required' => 'カテゴリーを入力してください。',
           'name.unique' => 'そのカテゴリーは既に追加されています。']
       );
       
       $category = Category::find($id);
       $category->name = request('name');
       $category->save();
       return redirect('/category')->with('message', 'カテゴリーが編集されました。');
   }
```

手順５： View側でも設定していきます。追加ページと同じように追記していきます。編集ページ（edit.blade.php）にて、inputタグのclass名に、『@error('name') is-invalid @enderror』を追記します。その後の18行目から20行目にかけても@errorディレクティブを使って、$message変数を表示させます。

```restaurant_menu\resources\views\product\edit.blade.php

   <form action="{{ route('category.update', [ 'category' => $category->id ]) }}" method="POST">
    @csrf
    @method('PUT')
    <div class="form-group">
      <label for="categoryAdd" class="font-weight-bold">カテゴリー編集</label>
      <input type="text" class="form-control @error('name') is-invalid @enderror" id="categoryAdd" name="name" value="{{ $category->name }}" />  //変更
      @error('name')  //追加
       <p class="text-danger">{{ $message }}</p>  //追加
      @enderror  //追加
    </div>
    <button type="submit" class="btn btn-primary">編集</button>
  </form>
```

これで、フォームを空にして編集ボタンを押すと、『カテゴリーを入力してください。』というエラーが出て、何も変更せずに編集ボタンを押すと『そのカテゴリーは既に追加されています。』というエラーが出ます。

#16：Viewページの作成（メニュー）

カテゴリー関連の機能は完成したので、お次はメニュー追加フォームとダッシュボードの作成を行います！

手順１：まずはメニュー追加フォームのViewを作ります。
C:\xampp\htdocs\restaurant_menu\resources\views にproductというフォルダを作って、create.blade.php という名前でファイルを作ります。コードは以下の通りです。
フラッシュメッセージと@errorディレクティブを使ったバリデーションの部分は、既にコード内に記載済みです。カテゴリーの時と同様なので、これに関する説明は省きます。

```restaurant_menu\resources\views\product\create.blade.php

@extends('layouts.app')

@section('content')
<div class="container mt-3" style="max-width: 720px;">
 <div class="text-right">
   <a href="{{ url('/product/') }}">＜ 戻る</a>
 </div>
 
 @if ( session('message') )
 <div class="alert alert-success" role="alert">{{ session('message') }}</div>
 @endif
 
 <form action="{{ route('product.store') }}" method="POST" enctype="multipart/form-data">
   @csrf
   <div class="form-group" style="margin-top: 30px; margin-bottom: 30px">
     <label for="name" class="font-weight-bold">商品名</label>
     <input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" />
     @error('name')
     <p class="text-danger">{{ $message }}</p>
     @enderror
   </div>
   <div class="form-group" style="margin-bottom: 30px">
     <label for="textarea" class="font-weight-bold">詳細</label>
     <textarea class="form-control @error('description') is-invalid @enderror" id="textarea" rows="5" name="description"></textarea>
     @error('description')
     <p class="text-danger">{{ $message }}</p>
     @enderror
   </div>
   <div class="form-group" style="margin-bottom: 30px">
     <label for="price" class="font-weight-bold">値段</label>
     <input type="text" class="form-control @error('price') is-invalid @enderror" id="price" name="price" />
     <small class="form-text text-muted">半角数字で入力してください。</small>
     @error('price')
     <p class="text-danger">{{ $message }}</p>
     @enderror
   </div>
   <div class="form-group" style="margin-bottom: 30px">
     <label for="category" class="font-weight-bold">カテゴリー</label>
     <select class="form-control @error('category') is-invalid @enderror" id="category" name="category">
       <option value="" disabled selected style="display: none;">カテゴリーを選択してください。</option>
       @foreach(App\Category::all() as $category)
       <option value="{{ $category->id }}">{{ $category->name }}</option>
       @endforeach
     </select>
     @error('category')
     <p class="text-danger">{{ $message }}</p>
     @enderror
     <div class="text-right mt-2">
       <a type="button" href="{{ url('/category/create/') }}" class="btn btn-outline-secondary py-1" role="button">新規追加</a>
       <a type="button" href="{{ url('/category/') }}" class="btn btn-outline-secondary py-1" role="button">編集</a>
     </div>
   </div>
   <div class="form-group" style="margin-bottom: 30px">
     <label for="image" class="font-weight-bold">画像アップロード</label>
     <input type="file" class="form-control-file @error('image') is-invalid @enderror" id="image" name="image" />
     @error('image')
     <p class="text-danger">{{ $message }}</p>
     @enderror
   </div>
   
   <button type="submit" class="btn btn-primary my-3">送信</button>
   
 </form>
</div>
@endsection
```

40行目辺りの\<option\>タグ『 \<option value="" disabled selected style="display: none;"\>』の箇所について少し説明します。
これは、『カテゴリーを選択してください。』の文章を、下記画像のようにデフォルトで表示させる為に書いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/ca1bbf13-3c2a-9300-9cba-e0618f44c382.png)

属性の説明は下記4点です。
① value値を空にします。（ value=""）
② 選択できないようにします。（disabled）
③ デフォルトで選択表示されているようにします。（selected）
④ プルダウンの中ではなく、フォームの中に表示させるようにします。（style="display: none;）
また、『@foreach(App\\Category::all() as $category)』の部分は、コントローラーから変数が渡って来ている訳ではないので、ここでCategoryモデルにアクセスしています。

手順２： ブラウザで表示確認する為に、コントローラーの設定をします。（*おさらいですが、ルーティングは、リソースルーティングで既に設定しています。）
ProductController.phpで、以下のようにcreate()メソッドを設定します。

```restaurant_menu\app\Http\Controllers\ProductController.php

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

手順３： ブラウザで、『 http://127.0.0.1:8000/product/create 』へアクセスします。すると以下のように表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/31f89908-d29b-c534-7ee8-377dc2789291.png)

手順４： 次に、ダッシュボードのViewを作ります。
先程作ったproductフォルダに、index.blade.phpと言う名前でファイルを作ります。コードは以下の通りです。（＊データベースからデータを引っ張ってきて表示させる箇所は、現段階ではサンプル値の手入力です。）

```restaurant_menu\resources\views\product\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container-fluid my-2">
  <div class="row m-2">
    <div class="col">
      <h3 class="font-weight-bold">ダッシュボード</h3>
    </div>
    <div class="col text-right">
      <a type="button" href="{{ url('/product/create/') }}" class="btn btn-primary text-right" role="button"><i class="fas fa-plus"></i> 新規追加</a>
    </div>
  </div>
  
  <table class="table table-bordered">
    <thead class="table-dark">
      <tr>
        <th scope="col">
          id
        </th>
        <th scope="col">
          画像
        </th>
        <th scope="col">
          商品名
        </th>
        <th scope="col">
          詳細
        </th>
        <th scope="col">
          値段
        </th>
        <th scope="col">
          カテゴリー
        </th>
        <th scope="col">
          編集
        </th>
        <th scope="col">
          削除
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th scope="row">
          1
        </th>
        <td style="max-width: 200px;">
          <img src="#" class="img-fluid" />
        </td>
        <td>
          デミグラスハンバーグ
        </td>
        <td style="max-width: 300px;">
          お肉の旨味をギュッと閉じ込めたジューシーなハンバーグに、濃厚なデミグラスソースをたっぷりとかけてお楽しみください。
        </td>
        <td>
          880
        </td>
        <td>
          グランドメニュー
        </td>
        <td>
          <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
        </td>
        <td>
          <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button>
        </td>
      </tr>
    </tbody>
  </table>
  
</div>
@endsection
```

手順５： ブラウザで表示確認する為に、コントローラーの設定をします。
ProductController.phpで、以下のようにindex()メソッドを設定します。

```restaurant_menu\app\Http\Controllers\ProductController.php

  public function index()
   {
       return view('product.index');
   }
```

手順６： ブラウザで、『 http://127.0.0.1:8000/product/ 』へアクセスします。すると以下画像のように表示されるはずです。画像はまだアップしていないので、リンク切れになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/23f2fcef-83d3-fd4d-7da6-d2b8eb83e592.png)

#17：データベースへの挿入（メニュー）

手順１： フォームからの送信データをデータベースに挿入していきます。ProductController.phpで、以下のようにstore()メソッドを設定します。コードは以下の通りです。バリデーションの部分は、既に含んでいます。

```restaurant_menu\app\Http\Controllers\ProductController.php

    public function store(Request $request)
   {
       request()->validate(
           ['name' => 'required',
            'description' => 'required',
            'price' => 'required|integer',
            'category' => 'required',
            'image' => 'required|mimes:jpeg,png,jpg,gif,svg'],
           ['name.required' => '商品名を入力してください。',
            'description.required' => '詳細を入力してください。',
            'price.required' => '値段を入力してください。',
            'category.required' => 'カテゴリーを入力してください。',
            'image.required' => '画像を選択してください。']
       );
       
       $image = $request->file('image');
       $name = time().'.'.$image->getClientOriginalExtension();
       $destinationPath = public_path('/images');
       $image->move($destinationPath,$name);
     
       Product::create([
           'name'=>request('name'),
           'description'=>request('description'),
           'price'=>request('price'),
           'category_id'=>request('category'),
           'image'=>$name
       ]);
       
       return redirect()->back()->with('message', '商品情報が追加されました。');
   }
```

上記のコードの部分で、画像アップロードに関する部分を説明します。
① まずはフォームからアップされた画像を変数に代入して、（\$image = \$request->file('image');）
② アップロードした日時と画像の拡張子をつけてユニークな画像名にします。（\$name = time().'.'.\$image->getClientOriginalExtension();）
③  C:\xampp\htdocs\restaurant_menu\public にimagesという名前でフォルダを作っておきます。そして、そこに画像を保存するようにします。
（\$destinationPath = public_path('/images');　\$image->move(\$destinationPath,\$name);）

手順２： データの挿入にはProductモデルのcreate()メソッドを使っているので、ProductController.php上部に『use App\Product;』を追記することを忘れないようにします。

```restaurant_menu\app\Http\Controllers\ProductController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Product;  //追記

以下省略
｜
｜
```

手順３： ブラウザに戻って、メニュー追加ページで適当に情報を入力して、送信ボタンを押してみます。正常に送信された場合は、以下画像のようにフラッシュメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/77d868bd-ccf7-863a-0f0b-e859039ea8c1.png)

何も入力せずに送信ボタンを押すと、以下画像のようにエラーが表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/f2f7211d-20b8-2a3e-1d8b-5c825854fef1.png)

#18：ダッシュボードへ反映させる

ダッシュボードに追加したメニュー情報を反映させます。

手順１： まずは、コントローラーに情報を表示させるためのデータ受け渡しの設定を行います。
ProductController.phpで、元々書いてあった『return view('product.index');』はコメントアウトして、index() メソッドに下二行を追記します。

```restaurant_menu\app\Http\Controllers\ProductController.php

    public function index()
   {
       // return view('product.index');

       $products = Product::latest()->paginate(5);
       return view('product.index', ['products' => $products]);
   }
```

特筆すべきは、paginate(5)のページネーションの箇所です。5項目追加したら次のページに行くように設定しています。

手順２： ダッシュボードのView（index.blade.php）へ移動して、43行目辺りの\<tbody\>以下に、//追記 もしくは //変更 と書かれている部分を追記・変更してください。@if() 文や、@foreach 、@else 文の箇所は、Categoryの時と同様なので説明は省きます。
また、115行目辺りの\$products->links()の箇所は、コントローラーで設定したpaginate(5)の部分を表示させています。

```restaurant_menu\resources\views\product\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container-fluid my-2">
 <div class="row m-2">
   <div class="col">
     <h3 class="font-weight-bold">ダッシュボード</h3>
   </div>
   <div class="col text-right">
     <a type="button" href="{{ url('/product/create/') }}" class="btn btn-primary text-right" role="button"><i class="fas fa-plus"></i> 新規追加</a>
   </div>
 </div>
 
 <table class="table table-bordered">
   <thead class="table-dark">
     <tr>
       <th scope="col">
         #
       </th>
       <th scope="col">
         画像
       </th>
       <th scope="col">
         商品名
       </th>
       <th scope="col">
         詳細
       </th>
       <th scope="col">
         値段
       </th>
       <th scope="col">
         カテゴリー
       </th>
       <th scope="col">
         編集
       </th>
       <th scope="col">
         削除
       </th>
     </tr>
   </thead>
   <tbody>
     @if(count($products) > 0 )  //追記
     @foreach($products as $key=>$product)  //追記
     <tr>
       <th scope="row">
         {{ $key+1 }}  //変更
       </th>
       <td style="max-width: 200px;">
         <img src="{{asset('images')}}/{{$product->image}}" class="img-fluid" />  //変更
       </td>
       <td>
         {{$product->name}}  //変更
       </td>
       <td style="max-width: 300px;">
         {{$product->description}}  //変更
       </td>
       <td>
         {{$product->price}} 円  //変更
       </td>
       <td>
         {{$product->category->name}}  //変更
       </td>
       <td>
         <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
       </td>
       <td>
         <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button>
       </td>
     </tr>
     @endforeach  //追記
     @else  //追記
     <tr>  //追記
       <td colspan="8">追加された商品情報はありません。</td>  //追記
     </tr>  //追記
     @endif  //追記
   </tbody>
 </table>
 
 <div class="d-flex">  //追記
   <div class="mx-auto">  //追記
     {{$products->links("pagination::bootstrap-4")}}  //追記
   </div>  //追記
 </div>  //追記
 
</div>
@endsection
```

手順３： 63 行目辺りの『{{\$product->category->name}}』の箇所ですが、これはProductモデルからCategoryモデルにアクセスしようとしている為、（厳密に言うと、Categoryモデルのインスタンスのnameプロパティの値にアクセス）モデルのリレーション設定が必要です。
ProductモデルのモデルファイルProduct.phpで、以下のようにcategory()メソッドを追記します。一つのメニューにつき、一つのカテゴリーがあるので、関係性はhasOneにします。
Laravelのモデルのリレーションについてご存知でない方は、ご自身で調べてみてください。

```restaurant_menu\app\Product.php

class Product extends Model
{
   protected $fillable=['name', 'description', 'price', 'image', 'category_id'];
   
   public function category(){
   	return $this->hasOne('App\Category','id','category_id');
   }
}
```

手順４： メニュー追加ページで、適当に情報を入力した後に、『＜ 戻る』ボタンを押してダッシュボードを表示させてみます。すると、以下画像のように表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/9761817b-1db6-527e-5655-c55c71c99016.png)

手順５： 画面上部の『Restaurant Menu』の部分ですが、ここをクリックするとダッシュボードに飛ぶように設定しようと思います。C:\xampp\htdocs\restaurant_menu\resources\views\layouts\app.blade.phpで、26行目辺りの以下コード部分（href属性のとこ。）を、『url('/product')』に変更します。

\<a class="navbar-brand" href="{{ url('/') }}"\>
↓変更
\<a class="navbar-brand" href="{{ url('/product') }}"\>

#19：編集/削除機能をつける（メニュー）

ダッシュボードの編集/削除機能を完成させていきます。

手順１： まずはダッシュボードのview画面を作成します。コードは以下の通りです。編集ボタンと削除ボタンの箇所に、カテゴリーでやった時と同様にコードを追記しています。その為、ここでのコードに関する説明は省きます。

```restaurant_menu\resources\views\product\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container-fluid my-2">
 <div class="row m-2">
   <div class="col">
     <h3 class="font-weight-bold">ダッシュボード</h3>
   </div>
   <div class="col text-right">
     <a type="button" href="{{ url('/product/create/') }}" class="btn btn-primary text-right" role="button"><i class="fas fa-plus"></i> 新規追加</a>
   </div>
 </div>
 
 @if (session('message'))  //追記
 <div class="alert alert-success" role="alert">{{ session('message') }}</div>  //追記
 @endif  //追記
 
 <table class="table table-bordered">
   <thead class="table-dark">
     <tr>
       <th scope="col">
         #
       </th>
       <th scope="col">
         画像
       </th>
       <th scope="col">
         商品名
       </th>
       <th scope="col">
         詳細
       </th>
       <th scope="col">
         値段
       </th>
       <th scope="col">
         カテゴリー
       </th>
       <th scope="col">
         編集
       </th>
       <th scope="col">
         削除
       </th>
     </tr>
   </thead>
   <tbody>
     @if(count($products) > 0 )
     @foreach($products as $key=>$product)
     <tr>
       <th scope="row">
         {{ $key+1 }}
       </th>
       <td style="max-width: 200px;">
         <img src="{{asset('images')}}/{{$product->image}}" class="img-fluid" />
       </td>
       <td>
         {{$product->name}}
       </td>
       <td style="max-width: 300px;">
         {{$product->description}}
       </td>
       <td>
         {{$product->price}} 円
       </td>
       <td>
         {{$product->category->name}}
       </td>
       <td>
         <a href="{{route('product.edit',[$product->id])}}">  //追記
           <button type="button" class="btn btn-outline-danger"><i class="far fa-edit"></i> 編集</button>
         </a>  //追記
       </td>
       <td>
         <!-- <button type="button" class="btn btn-outline-primary"><i class="far fa-trash-alt"></i> 削除</button> -->  //コメントアウト
           //ここから追記
         <button type="button" class="btn btn-outline-primary" data-toggle="modal" data-target="#exampleModal{{$product->id}}"><i class="far fa-trash-alt"></i> 削除</button>
         
         <!-- Modal -->
         <div class="modal fade" id="exampleModal{{$product->id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
           <div class="modal-dialog" role="document">
             <form action="{{ route('product.destroy', [ 'product' => $product->id ]) }}" method="POST">
               @csrf
               @method('DELETE')
               <div class="modal-content">
                 <div class="modal-header">
                   <h5 class="modal-title" id="exampleModalLabel">カテゴリー削除</h5>
                   <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                   </button>
                 </div>
                 <div class="modal-body">
                   本当に削除しますか？
                 </div>
                 <div class="modal-footer">
                   <button type="button" class="btn btn-secondary" data-dismiss="modal">キャンセル</button>
                   <button type="submit" class="btn btn-primary">削除</button>
                 </div>
               </div>
             </form>
           </div>
         </div>
         //ここまで追記
       </td>
     </tr>
     @endforeach
     @else
     <tr>
       <td colspan="8">追加された商品情報はありません。</td>
     </tr>
     @endif
       
   </tbody>
 </table>
 
  <div class="d-flex">
   <div class="mx-auto">
    {{$products->links("pagination::bootstrap-4")}}
   </div>
  </div>
 
</div>
@endsection
```

手順２：次に、編集ボタンを押したときの編集画面のViewを作成していきます。productフォルダにedit.blade.phpという名前でファイルを作ります。こちらもカテゴリーの時と同様、追加フォーム画面とほぼ一緒です。コードは以下の通りです。

```restaurant_menu\resources\views\product\edit.blade.php

@extends('layouts.app')

@section('content')
<div class="container mt-3" style="max-width: 720px;">
<div class="text-right">
  <a href="{{ url('/product/') }}">＜ 戻る</a>
</div>

<form action="{{ route('product.update', [$product->id]) }}" method="POST" enctype="multipart/form-data">
  @csrf
  @method('PUT')
  <div class="form-group" style="margin-top: 30px; margin-bottom: 30px">
    <label for="name" class="font-weight-bold">商品名</label>
    <input type="text" class="form-control @error('name') is-invalid @enderror" id="name" name="name" value="{{ $product->name }}"/>
    @error('name')
    <p class="text-danger">{{ $message }}</p>
    @enderror
  </div>
  <div class="form-group" style="margin-bottom: 30px">
    <label for="textarea" class="font-weight-bold">詳細</label>
    <textarea class="form-control @error('description') is-invalid @enderror" id="textarea" rows="5" name="description">{{ $product->description }}</textarea>
    @error('description')
    <p class="text-danger">{{ $message }}</p>
    @enderror
  </div>
  <div class="form-group" style="margin-bottom: 30px">
    <label for="price" class="font-weight-bold">値段</label>
    <input type="text" class="form-control @error('price') is-invalid @enderror" id="price" name="price" value="{{ $product->price }}"/>
    <small class="form-text text-muted">半角数字で入力してください。</small>
    @error('price')
    <p class="text-danger">{{ $message }}</p>
    @enderror
  </div>
  <div class="form-group" style="margin-bottom: 30px">
    <label for="category" class="font-weight-bold">カテゴリー</label>
    <select class="form-control @error('category') is-invalid @enderror" id="category" name="category">
      <option value="" disabled selected style="display: none;">カテゴリーを選択してください。</option>
      @foreach(App\Category::all() as $category)
      <option value="{{ $category->id }}" @if($category->id == $product->category_id) selected @endif>{{ $category->name }}</option>
      @endforeach
    </select>
    @error('category')
    <p class="text-danger">{{ $message }}</p>
    @enderror
    <div class="text-right mt-2">
      <a type="button" href="{{ url('/category/create/') }}" class="btn btn-outline-secondary py-1" role="button">新規追加</a>
      <a type="button" href="{{ url('/category/') }}" class="btn btn-outline-secondary py-1" role="button">編集</a>
    </div>
  </div>
  <div class="form-group" style="margin-bottom: 30px">
    <label for="image" class="font-weight-bold">画像アップロード</label>
    <input type="file" class="form-control-file @error('image') is-invalid @enderror" id="image" name="image" />
    @error('image')
    <p class="text-danger">{{ $message }}</p>
    @enderror
  </div>
  
  <button type="submit" class="btn btn-primary my-3">送信</button>
  
</form>
</div>
@endsection
```

上記のコードで特筆すべきことは、商品名等の各項目のinputタグ等にvalue値を書いていますが、textareaタグにはそもそもvalue属性はないので、タグの中にそのまま書いています。

手順３： コントローラーの設定を行います。ProductController.phpの edit()メソッド、update()メソッド、そしてdestroy()メソッドを以下のように設定します。カテゴリーでやった時とほぼ同様なので、コードの説明は省きます。

```restaurant_menu\app\Http\Controllers\ProductController.php

    public function edit($id)
   {
       $product = Product::find($id);
       return view('product.edit', ['product' => $product]);
   }
    public function update(Request $request, $id)
   {
       request()->validate(
           ['name' => 'required',
            'description' => 'required',
            'price' => 'required|integer',
            'category' => 'required',
            'image' => 'mimes:jpeg,png,jpg,gif,svg'],
           ['name.required' => '商品名を入力してください。',
            'description.required' => '詳細を入力してください。',
            'price.required' => '値段を入力してください。',
            'category.required' => 'カテゴリーを入力してください。']
       );
       $product = Product::find($id);
       $name = $product->image;
       if( $request->hasFile('image')) {
           $image = $request->file('image');
           $name = time().'.'.$image->getClientOriginalExtension();
           $destinationPath = public_path('/images');
           $image->move($destinationPath,$name);
       }
       $product->update([
           'name'=>request('name'),
           'description'=>request('description'),
           'price'=>request('price'),
           'category_id'=>request('category'),
           'image'=>$name
       ]);
       return redirect()->route('product.index')->with('message','商品情報が更新されました。');
   }
update() メソッドに関してですが、編集ページなので、画像はアップロードしないで、元の画像を使うときもあるかと思います。なので、バリデーションのrequiredは消します。

    public function destroy($id)
   {
       $product = Product::find($id);
       $product->delete();
       return redirect('/product')->with('message', '商品情報が削除されました。');
   }
```

手順４： ブラウザで確認してみます。まずは、『 http://127.0.0.1:8000/product/ 』にアクセスして、登録したメニューのどれでもいいのですが、編集ボタンを押します。すると、以下画像のように編集前のデータが入った状態でページが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/25f23f71-4853-dd61-23c3-538e3fa4ab2d.png)

編集して送信ボタンを押すと、ダッシュボードにリダイレクトされてフラッシュメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/c3c22d2e-f53e-d691-8aa6-a80b54208d90.png)

削除ボタンを押すと、以下画像のようにモーダル表示されて、データを削除することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/fd2377e8-ad08-c727-b9c1-fb84c0806346.png)

#20：お客さん用画面を作成する

最後にお客さん用の画面を作成します。

手順１： まずはルートの設定をします。これは、リソースルーティングでは設定されていないページになるので、手動で設定する必要があります。C:\xampp\htdocs\restaurant_menu\routes\web.phpで、以下のように追記します。

```restaurant_menu\routes\web.php
Route::get('/', 'ProductController@productTop');
```

手順２： 次に、コントローラーに設定します。ProductController.phpに、productTop()というメソッドを以下のように追記します。

```restaurant_menu\app\Http\Controllers\ProductController.php
    public function productTop() {
       $categories = Category::latest()->get();
       return view('product.top', ['categories' => $categories]);
   }
```

手順３： Categoryモデルを使うので、ProductController.phpの上部に『use App\Category;』の追記を忘れないようにします。 

```restaurant_menu\app\Http\Controllers\ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Product;
use App\Category;  //追記

以下省略
｜
｜
```

手順４： 次にViewの設定をします。C:\xampp\htdocs\restaurant_menu\resources\views\productに、top.blade.phpという名前でファイルを作ります。コードは以下の通りです。

```restaurant_menu\resources\views\product\top.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="{{ asset('js/app.js') }}" defer></script>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
@foreach($categories as $category)
<div class="container mt-5">

  <h3 class="text-danger font-weight-bold">{{$category->name}}</h3>
  <hr class="bg-danger" />
  <div class="row row-cols-3 mb-5">
  @foreach(App\Product::where('category_id',$category->id)->get() as $product)
    <div class="card">
      <img style="width: 100%; height: 15vw; object-fit: cover;" src="{{ asset('images') }}/{{ $product->image }}" class="card-img-top" />
      <div class="card-body">
        <h5 class="card-title font-weight-bold" style="display:inline;">{{ $product->name }}</h5><span class="card-title pr-1" style="float: right">{{ $product->price }} 円 + 税</span>
        <hr />
        <p class="card-text">{{ $product->description }}</p>
      </div>
    </div>
    @endforeach
  </div>
  
</div>
@endforeach
</body>
</html>
```

ここで特筆すべきは、『 @foreach(App\Product::where('category_id',\$category->id)->get() as $product) 』の部分です。
まず、コントローラーからproductモデルの値が渡ってきている訳ではないので、ここでProductモデルにアクセスしています。また、カテゴリー別に分けてメニューを表示する為に、クエリビルダのwhere節を使っています。カテゴリーをチェックして、同じカテゴリーのもののみ、その後の項目を表示させる為です。
Laravelのクエリビルダについて、わかりやすくまとめてらっしゃるサイトがあったので、ご紹介します。↓↓こちらのサイトです。

[Laravel クエリビルダ記法まとめ](https://www.ritolab.com/entry/93)

手順５：  メニュー追加ページで情報入力した後に、『 http://127.0.0.1:8000/ 』にアクセスすると、以下のような感じで表示されるはずです。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235741/ce36f697-4463-31ab-dd91-848d86b56076.png">

#21：認証機能をかける

現段階では、ダッシュボード等の管理画面に、ログインしていなくてもアクセスできてしまうので、認証機能をかけます。
Bootstrapをインストールした時に、一緒にLaravelのauthentication機能もインストールしているので、今回やるべきことは簡単です！
ProductController.phpで、categoryとproductのリソースルーティング部分に、以下のように『->middleware('auth')』を追記するだけです！

```restaurant_menu\app\Http\Controllers\ProductController.php
Route::resource('category','CategoryController')->middleware('auth');
Route::resource('product','ProductController')->middleware('auth');
```

これで『 http://127.0.0.1:8000/product/create 』や、『 http://127.0.0.1:8000/category 』にアクセスしようとすると、ログインページにリダイレクトされます！

以上で完成です。お疲れさまでした！