カテゴリー
EC-CUBE

【EC-CUBE4】注文ステータス追加

[temp id=3]

コンビニ支払いのステータス追加

mtb_order_statusのid2が空いているので使用する

DB(テーブル)にデータ追加

  • mtb_order_status:入金待ち追加
  • mtb_order_status_color:入金待ちカラー追加
  • mtb_customer_order_status:入金待ち追加

OrderStatus(Entity)へ定数

今回は本体ソースに追加しているが、CustomizeでOrderStatusTraitを作成しても良い

定数「WAIT_PAYMENT」の追加

/**
 * OrderStatus
 *
 * @ORM\Table(name="mtb_order_status")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Entity(repositoryClass="Eccube\Repository\Master\OrderStatusRepository")
 * @ORM\Cache(usage="NONSTRICT_READ_WRITE")
 */
class OrderStatus extends \Eccube\Entity\Master\AbstractMasterEntity
{
    /** 新規受付. */
    const NEW = 1;
    /** 入金待ち. */
    const WAIT_PAYMENT = 2;
    /** 注文取消し. */
    const CANCEL = 3;
    /** 対応中. */

注文ステータス遷移設定

app/config/packages/order_state_machine.php

編集箇所抜粋

'places' => [
     (string) Status::NEW,
     (string) Status::WAITI_PAYMENT,
     (string) Status::CANCEL,
     (string) Status::IN_PROGRESS,
     (string) Status::DELIVERED,
     (string) Status::PAID,
     (string) Status::PENDING,
     (string) Status::PROCESSING,
     (string) Status::RETURNED,
     (string) Status::CANCEL_ENTRY,
     (string) Status::CANCEL_PROCESSING
 ],

入金待ちから変更できるステータスの追加

※複数の場合は「配列で渡す」

'transitions' => [
    'pay' => [
        'from' => (string) Status::NEW,
        'from' => [(string) Status::NEW, (string) Status::WAIT_PAYMENT],
        'to' => (string) Status::PAID,
    ],
    'packing' => [
        'from' => [(string) Status::NEW, (string) Status::PAID, (string) Status::CANCEL_ENTRY],
        'to' => (string) Status::IN_PROGRESS,
    ],
    'cancel' => [
        'from' => [(string) Status::NEW, (string) Status::IN_PROGRESS, (string) Status::PAID, (string) Status::CANCEL_PROCESSING],
        'to' => (string) Status::CANCEL,
    ],
    'back_to_in_progress' => [
        'from' => (string) Status::CANCEL,
        'to' => (string) Status::IN_PROGRESS,
    ],
    'ship' => [
        'from' => [(string) Status::NEW, (string) Status::PAID, (string) Status::IN_PROGRESS, (string) Status::CANCEL_ENTRY],
        'to' => [(string) Status::DELIVERED],
    ],
    'return' => [
        'from' => (string) Status::DELIVERED,
        'to' => (string) Status::RETURNED,
    ],
    'cancel_return' => [
        'from' => (string) Status::RETURNED,
        'to' => (string) Status::DELIVERED,
    ],
    'cancel_entry' => [
        'from' => [(string) Status::NEW, (string) Status::IN_PROGRESS, (string) Status::PAID, (string) Status::DELIVERED, (string) Status::CANCEL_PROCESSING, (string) Status::WAIT_PAYMENT],
        'to' => (string) Status::CANCEL_ENTRY,
    ],
    'cancel_processing' => [
        'from' => (string) Status::CANCEL_ENTRY,
        'to' => (string) Status::CANCEL_PROCESSING,
    ],
],

OrderStateMachineでステータス変更処理

キャンセルの場合は、在庫やポイントを戻してくれる

$this->orderStateMachine->apply($Order, $changeStatus);

OrderStateMachineでステータスの処理を追加

在庫を戻したり、ポイントの減算処理も追加できる

