EC-CUBE4でトップページ等以外はログインを必須にする簡易的な会員制サイトを作る方法

EC-CUBE Advent Calendar 2020 22日目の記事です。

お客さんの要望で会員制のクローズドサイトを作成したいという要望が時々あります。

クローズドサイトといっても完全にクローズドにするのか、トップページと会員登録だけ公開しておくのか、専用IDを別途発行して対応するのかなど色々とあります。

今回は、トップページと会員登録だけを公開した会員制サイトのカスタマイズを紹介します。

ログインが必要となる処理の設定

ログインを必須とするのは、EccubeExtensionクラスに定義を追加するだけで対応可能です。EccubeExtensionクラスは同名のものがあるのでパスを確認するようにしてください。

  • src/Eccube/DependencyInjection/EccubeExtension.php
// SSL強制時は, httpsのみにアクセス制限する
$accessControl = [
  ['path' => '^/%eccube_admin_route%/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/%eccube_admin_route%/', 'roles' => 'ROLE_ADMIN'],
  ['path' => '^/mypage/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/mypage/withdraw_complete', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/mypage/change', 'roles' => 'IS_AUTHENTICATED_FULLY'],
  ['path' => '^/mypage/', 'roles' => 'ROLE_USER'],
];

ここの定義にログイン必須にするための処理を追加します。

// SSL強制時は, httpsのみにアクセス制限する
$accessControl = [
  ['path' => '^/%eccube_admin_route%/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/%eccube_admin_route%/', 'roles' => 'ROLE_ADMIN'],
  ['path' => '^/mypage/login', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/mypage/withdraw_complete', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'],
  ['path' => '^/mypage/change', 'roles' => 'IS_AUTHENTICATED_FULLY'],
  ['path' => '^/mypage/', 'roles' => 'ROLE_USER'],
  // 定義追加
  ['path' => '^/$', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'], // トップページはログイン不要
  ['path' => '^/entry', 'roles' => 'IS_AUTHENTICATED_ANONYMOUSLY'], // 会員登録ページはログイン不要
  ['path' => '^/', 'roles' => 'ROLE_USER'], // 全ページログイン必須
];

この処理を追加後、トップページと会員登録ページ以外にアクセスしてログイン画面が表示されれば設定完了です。

特定商取引やプライバシーポリシーなども除外する場合、上記に定義を追加するだけです。

パスの部分はURLを設定する様にしてください。

権限について

EC-CUBEではログインを行うのに権限が存在しており、

  • IS_AUTHENTICATED_ANONYMOUSLY : ログインなしでのアクセス可
  • IS_AUTHENTICATED_FULLY : 会員ログインが必要
  • ROLE_USER : 会員ログインが必要
  • ROLE_ADMIN : 管理者ログインが必要

というようになっています。先ほど設定したIS_AUTHENTICATED_ANONYMOUSLYなどは権限のことを表しています。

ROLE_USERIS_AUTHENTICATED_FULLYの違いですが、ログイン時に自動ログイン(REMEMBERME)にチェックをいれてログインしている時に動作が異なります。

  • ROLE_USER : 自動ログイン済の場合はログイン不要
  • IS_AUTHENTICATED_FULLY : 自動ログインされていてもログインが必要

という動作になります。EC-CUBEでは会員情報変更時のこの権限を利用しています。

以上で簡単に会員サイトを作る仕組みを用意しましたが、このままであれば会員登録されると誰でも見れるサイトになってしまいますので、会員登録された場合、管理画面側で本登録をさせるというカスタマイズを行えばよりクローズドなサイトが出来上がります。

その方法は後日説明します。

EC-CUBE4でCSVファイル出力時に数値項目へ'.00'を付与させない方法

EC-CUBE Advent Calendar 2020 20日目の記事です。

EC-CUBE4で注文CSVダウンロードした時に数値項目(金額など)に.00が付与されてダウンロードされます。

国際化対応されているので小数点以下が付与されても別に気にしなくても良いのですが、偶に外部連携時に不要なことがあります。

今回は付与しない方法の説明です。

CsvExportServiceの変更

今回は一部の箇所を変更するのみです。

  • src/Eccube/Service/CsvExportService.php
/**
 * CSV出力項目と比較し, 合致するデータを返す.
 *
 * @param \Eccube\Entity\Csv $Csv
 * @param $entity
 *
 * @return string|null
 */
public function getData(Csv $Csv, $entity)
{
    // エンティティ名が一致するかどうかチェック.
    $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
    $entityName = ClassUtils::getClass($entity);
    if ($csvEntityName !== $entityName) {
        return null;
    }

    // カラム名がエンティティに存在するかどうかをチェック.
    if (!$entity->offsetExists($Csv->getFieldName())) {
        return null;
    }

    // データを取得.
    $data = $entity->offsetGet($Csv->getFieldName());

    // one to one の場合は, dtb_csv.reference_field_name, 合致する結果を取得する.
    if ($data instanceof \Eccube\Entity\AbstractEntity) {
        if (EntityUtil::isNotEmpty($data)) {
            return $data->offsetGet($Csv->getReferenceFieldName());
        }
    } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
        // one to manyの場合は, カンマ区切りに変換する.
        $array = [];
        foreach ($data as $elem) {
            if (EntityUtil::isNotEmpty($elem)) {
                $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
            }
        }

        return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
    } elseif ($data instanceof \DateTime) {
        // datetimeの場合は文字列に変換する.
        return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
    } else {
        // スカラ値の場合はそのまま.
        return $data;
    }

    return null;
}

となっています、がそれを

/**
 * CSV出力項目と比較し, 合致するデータを返す.
 *
 * @param \Eccube\Entity\Csv $Csv
 * @param $entity
 *
 * @return string|null
 */
public function getData(Csv $Csv, $entity)
{
    // エンティティ名が一致するかどうかチェック.
    $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
    $entityName = ClassUtils::getClass($entity);
    if ($csvEntityName !== $entityName) {
        return null;
    }

    // カラム名がエンティティに存在するかどうかをチェック.
    if (!$entity->offsetExists($Csv->getFieldName())) {
        return null;
    }

    // データを取得.
    $data = $entity->offsetGet($Csv->getFieldName());

    // one to one の場合は, dtb_csv.reference_field_name, 合致する結果を取得する.
    if ($data instanceof \Eccube\Entity\AbstractEntity) {
        if (EntityUtil::isNotEmpty($data)) {
            return $data->offsetGet($Csv->getReferenceFieldName());
        }
    } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
        // one to manyの場合は, カンマ区切りに変換する.
        $array = [];
        foreach ($data as $elem) {
            if (EntityUtil::isNotEmpty($elem)) {
                $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
            }
        }

        return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
    } elseif ($data instanceof \DateTime) {
        // datetimeの場合は文字列に変換する.
        return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
    } else {
        // スカラ値の場合はそのまま.
        if (is_string($data)) {
            $data = preg_replace('/\.0+$/', '', $data);
        }
        return $data;
    }

    return null;
}

