スクリーンショット_2020-01-25_21

Laravel6.0(PHP7.3)+MySQL+Laradockで簡易的なECサイトを作る④

お疲れ様です。向江です。
すでに4記事目ですね!
ここまで来た方はそれだけでも持続力があるので、十分に自分を褒めてあげていいと思います。

結局なんだかんだプログラミングって
才能やコツとかの前にどれだけコードを書いたかってのが初学者にとっては絶対的な尺度になると思ってます。
(もちろんその後は色々考えて行かないといけないですが。)

ということでたくさん書いていきましょう!


今までの記事は

■最初の記事↓
https://note.com/mukae9/n/n12cc13fd4f90

■2番目の記事↓
https://note.com/mukae9/n/naf7dff31b4db

■3番目の記事↓
https://note.com/mukae9/n/n2ed6be437f0d

です!
カートを表示させる課題がありましたね。


******前回の記事から抜粋*******

■routes/web.phpで/mycartにアクセスされた場合でShopController@myCartメソッドが発動するようにルーティング

■mycart.blade.phpを作成(shop.blade.phpと同じ構成でbody内は下記参考)

■Cartモデルを作成

■cartsテーブルにphpMyadminからでいいので、
id=1,
stock_id=1,
user_id=1

id=2,
stock_id=2,
user_id=2


の2つのダミー情報を入れておく。

■ShopController@myCartに
Cartモデルを使ってcartsモデルからの全データを取得
その値を引き渡してmycart.blade.php表示させる処理を記述。

■mycart.blade.phpのbody内に<h1>カートの中身</h1>とControllerから渡されたuser_idとstock_idをforeachを使って表示
(1122と味気なく表示されたらOK)

実践課題
■/mycartはログインしている人だけに表示させたい!対策をしてみよう!
ヒント:middleware('auth')を使う!

**********************

できましたでしょうか?
まだ出来ていない方はチャレンジしてみてくださいね。

答えを見ながら模写するのと、
考えながら0から自分でコードを書くのでは
習得率が違いますよ!
(二つの学校で講師+メンティー2名に教えてる立場なのでその差はよく認識しています。)

それでは詳細は3記事目に書いていますので
パパッと答えあわせ感覚で進めていきます。

???ってなる方は時々前の記事に戻ってくださいね。
詳しく解説しています。


1、カート画面を表示させる

課題①:routes/web.phpで/mycartにアクセスされた場合でShopController@myCartメソッドが発動するようにルーティング

Route::get('/mycart', 'ShopController@myCart');

これはもう説明不要かな。

課題②:mycart.blade.phpを作成(shop.blade.phpと同じ構成でbody内は下記参考)

下記参考なのでとりあえずshop.blade.phpを複製してmycart.blade.phpに名前を変えておきます。

課題③:Cartモデルとcreate_carts_tableを作成
cartsテーブルの構成は
・id(bigIncrements)
・stock_id(int)
・user_id(int)
・timestamps()

記事①の課題ですでにcartsテーブルは作ってると思うので
まずはモデルの作成です。

php artisanの出番ですね。
app(Laravel自体フォルダ)でターミナルを開き

php artisan make:Model Models/Cart

作成したcart.phpを開き
変更を可能とするカラムを指定しておきます。

    protected $fillable = [
       'stock_id', 'user_id',
   ];


次はマイグレーションファイルの作成です。
同じくapp(Laravel自体フォルダ)でターミナルを開き

php artisan make:migration create_carts_table

作成されたファイルを開いて
catsテーブルの構成は
・id(bigIncrements)
・stock_id(int)
・user_id(int)
・timestamps()
とのことなので、

    public function up()
   {
       Schema::create('carts', function (Blueprint $table) {
           $table->bigIncrements('id');
           $table->bigInteger('stock_id');
           $table->bigInteger('user_id');
           $table->timestamps();
       });
   }

となるかと思います。

後はマイグレーションするだけですね、
laradockフォルダ上で、
(もちろんDockerを稼働させている状態です)

まずコンテナに入ります。

docker-compose exec workspace bash

app(laravel自体フォルダ)に移動します。

cd app 

マイグレート!

php artisan migrate

これでOKです!

課題④:cartsテーブルにphpMyadminからでいいので、
id=1,
stock_id=1,
user_id=1

