Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
15
Help us understand the problem. What are the problem?

Laravelでsession(カート機能実装)についてまとめてみた

0.はじめに

この記事について

この記事は「Requestインスタンス」を用いたセッションに関する記事です。

Laravelを用いた共同開発講座に参加させていただきました。
その中で一際難しく感じたセッションを用いたカート機能の実装についてまとめたいと思います。
同じように悩む誰かの一助になれば幸いです。

転職前の若造の乱筆ですがよろしくお願いいたします。
間違い等あれば喜んで訂正させていただきます。

簡単に自己紹介

・医療職5年目
・完全独学6ヶ月後、共同開発講座に参加
・転職まであと○○(?)

ではさっそく参ります。

1.セッションとは

セッションて何?

【セッション = データを保存しておく仕組み】
です。

よくある"session"の説明   >>>  「アクセスの開始から終了までの一連の通信」   
実際の"session"のイメージ  >>>   「カギ」とか「合言葉」みたいな

という感じに、よくある説明と実際の掴みどころが少し違うような気がします。
よくある説明の通り、実現したいことは「アクセスの開始から終了までの一連の通信」を成り立たせることです。
SNSの場合毎回ログインせずとも、なぜかログイン後の画面からスタートできます。
これは一度ログインしたユーザーの情報を、サーバーが覚えてくれているから実現できます。
ショッピングサイトの場合でも、商品をカートに入れたあとにまたショッピングを楽しむにはカートに入れた商品のデータを保存しておく必要があります。
そのデータを保存するためにセッション機能があります。

「セッション機能をなぜ使うのか?」
この問に一言で答えるなら
「ステートレスなプロトコルをステートフルなプロトコルにするために使う」
となります。
これを超具体的に解説すると下記のようになります。

具体例で解説

①あるuserがSNSに初回ログインした時にクライアントは、サーバー(Laravel)に合言葉(セッション情報)を渡します。
②サーバーは合言葉を覚えます。
③userはSNSを閉じます(別のサイトに飛ぶとします)
④(サーバーはまだ覚えてます。)
⑤userはSNSのログイン後画面に戻ります。(合言葉を言う)
⑥サーバーはuserを識別し、歓迎してログイン後の状態にする。(合言葉を確認)
⑦ログインされた状態が保たれています(ステートフル!!)

※セッション機能がないともう一度ログインしないといけません(ステートレス。。)

つまり

ステート(状態)レス === (ログイン)状態が保てない

ステート(状態)フル === (ログイン)状態を保てる

ようにするのがセッション機能です。

おそらくこれだけでは不足だと思いますので
参考になり、わかりやすかった記事を掲載させていただきます。
https://qiita.com/Yametaro/items/9b65a21940e001554719
https://umaroidblog.com/webtechnology1

2.セッションを使うと何ができる?

①ログイン状態のキープ

②ショッピングカート機能として商品をカート内に入れたままの状態をキープ

だいたいこの2つです(他にもあると思います)
今回は②のショッピングカート機能を実装したので、そちらを深堀していきます。

3.セッションの使い方その①〜言葉で説明〜

この項でまず押さえていただきたいのが
「セッション操作は、サーバー(Laravel)内での動作である」
ということを忘れずにお進みください。(この前提が割と大事)

セッション操作の種類

Laravelでセッションを操作するには主に3つの方法があるようです。

①Requestインスタンス
②Sessionファサード
③Sessionヘルパ

今回は①Requestインスタンスを用いて実装しました。
→今回はショッピングカート機能なので、ユーザーが購入したい商品をカートにいれる際にFormタグで送信(HTTPリクエスト)するため、この方法を用います。
つまり
商品情報を含んだHTTPリクエストを受け取って、その情報をそのままサーバー(Laravel)にセッション情報として保存したい時に有用です。

大まかな流れ

大きな流れとしては以下のようになります。
やりたいことは非常に簡単です。

①飛んできたRequestをLaravelのセッションへ保存する
②保存したセッション情報を取得し、表示させる

この2つの動作をLaravel上で実装できればOKです。
やることはこの2つだけなのですが、ここにMVCや変数の受け渡しが絡んでくるためややこしいのだと思います...
次に実際に使用するコードについて見ていきます。

4.セッションの使い方その②〜コードで説明〜

使用するコード