に変更するだけで対応可能です。

変更箇所は

// スカラ値の場合はそのまま.
if (is_string($data)) {
    $data = preg_replace('/\.0+$/', '', $data);
}

になります。

特に対応する箇所でもないのですが、必要な方はこの記述を追加してください。

EC-CUBE4でポイント履歴を作成する方法

EC-CUBE Advent Calendar 2020 19日目の記事です。

EC-CUBE4ではEC-CUBE3系で無くなったポイント機能が標準で搭載されています。

このポイント機能ですが、ポイント利用とポイント付与しかなくポイント履歴機能は存在しません。

時々お客さんによってはポイント履歴が欲しいと言われることがありますので、今回はポイント履歴を作成します。

今回の変更は複雑な箇所も多いため慣れていない方はお気をつけください。

会員登録時と商品レビュー公開時にも自動ポイント付与及びポイント履歴として表示させるようにカスタマイズも可能ですが今回は省きます。

続きを読む

EC-CUBE4でメールアドレスではなく任意のユーザー名でログインする方法

EC-CUBE Advent Calendar 2020 17日目の記事です。

時々お客さんからの要望で、メールアドレスだけではなく任意のユーザー名でログインさせたいという要望があります。 もっと詰めていくと、会員登録時には「任意のユーザー名」「メールアドレス」「パスワード」だけで登録させたいというものまであります。

その場合、住所はどのタイミングで入力させるのかというと購入画面で入力させるようにすれば良いということですが、購入画面で購入者情報と配送情報を入力させる方法は別の機会に説明します。

今回は会員登録画面を「ユーザー名」「メールアドレス」「パスワード」だけの項目にし、ユーザー名でもログインできる方法を説明します。

続きを読む

EC-CUBE4とWordPressを連携する方法

EC-CUBE Advent Calendar 2020 15日目の記事です。

EC-CUBE4でWordPressの記事を取得する方法を先日書きました。

EC-CUBE4でWordPressの投稿記事を簡単に出力する方法 - AmidaikeBlog