id=2,
stock_id=2,
user_id=2

の2つのダミー情報を入れておく。

これは自分の環境構築で作ってくれた方は
Dockerを起動している状態で
(laradockフォルダ上でdocker-compose up -d mysql nginx phpmyadminをしました?)

http://localhost:8080

自分の環境によって違います。

でphpmyadminが開きます。
他の環境構築方法で作っている場合はその方法で
phpmyadminを開いて下さい。

ログイン後に
defaultデータベース(環境構築方法によって名前違います)を開くと
今まで作ったテーブルたちがいるのでcartsテーブルを開きます。

※凡ミスではないのになぜかログインできない方はLaradockの癖にやられてるかも!
この記事の後半を確認してください!

https://qiita.com/mukae_tech/items/24709085948a6d707da3

あとはcartsテーブル上で指示通りダミーデータを挿入します。
(わからない方はググりましょう!)

課題⑤:ShopController@myCartに
Cartモデルを使ってEloquantで全データを取得
その値を引き渡してmycart.blade.php表示させる処理を記述。

ちょっと難しく感じるかもしれませんが、
やっていることは3記事目の内容と一緒です!

Cartモデルを使うので
 Eloquantを使うならそのコントローラーでモデルをuseで結びつけてあげる必要があります。

なのでShopController.phpの頭の部分に

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Cart;

を追記します。(もともとあるのもあります)

ルーティングを
Route::get('/mycart', 'ShopController@mycart');
としているので、

mycartメソッドを作ってあげます。
そしてEloquantで全件取得なのでall()で良さそうですね。
情報を入れる変数は$myCartsにしてみます。
後はreturnで返すだけですね!
(???って方は3記事目を復習してください!詳しく書いてます!)

   public function myCart()
   {
       $my_carts = Cart::all();
       return view('mycarts',compact('my_carts'));
       
   }

課題⑥:mycart.blade.phpに<h1>カートの中身</h1>とControllerから渡されたuser_idとstock_idをforeachを使って表示
(1122と味気なく表示されたらOK、追加位置はshop.blade.phpと同じく
<div class="d-flex flex-row flex-wrap">以下でOK)

@extends('layouts.app')

@section('content')
<div class="container-fluid">
 <div class="">
     <div class="mx-auto" style="max-width:1200px">
         <h1 class="text-center font-weight-bold" style="color:#555555;
             font-size:1.2em; padding:24px 0px;">カートの中身</h1>
         <div class="card-body">
             
               {{-- 追加 --}}               
               @foreach($my_carts as $my_cart)
                    {{$my_cart->stock_id}}<br>
                    {{$my_cart->user_id}}<br>
               @endforeach

              {{-- ここまで --}}
             
         </div>
     </div>
 </div>
</div>
@endsection

これで一通りは完了ですね!

こんな感じになっていれば成功です!↓

スクリーンショット 2020-01-25 20.22.32


2、カートページはログイン状態のみ閲覧可能にする


実践課題①:/mycartはログインしている人だけに表示させたい!対策をしてみよう!
ヒント:middleware('auth')を使う!

ここは記事でも説明していなかったので実践課題です。

といってもかなり簡単に実装できます。
色々な方法がありますが、

Route::get('/mycart', 'ShopController@myCart')->middleware('auth');

これだけです。

これでこのルートはログイン状態じゃないとリダイレクトされます。

スクリーンショット 2020-01-25 20.24.25

/mycartを
リロードしたらログイン画面に飛ばされました。
せっかくなので右上のRegisterから会員登録をしてみてください!
ログイン状態だとカートページが見れるはずです!

さてここで、
なぜリダイレクト、、、?
どこに???

軽くツアーをしてみましょう。
->middleware('auth')
となっていますので、authという名前のミドルウェアが存在していることは分かります。

ミドルウェアはリクエストが来てすぐと、レスポンスを返す時に動作する機能です。
厳密には違いますが簡単に言うとコントローラーの処理前と処理後といったところでしょうか。

ミドルウェアを使えば、
コントローラーがどんどん太っていくのを防げますし、
「なんにせよログインしてるかどうかを先に判断したい」
などメイン処理をする前に「なんにせよ」的な機能をつけたい時によく使う気がする。