addCartアクション
//セッションに「キー」という名前をつけて、セッション情報を保存します
$request->session()->put('ここにキーが入る', $ここに値が入る);

こちらのコードはaddCartアクション(名前は適当)に記載します。
つまりカートに商品をいれると言う動作を担うアクションに記載します。
このコードにより、サーバー(Laravel)にセッション情報が「キー」と言う名前で保存されます。

indexアクション
//セッションから「キー」という名前を探して、セッション情報を取得します
$request->session()->get('ここにキーが入る', $ここに値が入る);

こちらのコードはindexアクション(名前は適当)に記載します。
つまりカート内商品一覧を表示させる動作を担うアクションに記載します。
このコードにより、サーバ(Laravel)に保存していた「キー」と言う名前のセッション情報を引っ張り出します。

上記2つのコードを使用します

セッション情報の保存場所について

ちなみに
「セッション情報を保存する」とありますが、
いったいどこにどんな形で保存されるのか?

ここに保存されます↓↓↓
strage > framework > sessions
スクリーンショット 2020-12-29 0.01.02.png

その中身であるsession情報は以下の通り暗号化?されています↓

a:4:{s:6:"_token";s:40:"uK79rCecgKQ1OItE1PtKdwj5OgPQUX1DbS5tY9FS";s:9:"_previous";a:1:{s:3:"url";s:39:"http://192.168.33.11/●●●●●●●●●●●●●●●";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:3:"url";a:1:{s:8:"intended";s:25:"http://192.168.33.11/●●●●●●";}}

このように、セッション情報は一種の個人情報であるため、暗号化されてサーバー側に保存されています。

5.カート機能を実装してみる

では、いよいよ実装に入ります。

ルーティング

web.php
Route::resource('cartitem', 'CartController', ['only' => ['index']]);
Route::group(["prefix" => 'iteminfo'], function() {
    Route::get('/{id}', 'CartController@show');
    Route::post('/add', 'CartController@addCart')->name('addcart');
});

参考までに載せておきます。

コントローラ

CartController.php (showアクション)
public function show($id)
    {
        //変数の初期化
        $ProductInfo = array();
        $ProductCategory = array();
        $UserId = '';
        //urlパラメータから飛んできたユーザidを元にモデルからそれぞれ商品、カテゴリーを特定
        $ProductInfo = Product::findOrFail($id);
        $ProductCategory = Category::findOrFail($ProductInfo -> category_id);
        $UserId = Auth::user()->id;

        return view('iteminfo', 
        [
            'ProductInfo' => $ProductInfo,
            'ProductCategory' => $ProductCategory,
            'UserId' => $UserId,
        ]);
    }

showアクションはiteminfo画面(商品の詳細画面)を表示させるアクションです
参考までに載せておきます。

View(商品詳細画面) の Form部分

iteminfo.blade.php(Form部分)
{!! Form::open(['route' => 'addcart']) !!}

        {{ Form::hidden('user_id', $userId) }}

        {{ Form::hidden('productId', $productInfo->id) }}

    <div class="form-group row justify-content-center">
        <label class="col-form-label">購入個数</label>
        <div class="">

            <input type="number"
        class="inputNumber form-control" value="0" name="quantity" >
        </div>

        <lavel class="col-form-label"></lavel>
        <div class="col-sm-auto">
            {!! Form::submit('カートへ', ['class' => 'btn btn-primary']) !!}
        </div>
    </div>
{!! Form::close() !!}

解説

これはForm部分で 「カートへ入れる」のボタンの部分になります。
このボタンを押すと下記の動作がに入ります。

①{{ Form::hidden('user_id', $UserId) }}

②{{ Form::hidden('ProductId', $ProductInfo->id) }}

③<input 略 name="Quantity" >

この3つのname属性で送信する(Formで指定したaddCartという名前のルーティングへ)

web.phpを介して、CartController(addCartアクション)へいきます。

コントローラ(addCartアクション)

CartController(addCartアクション)

public function addCart(Request $request)
    {
        //セッションに保存したい変数を定義する(ここでは商品idと注文個数)
        //飛んできた$requestの中のname属性をそれぞれ指定
        $SessionProductId = $request->ProductId;
        $SessionProductQuantity = $request->Quantity;
        //配列の入れ物を作る(初期化)
        $SessionData = array();

        //作った配列に、compact関数を用いてidと個数の変数をまとめる(”” を使っているが変数の意味)
        $SessionData = compact("SessionProductId", "SessionProductQuantity");

        //session_dataというキーで、$SessionDataをセッションに登録
        $request->session()->push('session_data', $SessionData);

        return redirect('cartitem');
    }

解説

今回セッションに保存したい内容は
①注文された商品のid
②注文された個数
の2つになります。

なので
このアクションでセッションにIDと個数を保存します。

変数を定義して、 ProductId というname属性で飛んできた内容を$requestから抽出します。
$SessionProductId = $request->ProductId;

同じく Quantity というname属性で飛んできた内容を$requestから抽出します。
$SessionProductQuantity = $request->Quantity;

ここで新たな変数を定義し、空の配列を用意してあげます。
※ショッピングカート機能であれば、商品idと注文個数が1セットであって欲しいために新たな変数を定義し、ショッピングはたくさんの商品を買うので、データを管理しやすくするために配列を作成しました。
$SessionData = array();

作成した配列に2つの変数を統合します。
$SessionData = compact("SessionProductId", "SessionProductQuantity");
※この時ダブルクォーテーションがついているが"SessionProductId"は変数を意味しています。

セッションにpushして配列に次々と値を加えていく形をとる
$request->session()->push('session_data', $SessionData);
※大項目4にて、セッションに保存は”put”を用いていましたが、今回は配列に入れていくので”push”となります。

web.phpのcartitemにリダイレクトする

CartControllerのindexアクションに繋がる
(このindexアクションでカート内商品一覧を表示させる動作を担います)

コントローラ(indexアクション)

cartController(indexアクション)

public function index(Request request)
    {
        //セッションに保存していた値を取得し、変数として定義
        SessionData = request->session()->get('session_data');
        //セッションデータのなかのそれぞれのデータを抽出
        SessionProductId = array_column(SessionData, 'SessionProductId');
        SessionProductQuantity = array_column(SessionData, 'SessionProductQuantity');
        dd($SessionData);
    }

解説

セッションに保存していた値を取得し、変数で再定義します。

$SessionData = $request->session()->get('session_data');

array_column関数を用いてIDのデータをそれぞれ抽出し、これもまた変数で再定義します。
$SessionProductId = array_column($SessionData, 'SessionProductId');

注文個数(Quantity)のデータに関しても同様に。
$SessionProductQuantity = array_column($SessionData, 'SessionProductQuantity');

さて、ここで
dd($SessionData);
を記述すれば、ここにどのようなデータが飛んできているのかがわかります。
せっかくなので見ておきましょう。

6.セッションから取り出したデータ内容を確認

以下は商品詳細画面です。
ここに個数「5個」を入力して「カートへ」ボタンを押すとどうなるでしょう。
ちなみにこのサンプルデータのidは「2」です。
スクリーンショット 2020-12-29 23.43.02.png
ボタンを押すと
スクリーンショット 2020-12-29 23.44.10.png
配列でデータが飛んできているのがわかります。
その配列の中にidと個数の情報がはいっているのがわかります。

ではこのあと、他の商品画面に遷移してもう一つ商品をカートに入れてみるとどうでしょう。
商品idは「4」、個数は「8」個でカートに入れてみます。
スクリーンショット 2020-12-29 23.46.43.png
ボタンを押すと
スクリーンショット 2020-12-29 23.47.52.png
配列の中に配列でデータが増えて飛んできているのがわかります。
つまり、商品1つにつき、1つの配列でまとめてデータを送信しているということです。
さらに、先ほどカートへ入れた商品データの配列もそのまま残っていることがわかります。
つまり、セッションに保存された内容は、一度画面遷移を行っても情報は保持されたままということです。

そして
この取り出したデータ(変数)を元に、View(カート内商品一覧)でforeach文などを用いて商品データを表示させることができれば、カート機能の完成です!!

7.まとめ

今回はカート機能についてまとめてみました。
コントローラの使い方や変数の渡し方がすごく重要だと思います。
そして、これがセッションの全てではありませんが、非常に便利な機能だと感じました。
まだまだこれからも精進いたします!

少し長くなってしまいましたが、最後まで読んでいただいた方々、本当にありがとうございますm(__)m

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
15
Help us understand the problem. What are the problem?