    public static function getSubscribedEvents()
    {
        return [
            'workflow.order.completed' => ['onCompleted'],
            'workflow.order.transition.pay' => ['updatePaymentDate'],
            'workflow.order.transition.cancel' => [['rollbackStock'], ['rollbackUsePoint']],
            'workflow.order.transition.back_to_in_progress' => [['commitStock'], ['commitUsePoint']],
            'workflow.order.transition.ship' => [['commitAddPoint']],
            'workflow.order.transition.return' => [['rollbackUsePoint'], ['rollbackAddPoint']],
            'workflow.order.transition.cancel_return' => [['commitUsePoint'], ['commitAddPoint']],
            // 処理が必要であればここで定義
            // 'workflow.order.transition.cancel_entry' => [],
            // 'workflow.order.transition.cancel_processing' => [],
        ];
    }
カテゴリー
EC-CUBE

【EC-CUBE4】エラーリスト

エラーの解決方法をメモする。

ローカル環境構築関連

WARNING [cache] Failed to save key

事象1:DockerでカスタマイズしたCommand実行で発生した

事象2:AWSとソニーペイメントプラグインを使用していて、cron実行で発生した

原因:AWSのELBを挟んだ場合、REMOTE_ADDRで正しいIPが取得できない

プロジェクト名/app/Plugin/SlnPayment4/Service/Utill.php

修正前ソース