あとミドルウェア化すると多面で使えて便利ですね。
当然今回のログイン認証にも大活躍します。


まずはミドルウェアの利用を司るapp/http/kernel.phpを見てみます。

すると少しスクロールすると、
$routeMiddlewareというのを発見しました!
そこの先頭に'auth'がいますね!

スクリーンショット 2020-01-24 16.15.47

ここで
->middleware('auth')を使えば
\App\Http\Middleware\Authenticate::classと繋がることが分かります。

なので->middleware('auth')の中身はAuthenticate.phpです。

app/http/Middleware/Authenticate.phpを覗いてみましょう。

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
   /**
    * Get the path the user should be redirected to when they are not authenticated.
    *
    * @param  \Illuminate\Http\Request  $request
    * @return string
    */
   protected function redirectTo($request)
   {
       if (! $request->expectsJson()) {
           return route('login');
       }
   }
}

まだまだ紐解いていく必要がありそうですね。
次見るべきは
Illuminate\Auth\Middleware\Authenticateでしょうか。
venderフォルダの中に隠れています。

ただこれ以上行くと初学者は心が折れてしまいますので、
今はこうやってファイル群が裏に隠れているから
Laravelが準備している->middleware('auth')だけでログイン状態のチェックとリダイレクトが出来ると言う認識で十分です。

以上で前回の課題は完了です!

3、「カートに入れる」機能を作る

今の状態で
■商品一覧ページ(shop.blade.php)
■カートページ(cart.blade.php)
が出来上がりました。

次はカートに追加する機能を実装して行きます。
大きな流れは
①商品一覧ページの各商品ごとに「カートに追加」ボタンを作る
②カートに追加ボタンからPOST送信で/mycartにアクセスされた場合のルートを作成する。
③Cartsテーブルにログイン状態のユーザーのIDと商品のIDを格納する。
④Cartsテーブルから情報を取得して表示する。

です。
これだけでプログラミングのイメージがつく方はまずは自分だけで実装してみてください!
力になると思います!


では進んでいきます!
①商品一覧ページの各商品ごとに「カートに追加」ボタンを作る

shop.blade.phpですね。
以下のように追記をします。

@extends('layouts.app')

@section('content')
<div class="container-fluid">
   <div class="">
       <div class="mx-auto" style="max-width:1200px">
           <h1 style="color:#555555; text-align:center; font-size:1.2em; padding:24px 0px; font-weight:bold;">商品一覧</h1>
           <div class="">
               <div class="d-flex flex-row flex-wrap">
           
                       @foreach($stocks as $stock)

                           
                           <div class="col-xs-6 col-sm-4 col-md-4 ">
                               <div class="mycart_box">
                                   {{$stock->name}} <br>
                                   {{$stock->fee}}円<br>
                                   <img src="/image/{{$stock->imgpath}}" alt="" class="incart" >
                                   <br>
                                   {{$stock->detail}} <br>

                                    {{-- 追加 --}}

                                   <form action="mycart" method="post">
                                       @csrf
                                       <input type="hidden" name="stock_id" value="{{ $stock->id }}">
                                       <input type="submit" value="カートに入れる">
                                   </form>

                                    {{-- ここまで --}}
                               </div>

                                {{-- 追加 --}}
                               <a class="text-center" href="/">商品一覧へ</a>
                                {{-- ここまで --}}  
 
                           </div>
                       @endforeach                    
               </div>
               <div class="text-center" style="width: 200px;margin: 20px auto;">
               {{  $stocks->links()}} 
               </div>
           </div>
       </div>
   </div>
</div>
@endsection

スクリーンショット 2020-01-25 20.33.10

最悪なUIの状態となってしまっていますがなんとか追加できましたね
デザイン部分は後ほどやりたいと思っているのでグッとこらえてください。

今回追加しているのは以下です。

<form action="mycart" method="post">
 @csrf
 <input type="hidden" name="stock_id" value="{{ $stock->id }}">
 <input type="submit" value="カートに入れる">
</form>

form/inputについてはhtmlの基本事項なので割愛します。
{{ $stock->id }}もすでに解説済みですね。

