ショッピングカートライブラリ LaravelShoppingcart 使ってみた

# はじめに

Laravelはフルスタックなフレームワークなので、単体でもわりと簡単になんでも作れてしまうのだが、
人気フレームワークだけあって、自分で作らなくてもPackagistやGitHubを漁れば
便利そうなライブラリがたくさん出てくる。

今回導入するショッピングカートの機能を持つライブラリもいくつか見つかったが、

+ 機能がシンプルである
+ 利用実績がたくさんある(GitHub Star数が多い)
+ ライブラリの更新が放棄されていない(Laravel 5.4対応が保証されている)

という点より、[LaravelShoppingcart](https://github.com/Crinsane/LaravelShoppingcart)を採用した。

以下、導入方法、基本的な使用方法を記載する。
もっとも、「機能がシンプルである」ため、
この記事を読まずとも右クリック→Google翻訳で問題なく導入できる気はするが。

# 導入
## インストール

+ composerでインストールする。

```
composer require gloudemans/shoppingcart
```

+ サービスプロバイダーとエイリアスを登録する。

```php:config/app.php
//サービスプロバイダー
Gloudemans\Shoppingcart\ShoppingcartServiceProvider::class

//エイリアス
'Cart' => Gloudemans\Shoppingcart\Facades\Cart::class
```

+ configファイルを```config/cart.php```へコピーする。

```
php artisan vendor:publish
```

## configファイルの設定例

カネを扱うライブラリではドルやユーロでの計算が前提となっていて詰むことも多々あるが、
幸いにもLaravelShoppingcartでは設定を変更することで日本円にも対応可能である。

```php:config/cart.php
    //ギョームで使用するなら税率変更処理や端数処理を実装する必要があると思われる
    'tax' => 8,

    //日本円に小数点は不要
    'format' => [
        'decimals' => 0,
        'decimal_point' => '',
        'thousand_seperator' => ','
    ],
```

ところでtaxのデフォルト値は**21%**である。
これだけ消費税の高い国(おそらくヨーロッパ)であれば軽減税率制度があると思うのだが、
現地の人はカスタマイズなしでそのまま使えるのだろうか。

# 使用方法

## カートに入れる処理
```Cart::add()``` を使う。
カートに投入されるとそれぞれrowIdが割り当てられる。
実際に使用する場合は商品Eloquentモデルと関連付けることとなると思われるが、2つの方法がある。

1. メソッドチェーンでモデルと関連付ける
2. Buyableインターフェースを使用する

基本的には2の方法で実装したほうがスマートである。

### メソッドチェーンでモデルと関連付ける

```php:HogeController.php
$hogeProduct = HogeProduct::find($hogeId)
//->associate()にクラス名を渡すことで関連付けが行われる
Cart::add($hogeProduct->id, $hogeProduct->name, $qty, $hogeProduct->$price, ['hogeOption' => 'huga'])
->associate(HogeProduct::class);
```

ID、商品名、量、単価の4引数が必須なため、長く冗長なコードになる
また、```Cart::add()```に配列を渡すことで複数商品を同時にカートに入れることもできるのだが、
```->associate()```は配列に対応していないようで、配列を代入しようとすると例外が発生する。

### Buyableインターフェースを使用する

+ 商品Eloquentモデルに以下のインターフェースおよびメソッドを追加する。

```php:HogeProduct.php
class HogeProduct extends Model implements Buyable
{
        public function getBuyableIdentifier($options = null)
    {
        return $this->id;
    }

    public function getBuyablePrice($options = null)
    {
        //商品価格カラム名
        return $this->price;
    }

    public function getBuyableDescription($options = null)
    {
        //商品名カラム名
        return $this->name;
    }
}
```

上記事前準備を行うことで、引数2つでカートに投入することができるようになる。

```php:HogeController.php
$hogeProduct = HogeProduct::find($hogeId)
//スマートになった
Cart::add($hogeProduct, $qty);
```

## カートの中身を参照する処理
Cart::content()を呼び出すことで、Collection形式でカートの中身をすべて取得できる。
カートの中身にはそれぞれrowIdが割り振られているので、カートの中身を編集するにはrowIdを引数とする。
詳細は[公式](https://github.com/Crinsane/LaravelShoppingcart)を参照してほしいが、以下のようなメソッドを使用することができる。

```php
//特定商品の更新(第2引数に連想配列を渡すことで、数量以外の項目も変更可能)
Cart::update($rowId, $qty)

//特定商品の削除
Cart::remove($rowId)

//特定商品の取得
Cart::get($rowId)
```

## カート全体を参照する処理
こちらも詳細は[公式](https://github.com/Crinsane/LaravelShoppingcart)を参照してほしい。
いずれも直感的なので、注意するとすれば```Cart::subtotal()```と```Cart::total()```の使い分けくらいだろうか。
(前者は税別価格、後者は税込価格)

```Cart::search()``` の仕様については公式を確認してほしい。

```php
//カートの破棄
Cart::destroy()

//商品合計額 + 税額の計算
Cart::total()

//税額の計算
Cart::tax()

//商品合計額の計算
Cart::subtotal()

//商品合計数の計算
Cart::count()

//商品の検索
Cart::search($function)
```

## Viewの処理
```Cart::content()``` をコントローラーから渡して、Bladeではforeachを使って回せばよい。
また ```->model``` メソッドを通すことで、関連付けたEloquentモデルにアクセスすることができる。

```php:hogeCart.blade.php(例)

@foreach($contents as $content)

    商品名：{{$content->name}}
    個数：{{$content->qty}}
    商品説明：{{$content->model->hoge_description}}

    <form>
    <input type="hidden" value="{{$content->rowId}}">
        //個数変更、削除処理など
    </form>

@endforeach

```

# おわりに
紹介していない機能として、複数のカートを用意したり、
カートの操作に応じてイベントを受信することができるらしい。

おおむねReadme.mdを読めば問題なく実装できるし、issuesが半ばサポート掲示板のようになっているので、
ハマったら適当なワードで検索するとだいたい解決できる。

# 参考URL
[公式GitHub](https://github.com/Crinsane/LaravelShoppingcart)
[端くれプログラマの備忘録 2016/06/09](http://www.84kure.com/blog/2016/06/09/laravel-%E3%82%B7%E3%83%A7%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0%E3%82%AB%E3%83%BC%E3%83%88/)