    public function GetLogInfo()
    {        
        $msg = '[{' . $_SERVER['SCRIPT_NAME'] . '}';
        
        $msg .= 'from {' . $_SERVER['REMOTE_ADDR'] . "}\n";
         ・
         ・
         ・

修正後ソース

    public function GetLogInfo()
    {        
        $msg = '[{' . $_SERVER['SCRIPT_NAME'] . '}';

        if(isset($_SERVER['REMOTE_ADDR'])){
            $msg .= 'from {' . $_SERVER['REMOTE_ADDR'] . "}\n";
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            // aws_cron対応
            $msg .= 'from {' . $_SERVER['HTTP_X_FORWARDED_FOR'] . "}\n";
        } else {
            // ローカル対応
            $msg .= 'from {' . '['.'localhost'.']' ."\t" . "}\n";
        }

ELB + K8S環境でingress-nginxを通した場合

$_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']

参考サイト:https://uiuifree.com/blog/develop/php-elb-ip-address/

No composer.json present in the current directory, this may be the cause of the following exception.

事象:「docker-compose up -d」コマンド実行で発生

原因:composerのバージョンが対応していないのでエラーみたいです。

ファイル名:プロジェクト名/Dockerfile

修正後ソース

RUN curl -sS https://getcomposer.org/installer \
  | php \
  && mv composer.phar /usr/bin/composer \
  && composer selfupdate --1 \ ←これ!!!
  && composer config -g repos.packagist composer https://packagist.jp \
  && composer global require hirak/prestissimo \
  && chown www-data:www-data /var/www \
  && mkdir -p ${APACHE_DOCUMENT_ROOT}/var \
  && chown -R www-data:www-data ${APACHE_DOCUMENT_ROOT} \
  && find ${APACHE_DOCUMENT_ROOT} -type d -print0 \
  | xargs -0 chmod g+s \
  ;

Unable to replace alias “session.handler” with actual definition “session.handler.memcached”

事象:サーバーからPULLしたソースでローカル環境構築

原因:handler_idの設定値が正しくない(古い?)

ファイル名:プロジェクト名/app/config/eccube/packages/framework.yaml

修正後ファイル

framework:
    secret: '%env(ECCUBE_AUTH_MAGIC)%'
    default_locale: '%locale%'
    translator:
      fallback: ['%locale%']
    csrf_protection: { enabled: true }
    http_method_override: true
    trusted_hosts: ~
    # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
    session:
        # ↓ handler_id: session.handler.memcached ↓
        handler_id: 'Eccube\Session\Storage\Handler\SameSiteNoneCompatSessionHandler'
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
        name: '%env(ECCUBE_COOKIE_NAME)%'
        cookie_lifetime: '%env(ECCUBE_COOKIE_LIFETIME)%'
        gc_maxlifetime: '%env(ECCUBE_GC_MAXLIFETIME)%'
        cookie_httponly: true

You have requested a non-existent parameter “kernel.secret”. Did you mean this: “kernel.charset”?

事象:サーバーからプルしたものをローカルで立ち上げようとしたら、発生したエラー

原因:パラメータが定義されているframework.yamlファイルがない

ファイル名:プロジェクト名/app/config/eccube/packages/framework.yaml

作成ファイル

framework:
    secret: '%env(ECCUBE_AUTH_MAGIC)%'
    default_locale: '%locale%'
    translator:
      fallback: ['%locale%']
    csrf_protection: { enabled: true }
    http_method_override: true
    trusted_hosts: ~
    # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
    session:
        handler_id: 'Eccube\Session\Storage\Handler\SameSiteNoneCompatSessionHandler'
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'
        name: '%env(ECCUBE_COOKIE_NAME)%'
        cookie_lifetime: '%env(ECCUBE_COOKIE_LIFETIME)%'
        gc_maxlifetime: '%env(ECCUBE_GC_MAXLIFETIME)%'
        cookie_httponly: true

    # When using the HTTP Cache, ESI allows to render page fragments separately
    # and with different cache configurations for each fragment
    # https://symfony.com/doc/current/book/http_cache.html#edge-side-includes
    esi: { enabled: true }
    fragments: { enabled: true }
    php_errors:
        log: true
    assets:
      base_path: '/html/template/%eccube.theme%'
      packages:
        admin:
          base_path: '/html/template/admin'
        save_image:
          base_path: '/html/upload/save_image'
        plugin:
          base_path: '/html/plugin'
        install:
          base_path: '/html/template/install'
        temp_image:
          base_path: '/html/upload/temp_image'
        user_data:
          base_path: '/html/user_data'
        # json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
    cache:
        # this value is used as part of the "namespace" generated for the cache item keys
        # to avoid collisions when multiple apps share the same cache backend (e.g. a Redis server)
        # See https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed
        prefix_seed: ec-cube
    # The 'ide' option turns all of the file paths in an exception page
    # into clickable links that open the given file using your favorite IDE.
    # When 'ide' is set to null the file is opened in your web browser.
    # See https://symfony.com/doc/current/reference/configuration/framework.html#ide
    ide: ~
    validation: { enable_annotations: true }
    templating: { engines: ['twig'] }

参考サイト

https://github.com/EC-CUBE/ec-cube/blob/4.0.5/app/config/eccube/packages/framework.yaml#L2

Place “2” is not valid for workflow “order”.

事象:注文ステータス追加で発生

原因:ステータス繊維の制御設定が必要

ファイル名:プロジェクト名/app/config/packages/order_state_machine.php

カテゴリー
EC-CUBE

【EC-CUBE4】SQL

便利そうなSQLをメモしていこうと思います。

調査ようSQL

共通テンプレート適用

layout_idがないデータは、dtb_page_layoutで設定して確認

USE eccubedb;
SELECT 
 P.id page_id
 ,PL.layout_id
 ,L.layout_name
 ,P.page_name
 ,P.file_name
FROM  dtb_page P
LEFT JOIN dtb_page_layout PL ON P.id = PL.page_id
LEFT JOIN dtb_layout L ON PL.layout_id = L.id;

データ削除

注文データ関連削除SQL

実際に削除する際は、バックアップ取るなど必ず確認して下さい!

USE eccubedb;
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE dtb_cart;
TRUNCATE TABLE dtb_cart_item;
TRUNCATE TABLE dtb_order;
TRUNCATE TABLE dtb_order_item;
TRUNCATE TABLE dtb_shipping;
-- ソニーペイメント
TRUNCATE TABLE plg_sln_order_payment_history;
TRUNCATE TABLE plg_sln_order_payment_status;
-- ソニーペイメント定期購入
TRUNCATE TABLE plg_sln_regular_order;
TRUNCATE TABLE plg_sln_regular_order_item;
TRUNCATE TABLE plg_sln_regular_shipping;
TRUNCATE TABLE plg_sln_regular_order_to_order;
SET FOREIGN_KEY_CHECKS = 1;

外部キー制約の無効化, 有効化

関連するデータがある場合は、削除する順序が正しくない場合はエラーになるので、こちらを入れてます。

SET FOREIGN_KEY_CHECKS = 0;
SET FOREIGN_KEY_CHECKS = 1;
カテゴリー
EC-CUBE

【EC-CUBE4】リポジトリー:Repository

[temp id=3]

ドキュメント読んで、手順通りに学んだわけではないので参考程度に見てください。

Repository拡張方法

基本的に本体のソースはアップデートで変更になり可能性があるので、拡張して使用するのが安全です。

新規Repositoryファイルを作成

ファイル保存場所:Customize\Repository\ProductRepository.php

・Repositoryファイル「ProductRepository.php」を作成

<?php

namespace Customize\Repository;

use Eccube\Repository\ProductRepository as BaseProductRepository;

class ProductRepository extends BaseProductRepository
{
    /**
     * 新規メソッドの作成
     *
     * @param null|array $ProductStatus 指定の商品ステータス
     *
     * @return Products[] 商品の配列の配列
     */
    public function getProductList($ProductStatus = null)
    {
        $qb = $this->createQueryBuilder('p');

        if ($ProductStatus) {
            $qb
                ->andWhere($qb->expr()->in('p.Status', ':Status'))
                ->setParameter('Status', $ProductStatus);
        }

        $Products = $qb->getQuery()->getResult();

        return $Products;
    }

}

・拡張するRepositoryをuse(読込み)

・extendsで拡張

本体Repositoryの拡張

・メソッド毎コピー

・必要ファイルの読込み&construct定義

設定ファイルに定義

設定ファイル:app/config/eccube/services.yaml

・新規Repositoryファイル「ProductRepository.php」を作成

・拡張するRepositoryを定義する

services:
     ・
     ・
     ・
    Customize\Repository\ProductRepository:
        decorates: Eccube\Repository\ProductRepository

データの更新がうまくいかない

カスタマイズ案件で「dtb_cart」「dtb_cart_item」に似たテーブルを作った時の事。

登録直後の「cart_item」が表示されない挙動になった。

・F5で更新すれば表示される

・DBには「cart」「cart_item」が登録されている

結論を言うとcartクラスを更新すれば問題なし!!

$this->entityManager->refresh($cart)

登録の流れ

cart登録

cart_item登録

cart_item登録後なのでcartに紐づいていないcart_itemがデータになっている。

cart情報を取得しなおせば解決

カテゴリー
EC-CUBE

【EC-CUBE4】エンティティ:Entity

私のControllerの拡張方法を説明していきます。

ドキュメント読んで、手順通りに学んだわけではないので参考程度に見てください。

しっかり学びたい人は、Doctrineのドキュメントをお読みください。

Entityの定義

商品クラスで説明

テーブル定義

    /**
     * Product
     * ↓ これがないとクラス名でテーブルが作成される
     * @ORM\Table(name="dtb_product")
     * ↓ クラス階層ごとに1つのテーブルを作成します
     * @ORM\InheritanceType("SINGLE_TABLE")
     * ↓ テーブルの識別用カラム
     * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
     * ↓ サービスの依存関係がないならコールバックの設定をした方が良いとのこと
     * @ORM\HasLifecycleCallbacks()
     * ↓ Repositoryの読込み設定
     * @ORM\Entity(repositoryClass="Eccube\Repository\ProductRepository")
     */
    class Product extends \Eccube\Entity\AbstractEntity

項目定義

         * @ORM\Column(name="id", type="integer", options={"unsigned":true})
         * @ORM\Column(name="name", type="string", length=255)
         * @ORM\Column(name="create_date", type="datetimetz")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="IDENTITY")
         * @ORM\OneToMany(targetEntity="Eccube\Entity\ProductImage", mappedBy="Product", cascade={"remove"})
         * @ORM\ManyToOne(targetEntity="Eccube\Entity\Member")
         * @ORM\JoinColumns({
         *   @ORM\JoinColumn(name="creator_id", referencedColumnName="id")
         * })

データ登録の流れ

  1. 登録対象Entityの取得 $Product = new Product
  2. $Product->setName = ‘テスト商品’
  3. 永続化登録設定 $this->entityManager->persist($Product)
  4. 登録処理 $this->entityManager->flush($Product)

実際のDBへ登録されるタイミングは、テンプレートに行ってからとか!?
どこかのサイトに書いてあった。

なので実際は登録される前の、Entityのオブジェクトからリスト取得など行ったりしているんじゃないかな٩(•̤̀ᵕ•̤́๑)

リレーションについて

初期表示データ取得できない

カスタマイズ中に発生した問題です。

EC-CUBE4は基本的にDoctrineを使用しています。

データベースをオブジェクト化した物で、都度データベースにアクセスしないでデータの取得や加工が行えます。

なぜこの状態になったか?

取得できなかったデータ
※わかりやすくEC-CUBEデフォルトのテーブルで説明します。

要件:カートの情報をデータ登録直後に一覧ページに表示したい。

関連するテーブルは、dtb_cartとdtb_cart_itemの2種類です。

パターン1

  1. dtb_cartへEntityで登録+永続化+フラッシュ
  2. dtb_cart_itemへEntityで登録+永続化+フラッシュ
  3. findByでリスト取得して、テンプレートへ

パターン2

  1. dtb_cartへEntityで登録+永続化+フラッシュ
  2. dtb_cart_itemへEntityで登録+永続化+フラッシュ
  3. テンプレートでfindByしてリスト取得

上記でうまくいかなかったです。

結局なんだったかと言うと、

リレーションが貼ってあるので、cart→cart_itemの順で登録

cartは最新の登録データは持っているが、紐づくcart_itemは後から登録されるので

cartのEntityに、cart_itemの最新情報が紐づいていない状態

cartのEntityを更新する

$this->entityManager->refresh(XXX);
XXXは、更新するEntityオブジェクト 

$this->entityManager->refresh($cart);

これで解決!

カテゴリー
EC-CUBE

【EC-CUBE4】コントローラー:Controller

[temp id=3]

私のControllerの拡張方法を説明していきます。

ドキュメント読んで、手順通りに学んだわけではないので参考程度に見てください。

しっかり学びたい人は、Symfonyのドキュメントをお読みください。

https://symfony.com/doc/current/controller.html

簡単なControllerのカスタマイズ

ここで説明する情報は既存機能のカスタマイズです。

本体フォルダ→拡張フォルダを見に行きRouteが同一の場合上書きされる性質をもつ

新規のControllerを作成する際は、既存で使用されていないか必ず確認してください。

会員登録や商品詳細をカスタマイズしたいなどで応用できます。

Controllerのカスタマイズが必要か確認

大規模か改修の際は必要

一覧画面:テーブルに追加した項目のみの処理は不要

データ取得は、EntityTrait

表示は、twig

バリデーションは、Form

Controllerのカスタマイズ手順

今回は、会員登録「EntryController」を例に解説していきます。

重要パス
  1. 拡張フォルダ:プロジェクト名/app/Customize/Controller/
  2. 本体フォルダ:プロジェクト名/src/Eccube/Controller/
  1. EntryController.phpをコピーし拡張フォルダへ保存
  2. ファイル名変更CustomEntryController.php
  3. 拡張ファイルへ変更

3について、

  1. namespaceの変更
  2. useでAbstractControllerの読込み
 namespace Customize\Controller;

 use Eccube\Controller\AbstractController;

 class CustomEntryController extends AbstractController
 {

 }

確認方法

デバックするだけです。

    /**
     * 会員登録画面.
     *
     * @Route("/entry", name="entry")
     * @Template("Entry/index.twig")
     */
    public function index(Request $request)
    {
        dump('通過確認');
        exit;

スピード重視型

必要なファイルの読込み

既存メソッドを改修

綺麗さ重視型

不要な読込みファイルの削除

不要なメソッドの削除

カテゴリー
EC-CUBE

【EC-CUBE4】Commandクラス

定期お知らせメールを作成した際に触れたクラスです。
cron→bach→command

コマンドクラスからSwift_Messageでメール送信する

Commandクラス作成

コマンドで作成できます。

bin/console make:command

Commandクラスでメール送信テスト

https://github.com/EC-CUBE/ec-cube/issues/2116
githubから拝借させていただきました。

<?php
/* This file is part of EC-CUBE
* Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
* http://www.lockon.co.jp/
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/ 
namespace Eccube\Command;
 
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
 
class MailCommand extends Command
{
    protected static $defaultName = 'eccube:mail';

    /**
     * @var SymfonyStyle 
     */
     protected $io;

    public function __construct(\Swift_Mailer $mailer) { 
        parent::__construct();
        $this->mailer = $mailer;
    }

    protected function configure() {
        $this->setDescription('メールのテスト'); 
    }

    protected function initialize(InputInterface $input, OutputInterface $output) {
        $this->io = new SymfonyStyle($input, $output); 
    }

    protected function execute(InputInterface $input, OutputInterface $output) {
        $message = (new \Swift_Message())
            ->setSubject('メール送信チェック')
            ->setFrom('test01@example.com')
            ->setTo('test02@example.com')
            ->setBcc('test03@example.com')
            ->setReplyTo('test04@example.com')
            ->setReturnPath('test05@example.com');
        $this->mailer->send($message);
        $this->io->success('メール送信テスト完了.'); 
   }
 }

コマンド名になります。

protected static $defaultName = 'eccube:mail';
bin/console eccube:mail

テスト用の叩き台です。

コマンドクラスの挙動確認後

サービスクラスを作成しそこで、メール送るリストなどで選別しメールを送り完了

カテゴリー
EC-CUBE

【EC-CUBE4】設定

設定関連の情報をまとめて行きます。

設定ファイル

EC-CUBEは、「.env」ファイルに各種設定を記述します。

場所は、プロジェクト配下にあります。

「.env」ファイルは不可視ファイル

・確認にはオプション変更が必要

・ターミナルからコマンド実行の方は、「ls -la」コマンドで確認できます。

どんな設定があるの!?

複数あるので、重要な物を記述します。

・モードの設定

・DBの接続設定

・メールの設定

・Cookieの設定

DBの設定

envファイルの設定変更で、SQLが選べる。

こちらの3つ「sqlite, mysql, postgresql」が記述されています。

デフォルトはSQLite3になっている。

MySQLへ変更する場合

1行目を「#」でコメントアウトして、2行目の「#」を削除すればmysqlへ変更可能

SQLの再起動が必要かな!?

# DATABASE_URL=sqlite://var/eccube.db
 DATABASE_URL=mysql://dbuser:secret@mysql/eccubedb
# DATABASE_URL=postgresql://postgres/eccubedb?user=dbuser&password=secret

記述方法

mysql://dbuser:secret@mysql/eccubedb
SQL種類://ユーザー名:パスワード@ホスト名/データベース名

Docker-composeで作業している方は、ホスト名は「SQLのコンテナ名」になります。

MySQL初期ユーザーアカウント

ユーザーID:dbuser

パスワード:secret

メール設定

初期値は、メールが届かない設定になっているので変更しておきましょう。

gmail設定方法

# MAILER_URL=null://localhost
# MAILER_URL=sendmail://localhost
 MAILER_URL=gmail://「@前」:「パスワード」@localhost

Gmailブロックされたら

Gmailへ通知がきます。
来ない方は問題ないと思います。

Chromeの設定:セキュリティで変更可能

・二段階認証の解除

・安全性の低いアプリのアクセスの許可

MailCatcher設定方法

使用する方はこちら

MAILER_URL=smtp://mailcatcher:1025

こちら「http://127.0.0.1:1080/」にアクセスで使えます。

docker-compose.ymlのコンテナ名により記述が変わるっぽい─=≡Σ((( つ•̀ω•́)つ

MAILER_URL=smtp://127.0.0.1:1025

こんな感じの画面です。
ユーザーには送信されない為、開発にはすごく便利です。

カテゴリー
EC-CUBE

【EC-CUBE4】DB関連

データベース関連の情報をメモしていきます。

環境

EC-CUBE4
Docker-Composeでインストール
Mac

データベース名の変更

初期設定時の場合なので、途中で変更する際は注意下さい。

デフォルトのデータベース設定:eccubedb

変更するには下記ファイルのデータベース名の箇所を変更

.env
docker-compoae.yml

http://localhost:8080/へアクセスするとエラー

dbuserの権限で落ちてますね。

An exception occurred in driver: SQLSTATE[HY000] [1044] Access denied for user 'dbuser'@'%' to database データベース名

ではSQLで確認しましょう

DockerのコンテナへSQL接続

意味が違かったらすみません。

Dockerの下記画面で、黄色の枠のCLIを押せばコンテナのコマンドライン?が起動します。

コマンドラインからmysqlに接続

mysql -u root -p

デフォルトのパスワードは:root

sqlで権限確認

SHOW GRANTS FOR `dbuser`@`%`;

結果

 +------------------------------------------------------+
 | Grants for dbuser@%                                  |
 +------------------------------------------------------+
 | GRANT USAGE ON *.* TO 'dbuser'@'%'                   |
 | GRANT ALL PRIVILEGES ON `eccubedb`.* TO 'dbuser'@'%' |
 +------------------------------------------------------+
 2 rows in set (0.00 sec) 

eccubedbのみの権限になってましたね!

権限を付与していきます。

GRANT ALL ON データベース名.* TO 'dbuser'@`%`; 

データベースにコマンドラインから下記コマンドでデータ投入٩(๑’ꇴ’๑)۶

docker-compose exec ec-cube composer run-script compile 

結果:成功

 > bin/console doctrine:schema:create
 

  ! [CAUTION] This operation should not be executed in a production environment! 
 

  Creating database schema...
 

  [OK] Database schema created successfully!                                     
 

 > bin/console eccube:fixtures:load
   > Finished Successful! 

あとは「http://localhost:8080/」へアクセスして確認─=≡Σ((( つ•̀ω•́)つ

QueryBuilder

EC-CUBEに限らずPHP使うならほとんどのフレームワークに入っている─=≡Σ((( つ•̀ω•́)つ

IN

WHERE IN (1,2,3,4) どれかに該当するデータ

->where($qb->expr()->in('cn.name', $product_code))

JOIN

テーブル結合

->leftJoin('Eccube\Entity\OrderItem', 'oi', 'WITH', 'o.id = oi.id')    

MIN, MAX

cn.nameを長さで使用していたので違和感のある感じになっています。

 $qb->select('MIN(cn.name) min_value', 'MAX(cn.name) max_value')
    ->groupBy('cn.name');

CASE

指定の項目が条件にあった場合は、項目を置き換える。
nullは使い勝手が悪いから、「なし」とかに置き換えても使用可能

->addSelect("(case when t.period = '2020-01-01 00:00:00' then '7日前' else '3日前' end) AS return_date")

WHENが増えるとENDでエラーになる↓

->addSelect("(case when t.period1 = '2020-01-01 00:00:00' then '7日前' when t.period2 = '2020-01-01 00:00:00' then '3日前' end) AS return_date")
カテゴリー
EC-CUBE

【EC-CUBE4】カスタマイズ

バージョン:EC-CUBE4.0

いろいろ調べていて時間がかかったのでメモします

書籍も買いました!

読んだ感想としては、EC-CUBEってものの6割ぐらいはわかるんじゃないかな٩(•̤̀ᵕ•̤́๑)

https://amzn.to/3ierEXx

※こちらの書籍を読んで拡張はできません。

カスタマイズ

EC-CUBE4は、、、4しか知りませんが、、、٩(๑’ꇴ’๑)۶

EC-CUBE本体がsrc配下にあります。

本体パス:参考になるソースがあるので確認して下さいって感じです。

カスタマイズ対応クラス
  1. データ項目追加「Entity」
  2. サービス「Service」
  3. バリデーション「Form」
  4. 表示「Twig」

既存機能のカスタマイズは、基本的にControllerの修正なしで行える。

テンプレートは本体をコピー

本体パス:src/Eccube/Resource/template/

カスタマイズパス:app/template/

本体からカスタマイズへコピーする。

あとは、app/template/配下のファイルをカスタマイズするだけです。

Controller

本体パス:/src/Eccube/Controller/

カスタマイズパス:app/Customize/Controller/

カスタマイズパスへコントローラーの作成

既存のパスを上書きしたい場合は、アノテーションで指定すれば良いらしい

    /**
     * @Method("GET")
     * @Route("/test")
     */
    public function index(){

    }

Entity

本体パス:src/Eccube/Entity/

カスタマイズパス:app/Customize/Entity/

コマンドで作成可能
テーブルのカラム定義とgetter,setterも作ってくれる。

拡張する場合は「trait」

bin/console make:entity

Repository

本体パス:src/Eccube/Repository/

カスタマイズパス:app/Customize/Repository/

Entityをコマンドで作成したら、合わせて作成してくれる。

bin/console make:entity

Command

本体パス:src/Eccube/Command/

カスタマイズパス:app/Customize/Command/

bin/consoleコマンドが作成出来る。

メルマガや定期処理を「cron」で行う際に使用した。

コマンドで作成可能

bin/console make:command

Form

本体パス:src/Eccube/Form/

カスタマイズパス:app/Customize/Form/

Fromクラスは、基本的にExtensionとTypeの2種類使用する

Extension既存のFromクラスの拡張で使用する。

既存の必須解除上書きやオプション追加や追加した項目のForm定義も可能

Type項目単体で定義しFormクラスで読み込んで使用する。

Service

本体パス:/src/Eccube/Service/

カスタマイズパス:app/Customize/Service/

サービスクラスの作成やデフォルトの拡張やプラグインのサービスの拡張も可能

app/config/eccube/services.yamlへ追加すれば拡張も可能

    Customize\Service\新規クラス名:
        decorates: 継承するクラスのパス
    Customize\Service\RegularOrderServiceCustomizer:
        decorates: Plugin\SlnRegular4\Service\RegularOrderService

・拡張したいサービスのファイルをCustomize/Service/配下へコピー

・namespaceを変更

・useへ拡張元のファイルパス

・extensへ拡張クラス名

データベースへ項目追加

下記2種類の方法があるみたいですね。
今回は1の方法で行っていきます。

1.Entityクラスに項目を追加しコマンドでデータベースに反映する方法

2.Entityをテーブルから逆再生する方法
https://qiita.com/haruna-nagayoshi/items/27108c75eaf9511f3524

今回は「商品情報」へ「項目の追加」をしていきたいと思います。

エンティティの拡張

商品エンティティの拡張をしていきます。

商品エンティティを拡張するので「ProductTrait.php」を作成する。

商品マスタ:dtb_product
商品エンティティ:/src/Eccube/Entity/Product
ProductTraitの作成する場所:/app/Customize/Entity/ProductTrait.php

<?php
namespace Customize\Entity;
 
use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation as Eccube;
 
/**
 * @Eccube\EntityExtension("Eccube\Entity\Product")
 */
trait ProductTrait
{
    /**
     * @var string|null
     *
     * @ORM\Column(name="product_symbol", type="string", length=45, nullable=true, options={"comment":"商品記号"})
     */
    public $product_symbol;

    /**
     * @var string|null
     *
     * @ORM\Column(name="packing_cost", type="decimal", precision=12, scale=2, nullable=true, options={"comment":"梱包料金"})
     */
    public $packing_cost;
}

コメントは入れるだけでもデータ構成の理解が早くなるのでなるべく書く٩(•̤̀ᵕ•̤́๑)

Proxyクラスの生成

cd プロジェクト配下
php bin/console eccube:generate:proxies
gen -> /Users/kenshiro/project/ec-cube/app/proxy/entity/src/Eccube/Entity/Product.php

ファイル変更後はキャッシュをクリア

bin/console cache:clear --no-warmup 

実行するSQLの確認

php bin/console doctrine:schema:update --dump-sql

エラー!!!

In AbstractMySQLDriver.php line 93:
 An exception occurred in driver: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known 

めちゃくちゃハマりましたο(´・ω・`o)

こちらの記事の原因と対応に感謝します─=≡Σ((( つ•̀ω•́)つ

https://qiita.com/kilica/items/6739b7a3d9992b593857

原因はDockerの知識が少ないところにありました。

macのターミナルでコマンド叩いてました。

EC-CUBE起動しているコンテナにログインしてコマンドを叩けば解決٩(•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ

と思いましたが変更が反映されずダメでした。

[OK] Nothing to update - your database is already in sync with the current entity metadata.

結局先ほどコマンドで作成したProxyへ「カラムの定義」を追加
場所:ec-cube/app/proxy/entity/src/Eccube/Entity/Product.php

// キャッシュクリア
bin/console cache:clear --no-warmup
// テーブルとの差分で実行するSQL確認
php bin/console doctrine:schema:update --dump-sql
// 結果↓
The following SQL statements will be executed:
「実行するSQL」
// テーブルとの差分でSQLを実行する
bin/console doctrine:schema:update --dump-sql --force
//結果
「実行したSQL」
[OK] Database schema updated successfully!

Entityの更新が反映されない

Entityの修正した時に発生した◟꒰◍´Д‵◍꒱◞

キャッシュクリアすれば出来るって記事はあったけど関係なかった、、、

bin/console cache:clear --no-warmup

composerで依存関係が管理されていてそれを更新すれば、エラーを解消できた!!

EC-CUBE起動しているコンテナにログインしてコマンドを叩けば解決٩(•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ

composer install

以上─=≡Σ((( つ•̀ω•́)つ

Dockerのコンテナにログインする方法

Dockerの下記画面で、黄色の枠のCLIを押せばコンテナへログインしたコマンドラインが起動します。

エンティティの作成

新規テーブル追加

app/config/eccube/pakages/devへ

maker.yamlファイルの追加

下記内容で保存

maker:
  root_namespace: 'Customize'

あとはターミナルのコマンドで解決
対話形式で作成していく

エンティティ作成コマンド

bin/console make:entity

コントローラー作成コマンド

bin/console make:controller

実行クエリ確認

どんなSQLを投げたのか確認したい事ありますよね!

dump($qb->getQuery()->getSQL());
exit;

こんな感じで確認できます٩(•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ

商品登録画面

追加項目への必須が機能しない

いろいろ調べたら、required属性が機能していなかった。

formタグに「novalidate」検証無効の設定がされていた、、、

アノテーションの自動生成で実装していたので「Assert\NotBlank()」を追加し解決

商品の非公開設定

商品データ関連を入れた際に確認した情報

商品「dtb_product:product_status_id」で非公開が可能

結論を言うと「dtb_product:product_status_id=2」

product_status_id 1:公開, 2:非公開 3:廃止

ただ、関連テーブルに非表示がある「dtb_class_category・dtb_product_class」「visible」、、、

情報も非表示にした方が良いのか?

dtb_productと関連した情報を持っていた場合は、管理画面の商品検索でエラーになります。

商品一覧の検索にヒットしないなど、余計な事になるのでやらない方が良いです。