Blog

ブログ

AWSマルチアカウント戦略でシンプル&セキュアな運用へ

はじめに

弊社では長らく、社内サービスを 単一の AWS アカウント に集約して運用してきました。サービス数自体は多くないものの、運用メンバーが増えるにつれて権限の境界が曖昧 となり、「誰がどこまで操作できるのか」を把握しづらい状況に陥っていました。

この課題を解決するため、AWS Organizations を活用した マルチアカウント戦略 を導入し、環境・責務ごとにアカウントを分離する取り組みを開始。本記事では、その背景と具体的なアプローチ、そして得られたメリットを紹介します。

現状の課題

  • 管理アカウントALB5 台の EC2 が混在

 

  • 管理アカウントに IAM ユーザーが集中しており、各メンバーに必要以上の権限が与えられている状況が多く、最小権限の原則を実践しにくい
  • 単一アカウントではコストの内訳が分かりにくい
    • コスト配分タグを使ってある程度の集計は行っていましたが、集計や可視化の観点ではやや見づらく、タグ運用も属人化しやすい課題がありました。

 

マルチアカウント構成とは

AWS Organizations を用いて 環境(開発・本番)や目的(ネットワーク・共有サービス)ごとにアカウントを分割 し、ガバナンスを効かせつつスケーラブルに拡張していく方法です。アカウントはそれぞれがセキュリティ境界となり、権限・課金・ログなどを独立して管理できます。

期待するメリット

1. 環境ごとの権限分離

アカウント単位で IAM ロールを限定できるため、操作ミスなどにより特定のサービスが停止するリスクを軽減できます。サービスごとにアカウントを分けることで、影響範囲を明確に分離し、安定した運用が可能になります。

2. コストの可視化と予算管理

コスト配分タグでもある程度の可視化は可能でしたが、マルチアカウント構成によりアカウントごとの使用量が分けて見られるようになり、より直感的かつ明確にサービスごとのコストを把握できるようになります。請求自体は管理アカウントに集約されるものの、各アカウントの使用状況が明確になることで、予算アラートの設定や異常検知にも役立ちます。

対応: ネットワークアカウントとサービスアカウントを分離

ルーティングを担うALB をネットワークアカウントに配置し、そこから別アカウントに移行した EC2 インスタンスへトラフィックを転送する構成とします。
本記事では、実際にHPインスタンスを別アカウントに移行したのでその手順を記載します。

大まかな移行ステップ

  1. 新規AWSアカウント作成、作成したAWSアカウントでVPC作成(この記事では割愛)
  2. ネットワーク接続
    • 管理アカウントの VPC ↔ 移行先 VPC を VPC ピアリングで接続。
    • RAMを使用してセキュリティグループを共有し、ALB からのトラフィックを許可。
  3. AMIを使用し、EC2を移行
    • AMI化し、構成を変更せずそのまま移行する想定
    • 共有機能で別アカウントで使用できるようにする
    • ※ 本構成のEC2は、MySQL をインスタンス内に直接構築しているため、AMI により構成をそのまま保持した移行が可能でした。
  4. ルーティング調整
    1. 新EC2へ接続するターゲットグループを作成。
      1. 別アカウントのEC2は参照できないため、IPアドレスでターゲットグループを設置する
    2. ALBのターゲットグループを差し替える。

 

ネットワーク接続

VPC ピアリングの手順

1. 移行元アカウントでVPC > ピアリング接続からピアリング接続を作成をクリック

2. VPC ID(リクエスト元)は接続元VPCのID、VPC ID(アクセプタ)は接続先VPCのIDをそれぞれ入力
今回のケースでは、アクセプタ側が別アカウントのため、アカウントID(アクセプタ)には接続先のアカウントIDを、VPC ID(アクセプタ)には移行先VPCのIDを入力

3. 移行先アカウントでVPC > ピアリング接続を表示するとリソースができているので、「リクエストを承諾」をクリック

4. それぞれのVPCでルーティングできるよう、ルートテーブルに設定を追加

 

RAMを使用し、移行先のアカウントにセキュリティグループを参照できるようにする

1. ALBが存在するアカウントでResource Access Manager > 自分が共有で、リソース共有を作成をクリック

2. ALBのセキュリティグループを共有する

AMIを使用し、EC2を移行

1. EC2のコンソール > インスタンスの状態 > イメージとテンプレート >イメージを作成から、AMIを作成する

2.イメージ名を入力し、「イメージを作成」を選択する

※本番稼働しているインスタンスの場合、「インスタンスを再起動」には要注意。チェックを入れていると、インスタンスが再起動されてしまいます。