今回は記事を取得するのではなく、WordPressからEC-CUBE4の関数やEC-CUBE4からWordPressの関数を利用できる方法を説明します。

ちなみにEC-CUBE2系はこちらの記事を参考にしてください。

qiita.com

今回は前回とは異なり、EC-CUBE4とWordPressは同階層にインストールするようにします。

というように、同一ドメイン、同階層でEC-CUBE4とWordPressが動作されている事を想定しています。

続きを読む

EC-CUBE4でお問い合わせ内容をDBへ保存する方法

EC-CUBE Advent Calendar 2020 11日目の記事です。

EC-CUBE4のお問い合わせフォームの内容は標準ではメールアドレスしか送られません。

ただ、お客様によっては時々お問い合わせフォームの内容をDBへ保存しておきたいという方がいます。

今回はお問い合わせフォームの内容をDBへ保存する方法を説明します。

続きを読む

EC-CUBE4でParsleyを利用したリアルタイムバリデーションの実装方法

EC-CUBE Advent Calendar 2020 8日目の記事です。

EC-CUBE4でフォーム画面の入力チェックはサーバ側のチェックで行っている画面と、HTML5のrequired属性を設定して入力チェックを行っている画面の2パターン存在しています。

サーバ側で入力チェックが必須なのは当然ですが、項目のフォーカスアウト時にリアルタイムバリデーションを行うように使い勝手をもう少し良くするために、入力チェックライブラリであるParsleyを利用します。

parsleyjs.org

利用方法はサイトを見れば一目瞭然なのですが、EC-CUBE4で利用する方法を説明します。

Parsleyのダウンロード、配置

Parsley - Download the pieces

こちらよりparsley.zipファイルをダウンロードします。
parsley.zipリンクを押すとGitHubの画面へ遷移するのでSource code (zip)をダウンロード後解凍し、distディレクトリにあるi18nディレクトリとparsley.min.jsを下記のディレクトリへ配置します。

html/template/default/assets/js

Parsleyの利用方法

会員登録入力画面を参考にParsleyを設定してみます。

src/Eccube/Resource/template/default/Entry/index.twig

ファイルを開き、以下の内容をを追記します。

{% block javascript %}
    <script src="//yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
{% endblock javascript %}{% block javascript %}
    <script src="//yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
    <script src="{{ asset('assets/js/parsley.min.js') }}"></script>
    <script src="{{ asset('assets/js/i18n/ja.js') }}"></script>
    <script>
        $(function() {
            Parsley.options.trigger = 'keyup focusout change input';

            $('#form1').parsley({
                classHandler: function(ParsleyField) {
                    return ParsleyField.$element;
                },
                errorsWrapper: '<p class="ec-errorMessage"></p>',
                errorTemplate: '<span></span>'
            }).on('field:validated', function() {
                var ok = $('.parsley-error').length === 0;
                if (!ok) {
                    $('.bg-load-overlay').remove();
                    if (this.$element.attr('required')) {
                        if (this.$element.hasClass('parsley-success')) {
                            this.$element.parent('div').removeClass('error');
                        } else {
                            this.$element.parent('div').addClass('error');
                        }
                    }
                }
            });
        });
    </script>
{% endblock javascript %}
Parsley.options.trigger = 'keyup focusout change input';

という箇所は、エラーチェックを行うタイミングを指定していますので、不要な方は削除してください。

次に、formタグにid属性を付与します。

<form method="post" action="{{ url('entry') }}" novalidate class="h-adr"><form id="form1" method="post" action="{{ url('entry') }}" novalidate class="h-adr">

この設定を行う事で、フォーカスアウト時にリアルタイムバリデーションを行ってくれるようになります。

一部デザイン崩れを起こす箇所もありますが、そこは適宜修正してください。

また、独自にデザインを作成している方は、parsleyに記載されている内容をデザインに合わせて修正してください。

Bootstrap4を利用してフォーム画面を作成されている方は以下の内容を適用する事でエラー箇所がキレイに表示されます。

$('#form1').parsley({
    errorClass: 'is-invalid',
    successClass: 'is-valid',
    classHandler: function(ParsleyField) {
        return ParsleyField.$element;
    },
    errorsWrapper: '<div class="invalid-feedback"></div>',
    errorTemplate: '<div></div>'
}).on('field:validated', function() {
    var ok = $('.is-invalid').length === 0;
    if (!ok) {
        $('.bg-load-overlay').remove();
    }
});

今回は必須入力のみのチェックを行なっていますが、他にも電話番号やメールアドレス等の入力チェックもありますので詳しくはParsleyのドキュメントをご覧ください。