ここで理解しておきたいのは
@csrfです。
これはセキュリティ対策ですね。
これを入れないとLaravelではformでの遷移を許可してくれません。
絶対に必要なおまじないのようなものなのでformが出たらまずは@csrfと覚えてください。
(無効にすることもできます)

意外と簡単に①は実装できちゃいました。

次は②なのでroutes/web.phpに追記して行きます。

Route::get('/mycart', 'HomeController@myCart');
Route::post('/mycart', 'ShopController@addMycart');//追記

これで/mycartにpost送信でアクセスされた時にはaddMycartメソッドが実行される事になります。

ちなみにGET送信とPOST送信の違いがわからない方は、
・GET送信→普通にアクセス
・POST送信→formを経由してのアクセス
くらいの認識で今は十分かなと思います。

次はShopControllerでaddMycartメソッドの中身を作り込んで行きます。

③Cartsテーブルにログイン状態のユーザーのIDと商品のIDを格納する。
④Cartsテーブルから情報を取得して表示する。

一気に作って行きましょう。

ShopControllerは以下のようになります。

    public function addMycart(Request $request)
   {
       $user_id = Auth::id(); 
       $stock_id=$request->stock_id;

       $cart_add_info=Cart::firstOrCreate(['stock_id' => $stock_id,'user_id' => $user_id]);

       if($cart_add_info->wasRecentlyCreated){
           $message = 'カートに追加しました';
       }
       else{
           $message = 'カートに登録済みです';
       }

       $my_carts = Cart::where('user_id',$user_id)->get();

       return view('mycart',compact('my_carts' , 'message'));

   }

$user_id = Auth::id()
これはログイン状態のユーザーのidを取得します。
Authファサードを使っています!

説明が長くなるので割愛しますが、ログイン状態のチェックなど様々な機能が実装できるので一度ドキュメントをみておくといいかもしれません!

https://readouble.com/laravel/6.x/ja/authentication.html
(後半)

そのあとは
$stock_id=$request->stock_id
でPOST送信で送られてきたstock_idを取得しています。
さっきshop.blade.phpで
<input type="hidden" name="stock_id" value="{{ $stock->id }}">
って作りましたよね!
そのname="stock_id"が->stock_idで結びついています。

またShopControllerの頭にも

use Illuminate\Http\Request