3. EC2 > AMIから、作成したAMIを移行先のアカウントへ共有

4. 移行先のアカウントでEC2 > AMIから、「AMIからインスタンスを起動」をクリックで起動

5. EC2のセキュリティグループ > インバウンドルールは、RAMで共有したALBのセキュリティグループを紐づける
※この時、カスタムルール内のプルダウン内にはALBのセキュリティグループは存在しないと思うので、セキュリティグループIDで直接入力する

ルーティング調整

1. EC2 > ターゲットグループから、ターゲットグループの作成をクリック

2. 他アカウントのEC2は直接参照できないので、グループの詳細の指定は「IPアドレス」を選択

3. 「その他のプライベートアドレス」を選択し、移行先のEC2インスタンスのプライベートIPアドレスを入力し、ターゲットグループを作成

4. ALBのターゲットグループを差し替えて、画面が表示されれば完了

 

終わりに

単一アカウント運用からマルチアカウント構成への移行は、セキュリティや運用の観点から重要な一歩でした。特に、IAMの権限分離やコストの明確化といった課題は、アカウントを分割することでシンプルかつ直感的に解決できることが実感できました。

今回のように、ALBをネットワークアカウントに残したまま、EC2をサービスアカウントへ移行することで、既存構成を大きく変更せずにスムーズな切り出しが可能です。

今後も、サービス単位や環境単位でのアカウント分離をさらに進めることで、よりガバナンスが効いた、安全かつスケーラブルなクラウド環境を構築していきたいと考えています。

本記事が、同様の課題を抱える方々の参考になれば幸いです。今後も運用で得られた知見を積極的に共有していきますので、ご期待ください。

SEO観点における動的ページURLの静的化について調べてみた

動的ページURLの静的化とは?

ここでは以下のように、動的なページ(例:検索結果などの属性を使った絞り込み条件を含んだURL)のURLを、?を含むクエリパラメータを使わずにスラッシュで全て表現する方法のことを指します。
動的ページURL:https://www.example.com/list/?pets=cats 
静的ページURL:https://www.example.com/pets/cats/

ときどき、SEO改善を目的として上記のような施策を耳にするのですが、他のSEO施策に比べると大がかりな内容なので、「どのような効果があるのか?」というのが気になったので調べてみました。

URLを静的化するメリット

公式ドキュメントでは「類似トピックのページをディレクトリにまとめる」という項の中で説明されていました

類似トピックのページをディレクトリにまとめる

「特にディレクトリ(フォルダ)を使って類似のトピックをまとめていると、各ディレクトリ内の URL が変更される頻度を Google が学習しやすくなります。」(引用)

変更の頻度を学習する???と思っていると、より具体的な例も記載されていました。

「policiesディレクトリ内のコンテンツはめったに変更されませんが、promotionsディレクトリ内のコンテンツはかなり高い頻度で変更されます。Googleはこの情報を学習することで、ディレクトリごとのクロール頻度を変えています」(引用)

確かにサイトポリシーなど変更頻度が低いページと最新プロモーションが頻繁に更新されるページが規則性なくバラバラに配置されているとクロールする方は大変ですね。
公式でも「Googlebotが1つのサイトをクロールできる時間には限界があります※1」と明言されている通り、Googlebotは必ずしもクロールしてくれるわけではないので、特に商品の数だけページが量産されるECサイトは、重要度の高いページが優先してクロールされるよう設計することが重要でしょう。
※1:クロールの一般論より

ここまで読んできて関連コンテンツは同じディレクトリに格納する方が良いというのは分かりました。

しかし、今回焦点を当てているのは動的ページURLで、これらは通常、日々更新されるものなので、
クロールの更新頻度は全て頻繁に来てほしい対象ではないでしょうか?と新たな疑問が浮かびました。

ということでもう少し見てみると、動的URLについては「ファセットナビゲーションURLのクロール管理」という項で説明されていました。ファセットナビゲーションURLのクロール管理

動的URLのベストプラクティス

ここで動的URLと呼んでいたものは、上記ページではファセットナビゲーションと呼称されています。
このページでは「ファセットナビゲーションの最適化方法」がいくつか紹介されていますが、
とりわけ「ファセットナビゲーションのベストプラクティス」と、あるべき姿が名言されています。

  • 業界標準のURLパラメータの区切り文字「&」を使用してください。(太字)
  • /products/fish/green/tinyのようにURLパスでフィルタをエンコードする場合は、フィルタの論理的な順序が常に同じであり、重複するフィルタが存在しないことを確認してください。
  • フィルタの組み合わせで結果が返されない場合は、HTTP404のステータスコードを返します。(太字)

