EC-CUBE4.2.3で会員用価格を使用する


# price01を会員価格として扱いたい

#### 環境
さくらのレンタルサーバー、クイックインストールの4.2.0をアップデートプラグインにて4.2.3にアップデート済み

#### インストール済みプラグイン
・公式のアップデートプラグイン各種
・EC-CUBEペイメントPlus決済プラグイン(4.2系/4.3系)


#### 概要
price01を会員価格用フィールドとして扱えるようにするため
price02を読み込む全てのサービスでログイン状態の確認をして
ログイン済みかつprice01に値がセットされていればprice01をprice02の代わりに読み込むように改造していきます。
(price01は使わずに、エンティティ拡張で新しいフィールドを追加してもよいです。)

:::note warn
この記事では本体のソースコードを直接編集していきますが、
本体アップデート時に上書きされてしまったり、
他プラグインの挙動に影響する可能性がありますのでお気をつけください。
本体バックアップを行った上でテスト環境にてお試しください。
:::

## デフォルトの価格用フィールド

デフォルトで用意されている価格用フィールドは、src/Eccuce/Entity/ProductClass.phpの
price01、price01IncTax
price02、price02IncTaxです。
price01はprice02がキャンペーン価格などの場合に通常価格と販売価格の比較用にのみ使用され、実際の決済時には参照されません。
しかしメソッドの構造や値の変更タイミングは01、02で完全に同じなので
price01を会員価格用フィールドとして扱うことにします。

## price02がいつ参照されるのか調べる

ログイン済みの場合にprice02の代わりにprice01を読んで欲しいので
まずはいつどのタイミングでgetPrice02()、getPrice02IncTax()が呼ばれているか調べます。

EC-CUBEのルートにてgrepコマンドで全てのディレクトリを検索します

```bash
grep getPrice02 -rl ./
```
実行するとたくさんヒットしますが編集するのは以下のファイルです。

./app/template/default/Product/detail.twig
./app/template/default/Product/list.twig
./src/Eccube/Service/PurchaseFlow/Processor/PriceChangeValidator.php
./src/Eccube/Service/CartService.php
./src/Eccube/Service/OrderHelper.php

## twigファイルの編集

twigファイル内では{% if is_granted('ROLE_USER') %}でログイン状態を確認できます。
オリジナルのコードを参考にしつつ、ログイン状態によって表示が切り替わるようにします。
```twig
{% if is_granted('ROLE_USER') and Product.getPrice01Min is not null %}
    {# ログイン済みかつ会員価格の登録された商品 #}
{% else %}
    {# 未ログインもしくは会員価格が登録されていない商品 #}
{% endif %}
```

先ほどの検索結果には載りませんが、/app/template/default/Mypage/history.twigでも、price02が読まれています。マイページのtwigなのでログインチェックせずにprice01を参照するように変えておきます。


## サービスの編集

CartService.phpとOrderHelper.php内ではもともとログイン状態を確認するためにgetUser()が定義されているので流用します。
それぞれのコード内でgetPrice02()、getPrice02IncTax()が呼ばれているところを検索してその直前にログインチェックを行うようにします。
```php
if ($this->getUser() && $ProductClass->getPrice01()) {
    $switchPrice = $ProductClass->getPrice01();
}else{
    $switchPrice = $ProductClass->getPrice02();
}
```

最後にPriceChangeValidator.phpですがgetUser()が定義されていないのでCartServiceを参考に実装していきます。
```php
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;


/**
 * 販売価格の変更検知.
 */
class PriceChangeValidator extends ItemValidator
{


    /**
     * PriceChangeValidator constructor.
     */
    public function __construct(
        SessionInterface $session,
        TokenStorageInterface $tokenStorage
    ) {
        $this->session = $session;
        $this->tokenStorage = $tokenStorage;
    }


    protected function getUser()
    {
        if (null === $token = $this->tokenStorage->getToken()) {
            return;
        }

        if (!is_object($user = $token->getUser())) {
            // e.g. anonymous authentication
            return;
        }

        return $user;
    }

    //以下略
    
```

サービスのソースコードを変更しただけではセッションの情報を受け取れないので/app/config/eccube/services.yamlに追記します。
サービスのコンストラクタ引数\\$sesson, \\$tokenStorageに渡すオブジェクトを書きます。
```yaml
services:

#中略

    Eccube\Service\PurchaseFlow\Processor\PriceChangeValidator:
            arguments:
                $session: '@session'
                $tokenStorage: '@security.token_storage'
```

最後にキャッシュクリアをして決済まで問題なく進めるか動作確認して終了です。
EC-CUBEペイメントPlus決済プラグイン(4.2系/4.3系)の場合、クレジットカード決済も問題なく通り、ログイン時の購入分は会員用価格にて請求されるのを確認できました。