と言うのがあってそれをメソッドで利用するために
public function addMycart(Request $request){
と最初のメソッドの引数にRequest $requestが入っています。

こちらも深入りは避けますが、
これらがあるからPOST送信のリクエストの中身が参照できるようになり、
$request->stock_idという書き方でformで送られてきた値を取得することができます。
フォームを使うのであれば必ず使うやつですので覚えておきましょう!

次は
$cart_add_info=Cart::firstOrCreate(['stock_id' => $stock_id,'user_id' => $user_id]);
です。
またfirstOrCreateが出てきましたね、
stock_idとuser_idが全く同じレコードが存在しないか確認して保存してくれます。

これだけでもいいですが、
■カートに追加した場合(同じレコードがなかった場合)
■カートに追加しない場合(同じレコードがあった場合)
で条件分岐させて表示させる文字を変えてみましょう。

Cart::firstOrCreateを格納した変数に対して、
->wasRecentlyCreatedを使います。
直近で保存された場合はtrueを
保存されていない場合はfalseを返してくれます。


if($cart_add_info->wasRecentlyCreated){
   $message = 'カートに追加しました';
}else{
   $message = 'カートに登録済みです';
}

これで状況にあったメッセージを表示させる事に成功しました。

今回は在庫が1つしかない設定ですのでこのようにしていますが、
カートに同じ種類のものを複数入れて行きたいのであれば、
else内でカート内数を+1させる処理をしてその情報をデータベースに持たせるなどしても良さそうですね。
同時にstocksテーブルにも在庫状態を…ってなってくるのでこの記事では触れないおきます。実践でやってみてください!

さあ、あとはカート情報を表示させるだけです!

4、カートの中身を表示する

ShopContollerの中の

$my_carts = Cart::where('user_id',$user_id)->get();

がカート内情報を取得するところですね。
仕組みはかなり単純です。

where句でuser_idが現在のログインしているユーザーのidと同じかどうかで情報を取得してきています。
あとは取得した情報をカートページで表示させるだけです。


return view('cart',compact('mycarts' , 'message'));

しっかりmessageも連れて行ってあげましょう。

連れて行く先の
 mycart.blade.phpも編集を加えて行きます!

@extends('layouts.app')

@section('content')
<div class="container-fluid">
   <div class="">
       <div class="mx-auto" style="max-width:1200px">
           <h1 class="text-center font-weight-bold" style="color:#555555;  font-size:1.2em; padding:24px 0px;">
           {{ Auth::user()->name }}さんのカートの中身</h1>

           <div class="">
               <p class="text-center">{{ $message }}</p><br>
               <div class="d-flex flex-row flex-wrap">

                   @foreach($my_carts as $my_cart)
                       <div class="mycart_box">
                           <p>ユーザーID:{{$my_cart->user_id}}</p>
                           <p>ストックID:{{$my_cart->stock_id}}</p>
                       <>/div
                   @endforeach

               </div>

               <a href="/">商品一覧へ</a>
           </div>
       </div>
   </div>
</div>
@endsection

追加された{{ Auth::user()->name }}はまたしてもAuthファサードです。ログイン者の情報を取得し今回はnameカラムを表示させています。


<p class="text-center">{{ $message }}</p><br>も追加されました。
これはコントローラーから送られてきたmessageを表示させています。

試しに色々カートにいれてみてください!
こんな感じになって行くと思います↓

スクリーンショット 2020-01-25 21.06.12

なんかカートができそうな雰囲気になってきましたね!!

4、今までのページのレイアウトを整える

さてこのままですとちょっとデザインのことを無視しすぎなので
軽く装飾しておきます。
デザインは自分は本職ではないのでご自身でデザインが得意な方は自分なりにしていただいて大丈夫です。

/resouces/sassフォルダを開いてください。

するとapp.scssが存在してるかと思います。
同じフォルダ内に

_style.scss
を新規ファイルで作成してください。
アンダーバーはミスじゃないですよ。
決まりなのでこう言う名前にしてくださいね。

そして
app.scssを開いて

// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');

// Variables
@import 'variables';

// Bootstrap
@import '~bootstrap/scss/bootstrap';

//追記します
@import 'style';

追記します。

これで
_style.scss
に書いたcssの内容が反映されるようになりました。

早速書いて行きましょう。

_style.scss

  img.cart{
   width: 30px;
 }
 
 img.incart{
   width: 50%;
   display: block;
   margin: 0 auto;
   height: 140px;
   object-fit: cover;
 }
 
 .mycart_box{
 
   color: #4c4c4c ;
   font-weight: bold;
   text-align: center;
   margin-top: 24px;
   padding: 24px 8px;
   font-size: 1.1em;
   background-color: #fefefe ;
   
 }
 
 .footer_design{
   background-color: #07728a ;;
   text-align: center;
   color: #fefefe ;
   padding: 60px;
 }
 
 .buy-btn{
   margin: 40px auto 60px;
   width: 200px;
   display: block;
   background-color: #ff5c73 ;
 }
 
 .ball{
   position: absolute;
 }

 .pagenate{
   width: 200px;margin: 20px auto;
 }

これでOK!

ですが、
このままだと反映されません。

scss(sass)ファイルはコンパイルしてcssに変換してあげる必要があります。

全然わからないって人も大丈夫!
Laravelにはlaravel Mixというビルドツールが最初から入っているので

app(Laravelフォルダ自体)をターミナルで開いて

npm run dev

これだけで変換が完了します。
sass-loaderがなんたらってエラーが出たら解決策は最初の記事に書いてますからね!

HPをみてみましょう!
(変化しない場合はキャッシュが残ってる場合かscssファイル名などのミスの可能性が高いです。)

スクリーンショット 2020-01-25 21.34.49

スクリーンショット 2020-01-25 21.38.43

なんか近づいてきましたね!

今回はここまでにしたいと思います!
あとは画像を表示させたり、カート機能を完成させたりです。

多分折り返しはしているはず!
また次回の記事でお待ちしてます〜!

次回の記事

https://note.com/mukae9/n/n18125664d380




***大阪の方でPHP学びたい方はここで先生してるんぜひ!***

http://code-create.tech/

雇われだけどね!!!!

この記事が気に入ったらサポートをしてみませんか?