ここでは、いのいちばん、それも太字で強調した上で&(?を使う前提)を使った通常のクエリパラメータが推奨されています。静的化したURLについても言及されていますが、太字の強調もないですし、なにより「その場合はこれに注意して」という注意点だけで推奨されていません。

色々と注意点は記載されているようですが、公式ドキュメントでは動的URLが推奨されていました。

ではなぜ公式ドキュメントではクエリパラメータが推奨されている一方で「動的ページURLの静的化すべき」という声も根強いのでしょうか。

動的URLもきちんとクロールされるようになってきた

次のサイトには「昔の検索エンジンはクエリパラメータの読み取りができず、2008年に識別できるようになった」という記載があります。

動的ページはSEOに不利?概要や静的ページとの違いを解説

また、次のGoogleの公式ブログ記事「DynamicURLsvs.staticURLs」も2008年に公開されたものなのですが、こちらでは「動的なURLはクロールできない=誤解である」と記載があり、静的URLへの変更も推奨されていません。

DynamicURLsvs.staticURLs

このことから2008年を起点にクエリパラメータのクロールは徐々に改善されてきている、と考えられます。最近の「静的URL VS 動的URL」関連の記事を読むと、SEO専門のページでも「静的URL/動的URL、どちらでも良い」という記事が多いように思えますので、あくまで個人の予想ではありますが、「静的URL=SEOに有利」というのは過去の名残なのではないかと考えられます。

※「2008年を起点に改善」と記載しましたが、2010年代の記事では、静的URLにした結果改善されたというのも目にするため、即時100%改善された、というよりは徐々に改善されてきて、最近「静的URL/動的URL、どちらでも良い」といえる状況になったのでは、と思われます。

今回は動的URLの静的化をSEOの観点で見ていきました。
ここでの結論としては静的URLは特に推奨されていない、としていますが、動的URLを採用するにしても、クローラーのリソースを食いつぶさないよう、SEO的は工夫が必要になります。また、URLが短くシンプルな静的化されたURLは、拡散する際にユーザーフレンドリーであるなど、別視点でもメリットはありますので、目的によっては採用する必要もあるかと思います。
それでも個人的には(条件の数にもよりますが)URLを静的化するよりは、動的URLのまま工夫をする方が実装的には現実的かと思います。どちらを採用するにせよ、動的URLはECサイトでは重要なページに位置付けられますので、きちんと設計する必要がありますね。
また気になることがあればまとめていきたいと思います。

 

Eccube4.3にXdebugいれてみた(PhpStorm/WLS2/Docker)

PHPでデバックするときに一番手っ取り早いのはver_dump関数ですが、見たい内容を毎回記述する必要があったり、画面表示しない処理(CSVダウンロードなど)だとデバックしにくい面もあります。

 

そこでXdebugです。
公式:https://xdebug.org/

IDEでブレークポイントをつけた箇所で処理が止まってくれて、変数の中身などを確認することが出来ます。 例えば次の画像のように$idの内容が確認できます。

 xdebugの仕組みの概要は以下です。

  1. IDEは特定のportでWebサーバーにインストールされたXdebugからの通信を待機する
  2. Xdebugは特定のportにコールバックする
  3. デバックセッションを開始して、DBGPプロトコル(デバッグ用の特別なプロトコル)を介してデータを転送

IDEによってWebサーバーが「呼び出される」のかと思っていましたが、実際は逆で Xdebug(Webサーバー)がIDE に接続しに行くようです。

この辺りは以下の動画が分かりやすかったので、気になる方はご視聴をお勧めします。
#03 – PHP Advanced Debugging With Xdebug- How Xdebug Works

とても便利なのですが、設定が少しややこしいので、今回は現時点で最新のEccube4.3をローカルに構築して、Xdebugの導入してみました!

手順1:ローカルにEccube4.3環境を立ち上げる

まずはEccubeのコードを用意します。
EccubeはOSS(オープンソースソフトウェア)で、以下のGitHubから取得できます。


https://github.com/EC-CUBE/ec-cube

コードを適当なディレクトリの配置後、初回インストールを実施するのですが、今回はXdebugの起動を確認すれば良いだけなので、初回インストール状態を残すべく、以下の変更を加えます

docker-compose.yml
volumes:
  html-app:  # ← ソースコードが含まれるボリューム(初回インストール後も残す)

services:
  ec-cube:
    volumes:
      - html-app:/var/www/html

この状態で初回インストールを行います。
参考:Docker Composeを使用してインストールする


#初回インストールコマンド
# コンテナの起動 (初回のみビルド処理あり)
docker-compose up -d

# 初回はインストールスクリプトを実行
docker-compose exec -u www-data ec-cube bin/console eccube:install -n

ローカルにアクセスできたらOK。
http://localhost:8080/

手順2:Xdeugをインストールする

ルート直下にあるDockerfile、docker-compose.yamlを変更します。

1.Dockerfileの修正
PECLでインストールします。以下を追記します。

RUN pecl install xdebug \
    && docker-php-ext-enable xdebug ## 追記

以下をコメントアウトします。(2度目立ち上げ時に失敗してしまうのでコメントアウト)
#COPY dockerbuild/docker-php-entrypoint /usr/local/bin/

2.php.iniにxdebugの設定を追加
ビルド時に「dockerbuild/php.ini」のファイルをphp.iniに読み込んでいるので、ここに以下の設定を追記します。

[xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_port = 9003
xdebug.client_host = host.docker.internal
  • mode=debug:ステップデバッグが出来るようになります。 それ以外の値はこちら
  • start_with_request:いつデバッグを開始するかを指定する。yesを選択 それ以外の値はこちら
  • client_port:PhpStormのデバッグポートで指定する値を設定します。※後述
  • client_host:Xdebug接続するIP アドレスまたはホスト名

個人的にclient_hostが毎回ハマるポイントです。
Macでは上記の「host.docker.internal」で問題ないらしいのですが、 私の環境(WLS2)だとうまくいきませんでした。
※最近のバージョンではWLS2でも「host.docker.internal」で出来る、という記事もみたのですが、残念ながら私の環境では出来ませんでした。
色々試行錯誤した結果以下の値を設定することで成功しました。
・コマンドプロンプトや PowerShell でipconfigを実行した後の「イーサネット アダプター vEthernet (WSL):IPv4 アドレス 」の値
※ただしこの値は固定ではない(再起動などで変更される可能性がある)ので、他の方法が出来る場合は他の方法を採用した方が良いと思います。


> ipconfig
イーサネット アダプター vEthernet (WSL):
   IPv4 アドレス . . . . . . . . . . : 172.**.***.***

手順3:IDE(今回はPhpStorm)にXdebugの設定を行う

仕組みの概要で触れた通り、IDEはXdebugからの通信を待機して受け取る必要があるので、設定が必要です。

1.設定->PHP->サーバ でサーバーを追加する
プラスマークから追加します。
ここでは主にパスマッピングが重要です。
パスマッピングの設定によって「Xdebug 経由でやってくる“/var/www/html/はローカルではこのパスですよ」と伝えることが出来ます。

名前 : 何でも良い。
ホスト : localhostで設定しているがそれ以外の値でも成功する。
ポート : 80で設定しているがそれ以外の値でも成功する。
デバッガー : Xdebug を選択
パスマッピングを使用する : オンにして対応するパスを設定する

設定値を入れたら適用する

2.設定->PHP->デバッグ でXdebugの設定を確認する

デバッグポート: 9000、9003の2つがデフォルトで指定されていますが、これは
Xdebugのポートのデフォルトが、Xdebug2では9000だったのが、Xdebug3で9003に変更されたためのようです。
今回はPHP8でXdebug3になるので、9003のみにして、
あとは「外部接続を受け入れる」にチェックが入っていることを確認して、適用保存します。
※9000,9003の2つが設定されたままでも問題ありません。

3.実行 / デバッグ構成 を設定する
PhpStormヘッダ部に「現在のファイル」となっている部分をクリックすると
「実行構成の編集」というメニューが表示されるのでそれをクリック。
プラスマークから「PHPリモートデバッグ」を追加します。


名前に何でも良いので値を設定し、適用します。
※「IDEキーでデバッグ接続をフィルターする」にチェックを入れる記事が多いですが、今回はチェック無しで出来たのでOFFのまま進めます。

手順4:ビルドを実施して再度コンテナを立ち上げ

手順1で立ち上げた環境ですが、一度

  • docker-compose down で削除
  • docker build -t ec-cube –no-cache –pull –build-arg TAG=8.1-apache . でビルドして
  • docker tag ec-cube ghcr.io/ec-cube/ec-cube-php:8.1-apache でタグ付けし、
  • docker-compose up -d で再度立ち上げます。

ec-cube_1コンテナに入り、 php -v で表示される情報の中に「Xdebug」の文字があればインストールされています。

手順5:デバッグを実行

1.PhpStormのヘッダ部にある電話のようなマークをクリックしてリッスンを開始します。
2.PhpStormのヘッダ部にある虫のようなマークをクリックしてデバッグを開始します。
3.ステップさせたいところにブレークポイントを設定して、ブラウザからリクエストを実行。

ステップデバッグが出来るようになると、初回のダイアログが表示されます。

承認し、最初の画像のようにブレークポイントで停止してくれるようになれば設定完了です!

 

いかがだったでしょうか。
開発を助けてくれるXdebugですが、EccubeだけではなくてPHPであれば利用できますので、
PHPで開発されている方はローカル環境に入れてみてはいかがでしょうか。

※Xdebugはあくまで開発専用の機能なので、本番環境には絶対に入れてはいけません。

【Shopify】検索結果を商品のみ表示したい

Shopify標準では検索は、オンラインストア内で特定の商品、ページ、またはブログ記事を検索して見つけることができるようになっています。
しかし、そもそもブログ機能を使わなかったり、シンプルに商品だけ表示させたい、というケースも多いと思います。

liquid上で検索結果ページのproduct-cardを回している箇所を探し、
{% if item.object_type == ‘product’ %}と絞ることで、ブログ記事を除いた商品のみ表示させることは成功しました。
しかし、検索結果の表示件数には反映されませんでした。
これではユーザーが戸惑ってしまいますよね。

search.results_count や search.results はすべての検索対象(商品・ブログ記事・ページなど)を含んだ数を返すため、表示件数にもブログ記事がカウントされてしまうという問題が起きているようです。

そこで今回は、検索フォームのURLに type=product を加える方法を試してみます。
この方法では search.results_count や search.results に含まれるデータも商品だけになるので、「表示件数に反映されない問題」も解決します。
また、コードはシンプルで1行追加するだけ、フィルタ処理やループの条件は変わらないため、不要になれば元に戻すことも簡単です。

type=product を含める変更:

<input name="type" type="hidden" value="product" />

例:

<form class="search-form" action="/search" method="get">
 <input name="q" type="search" placeholder="検索ワードを入力"> 
 <input name="type" type="hidden" value="product"> 
 <button type="submit">検索</button>
</form>

これにより、検索結果ページに商品のみ表示されるようになり、同時に正確な検索結果件数になりました。
注意したい点は、既存リンクやシェアされたURLが type=product を含んでいないと効果がないため、他のページやバナーからのリンクが /search?q=〇〇 のままにならないよう、すべての検索導線で type=product を統一する必要があります。
メリット・デメリットを確認した上で参考にしてみてください。

 

type=product が使えるケース:
・商品以外の検索結果(記事やページ)が邪魔になっている
・ユーザーに商品だけを探してほしい(例:EC特化の店舗)
・商品数が多く、ブログやページはほとんど活用していない

避けた方がいいケース:
・ブログ記事や固定ページに重要なコンテンツが多い
・検索で商品以外のコンテンツ「ガイド」「配送方法」などを探す人が多い
・SEO対策でブログ記事がSEOや販促で活用されている

 

 

ジョーレン社員旅行2024

株式会社ジョーレン管理部のKanaです。

 

10月末の土日、今年も社員旅行へ行ってまいりました。

今回の行先は【日光・鬼怒川】方面です。

総勢15名の社員が集まりました。

普段はフルリモートで働くメンバーが多いジョーレンなので、
こんな感じで顔を合わせて交流できるイベントも定期的に実施しています

(もちろん参加は任意です)!

 

まずは北千住駅に集合し、昨年夏に運行開始した

大人気特急列車【Specia X】へ乗り

一同東武日光駅へ向かいました。

SpeciaXの社内はシートの座り心地も良く

カフェカウンター、ラウンジなどがありとても豪華でした。

 

午後からは大イベントが待っているので早めのランチ休憩です。

初日はお蕎麦屋【報徳庵】さんにて

ランチ前に近くの公園を散策してお腹を空かせました。

こだわりの地粉100%のそばは喉越しがよく

とても美味しくいただきました。

 

さてさて続きまして午後からはお待ちかねのアクティビティー

【鬼怒川ラフティング・ライン下り】

どちらか選択し2班に分かれアクティビティーを楽しみました。

 

まずは【ライン下り班】~

例年ならば紅葉真っ盛りのはずでしたが…

今年は暑さのせいか色好きもまばらでしたが、

少しひんやりした心地よい風にあおられながら

約30分の船旅を楽しみました。

 

 

続きまして【ラフティング班】~

10月末の日光、寒いかな…大丈夫かな…と心配しながら当日を迎えましたが

幸い天候にも恵まれブルブルすることも無く楽しめました。

出航前に全員で記念撮影

ボートから落ちそうな謎のポーズをさせられたり

全員で円を作りバタバタ運動

4メートルの崖からダイブ!

 

運動不足ぎみの一同は約2時間ちょっと身体を動かして一同へとへと…

素敵な温泉と美味しいお食事が待つ温泉旅館【界 鬼怒川】へと向かいます。

https://hoshinoresorts.com/ja/hotels/kaikinugawa/

大自然に囲まれたお宿ではゆったりと温泉に入り、

庭園を散歩したり各々自由な時間を過ごしました。

見た目も美しく美味しいお料理に一同舌鼓を打ちました。

―――――――――――――――――――――――――――――――――

2日目は【金谷ホテルランチ・日光東照宮】観光です。

 

まずは【金谷ホテル日光】にて100年カレーで腹ごしらえです。

日光金谷ホテルは現存する日本最古のリゾートホテルだそうです。

ホテル内はとても豪華な作りでゆったりとお食事を楽しめました。

お次は日光と言ったらここ!東照宮観光です。

言わずと知れた、あの徳川家康を祀る神社としても知られています。

東照宮といったら【見ざる、聞かざる、言わざる】

沢山の人がお猿さんの写真を撮っていました。

約2時間ほど東照宮をたっぷり堪能しました。

 

東照宮を観光した後は各々自由行動で日光の市内を楽しみました。

楽しいアクティビティ、美味しいお食事、美しい景色

一同日頃のストレスを発散し楽しんでまいりました。

 

普段なかなか交流のないメンバー同士も交流する良い機会となりました。

また来年も行けるよう日々の業務に励みたいと思います。

 

ジョーレンでは一緒に働いてくれるエンジニアを募集中です。

この記事を読んでいただいているあなたと次回はご一緒できると嬉しいです。

ご連絡お待ちしております。

最後までお読みいただきありがとうございました。

 

【ECCUBE】会員登録時のカナを自動入力にしたい

最近これ便利だなっていうjavascriptプラグインを見つけたので紹介したいと思います。
開発者が嬉しいというより使っていただくユーザさんに便利なプラグインです。
名前を入力する場合は大抵フリガナも入力する欄が設置されていると思いますが同じことを2回入力するのって地味にめんどくさいと思うんです。
そんな手間を少しでも楽にしたい時はぜひ使ってみてください。
ECCUBEのバージョンには依存しないので、2系〜4系どこでも使用できるかと思います。
※今回は4系に実装します

autokana

https://github.com/harisenbon/autokana

こちら日本語入力に対するフリガナを自動的に別フィールドに記入するJQueryプラグインになります。
注意点も少しあります。
・keydownで発火するためコピペなどでは使えません
・入力されている文字を読み取ってカナに変換しているわけではないのでタイポした場合はカナに文字が残ってしまう

ここからは設置方法を説明します。とっても簡単です。

まず↑のリンクから.jsをダウンロードしhtml/user_data/jsに設置

Twigファイルを修正

app/template/default/Entry/index.twig

<script src="{{ asset('assets/js/autokana-master/jquery.autoKana.js', 'user_data') }}"></script>

<script>
    $(function() {
        $.fn.autoKana('input[name="entry[name][name01]"] ', 'input[name="entry[kana][kana01]"]', {katakana:true});
        $.fn.autoKana('input[name="entry[name][name02]"] ', 'input[name="entry[kana][kana02]"]', {katakana:true});
    });
</script>

これだけです!

とってもかんたんですね♪

では実際に名前を入力してみましょう。

 

ちゃんとカナに入力されているのがわかりますね!

すぐできますのでぜひお試しください

【EC-CUBE4系】環境変数を設定する際にハマった話

EC-CUBE4 の Docker環境で環境変数を設定する際に、思わぬ壁にぶち当たりました。

services.yaml に記述されている設定内容を、環境ごとに分けるため、環境変数から取得するようにしたかったのです。
クレジット決済の3Dセキュアに関する設定なので、3D_SECURE_SETTING といった感じの名前で環境変数を登録し、設定として取得するようにしました。

docker-compose を使用する環境で環境変数を登録するには、docker-compose.dev.yml の environment に記述します。

services:
  ec-cube:
    environment:
      3D_SECURE_SETTING: "my_value"

環境変数を設定ファイル services.yaml で取得するには、’%env(環境変数名)%’ とします。

parameters:
  my_setting: '%env(3D_SECURE_SETTING)%'

以上で、コントローラー等で

$this->eccubeConfig['my_setting']

とすれば、”my_value”が読み取れるはず、が、以下のエラーが発生しました。

Environment variable not found: “3D_SECURE_SETTING”

何度も設定方法を確認し、コンテナの再起動とキャッシュクリアを繰り返すも虚しく時間がすぎるだけでしたが、ふと、「この変数名…?」と気づきました。
数字で始まる変数名は、多くのプログラミング言語で許可されていません。
また環境変数の命名規則も同様なようです。
PHPのコーディングをしている時はほぼ無意識的に避けて命名していたのですが、設定ファイル内でのこととあってか、頭から抜けていました。

英字から始まる環境変数名にすることで、無事取得できました!
イージーなミスですが、油断してるとハマりますね。

【ECCUBE4】eccubeでenumを使いたい!

eccubeでenumを使いたい!

ECcubeでは固定値などはMasterにレコードを追加して、
使いたい場合は都度DBからレコードを検索して使用しているかと思います。

ですがいちいちDBに接続&検索をして使うのは…という場合にこんなやり方もあります。
enumの追加&使用方法を簡単ですがご紹介したいと思います。

まず、Customize配下にEnumディレクトリを追加

下記のようなファイルを作成

<?php
namespace Customize\Enum;
/**
* 会員ランク
*/
enum CustomerRankType: string
{
  case ROOKIE = ‘1’;
  case BRONZE = ‘2’;
  case SILVER = ‘3’;
  case GOLD = ‘4’;
  case PLATINUM = ‘5’;
  case DIAMOND = ‘6’;
  case MASTER = ‘7’;
  public function getLabel(): string
  {
   return match ($this) {
     self::ROOKIE => ‘ルーキー’,
     self::BRONZE => ‘ブロンズ’,
     self::SILVER => ‘シルバー’,
     self::GOLD => ‘ゴールド’,
     self::PLATINUM => ‘プラチナム’,
     self::DIAMOND => ‘ダイアモンド’,
     self::MASTER => ‘マスター’,
    };
  }
  public static function getTypeList()
  {
   $allList = [];
   foreach (self::cases() as $item) {
     $allList[$item->getLabel()] = $item->value;
   }
   return $allList;
  }
}

使用方法ですが、例えばFormTypeで使用する場合は下記のようにすれば使用できます。

->add(‘customer_rank’, ChoiceType::class, [
‘required’ => false,
expanded’ => false,
‘multiple’ => false,
‘placeholder’ => ‘選択してください’,
‘choices’ => CustomerRankType::typeList(),
])

Twigにはこんな感じです

<div class=”row mb-2″>
  <div class=”col-3″>
    <span>{{ ‘会員スペシャルランク’|trans }}</span>
    <span class=”badge bg-primary ms-1″>{{ ‘admin.common.required’|trans }}</span>
  </div>
  <div class=”col”>
    <div class=”row”>
      <div class=”col”>
        {{ form_widget(form.customer_rank) }}
      </div>
    </div>
  </div>
</div>

こんな感じで表示することができました。

ぜひ機会があればですが、検討してみてください。

【Eccube3系】キャッシュクリアコマンドでプラグインのキャッシュが消えないお話

EccubeではtwigやDoctrieで使用されているキャッシュをクリアする方法が、大きく2つあります。

  1. 管理画面でキャッシュクリア
    • コンテンツ管理のキャッシュ管理 で削除対象をチェックしてクリア
  2. キャッシュクリアコマンドでクリア
    • 3系だと下記コマンドですね
      • php app/console cache:clear
      • ※このコマンドを実行する際は、適切なユーザーで行う必要があります

私の参画していた案件ではコードがデプロイされると自動的にキャッシュクリアコマンドが実行されたので、(2)の方法でキャッシュクリアをしていたことになるのですが、それだとPluginのキャッシュがクリアされませんでした。

ということでキャッシュクリアコマンドでPluginのキャッシュもクリアさせる方法です。

  • 参考
    • https://github.com/EC-CUBE/ec-cube3/blob/3.0/src/Eccube/Util/Cache.php
/src/Eccube/Util/Cache.php



public static function clear($app, $isAll, $isTwig = false)
{
    $cacheDir = $app['config']['root_dir'].'/app/cache';

    $filesystem = new Filesystem();
    if ($isAll) {
        $finder = Finder::create()->in($cacheDir)->notName('.gitkeep');
        $filesystem->remove($finder);
    } elseif ($isTwig) {
        if (is_dir($cacheDir.'/twig')) {
            $finder = Finder::create()->in($cacheDir.'/twig');
            $filesystem->remove($finder);
        }
    } else {
        if (is_dir($cacheDir.'/doctrine')) {
            $finder = Finder::create()->in($cacheDir.'/doctrine');
            $filesystem->remove($finder);
        }
        if (is_dir($cacheDir.'/profiler')) {
            $finder = Finder::create()->in($cacheDir.'/profiler');
            $filesystem->remove($finder);
        }
        if (is_dir($cacheDir.'/twig')) {
            $finder = Finder::create()->in($cacheDir.'/twig');
            $filesystem->remove($finder);
        }
        if (is_dir($cacheDir.'/translator')) {
            $finder = Finder::create()->in($cacheDir.'/translator');
            $filesystem->remove($finder);
        }
        // pluginディレクトリを対象に追加ここから
        if (is_dir($cacheDir . '/plugin')) {
            $finder = Finder::create()->in($cacheDir . '/plugin');
            $filesystem->remove($finder);
        }
        // pluginディレクトリを対象に追加ここまで

    }

    if (function_exists('opcache_reset')) {
        opcache_reset();
    }

    if (function_exists('apc_clear_cache')) {
        apc_clear_cache('user');
        apc_clear_cache();
    }

    if (function_exists('wincache_ucache_clear')) {
        wincache_ucache_clear();
    }

    return true;
}

カスタマイズ箇所は「pluginディレクトリを対象に追加ここから」「pluginディレクトリを対象に追加ここまで」とコメントしている間の4行のみです。(コメント含めると6行)

「キャッシュクリアコマンドで全てのキャッシュファイルは削除される」と思い込んでいましたが、デフォルトではPluginは対象外のようです。

ちなみに、--allをつけてphp app/console cache:clear --allで実行するとapp/cache配下全てがクリアされるので、Pluginのキャッシュファイルも削除されますが、これは稼働中のサーバでは実行してはいけません。
デフォルトではapp/cache配下にセッションファイルも格納しているためです。

cacheというディレクト名なので削除可能なファイルが置かれている印象を受けますが、実はセッションのようなファイルが入っている、特にカスタマイズしている場合はセッション以外にも削除不可なファイルが配置されている可能性もありますので、allオプションはよほど自信が無い限りは利用しないほうが良いと思います。

以上、「キャッシュクリアコマンドで全てのキャッシュファイルは削除されると思ったらプラグインは別だった」でした。

【ECCUBE4系】商品価格を税込みで登録したい場合のカスタマイズ

ECCUBEでは、商品の価格は税抜の本体価格を登録する仕様になっています。

しかし元々税込価格で管理していた場合、端数の処理を考慮しつつ税抜価格を計算して登録しなければなりません。

それならはじめから税込価格を登録したい、というケースで実施したカスタマイズ方法がこちらです。

内容としてはシンプルに、商品の税表示区分はすべて「税込」とし、外税額を求めるメソッドで必ず0を返すようにしてしまうというものです。(確認したECCUBEバージョンは4.2です。)

app/Customize/Service/OrderHelperExtension.php を作成し、OrderHelper の getTaxDisplayType を上書き宣言します

<?php

namespace Customize\Service;

use Eccube\Entity\Master\TaxDisplayType;

class OrderHelperExtension extends \Eccube\Service\OrderHelper
{
    /**
     * 税表示区分を取得する.
     * 価格を税込みで登録するため、常に"税込"を返す
     *
     * @param $OrderItemType
     *
     * @return TaxDisplayType
     */
    public function getTaxDisplayType($OrderItemType)
    {
        return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::INCLUDED);
    }
}

app/Customize/Service/TaxRuleServiceExtension.php を作成し、TaxRuleService の getTax を上書き宣言します

<?php

namespace Customize\Service;

class TaxRuleServiceExtension extends \Eccube\Service\TaxRuleService
{
    public function getTax($price, $product = null, $productClass = null, $pref = null, $country = null)
    {
        // 価格を税込みで登録するため、外税計算は常に0を返す
        return 0;
    }
}

app/Customize/Resource/config/services.yaml でサービスの上書きを設定します。

services:
  Customize\Service\OrderHelperExtension:
    autowire: true
    decorates: Eccube\Service\OrderHelper
  Customize\Service\TaxRuleServiceExtension:
    autowire: true
    decorates: Eccube\Service\TaxRuleService

以上で、商品に登録した価格を税込みとして扱うことができます。

【注意】プラグインや独自カスタマイズで、上記で上書きしたメソッドを使わずに税額・税込価格を計算している場合があります。動作確認を行い、適切な修正を施す必要があります。