カテゴリー
EC-CUBE

【EC-CUBE4】初期注文ステータス変更

銀行支払いの場合は購入処理後に「新規受付」→「入金待ち」になるように変更する。

このカスタマイズは一例になります。

プラグインによっては、うまく胃開かない可能性があるのでご「注意ください。

もっと良いカスタマイズ方法があれば、コメントください。

[temp id=3]

購入フローの確認

購入フローは、使用する複数クラスで構成されています。

購入フローの設定は基本的に下記ファイルで行ってます。

ファイルパス:eccube/app/config/eccube/packages/purchaseflow.yaml

詳細は公式のドキュメントを確認ください。

EC-CUBE4開発者向けドキュメントサイト

OrderUpdateProcessorの確認

通常の購入フローで「新規受付」に変更しているのは、こちらのファイルです。

ファイルパス:eccube/src/Eccube/Service/PurchaseFlow/Processor/OrderUpdateProcessor.php

PHP
<?php

/*
 * This file is part of EC-CUBE
 *
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
 *
 * http://www.ec-cube.co.jp/
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Eccube\Service\PurchaseFlow\Processor;

use Eccube\Entity\ItemHolderInterface;
use Eccube\Entity\Master\OrderStatus;
use Eccube\Entity\Order;
use Eccube\Repository\Master\OrderStatusRepository;
use Eccube\Service\PurchaseFlow\PurchaseContext;

/**
 * 受注情報更新処理.
 */
class OrderUpdateProcessor extends AbstractPurchaseProcessor
{
    /**
     * @var OrderStatusRepository
     */
    private $orderStatusRepository;

    /**
     * OrderUpdateProcessor constructor.
     *
     * @param OrderStatusRepository $orderStatusRepository
     */
    public function __construct(OrderStatusRepository $orderStatusRepository)
    {
        $this->orderStatusRepository = $orderStatusRepository;
    }

    public function commit(ItemHolderInterface $target, PurchaseContext $context)
    {
        if (!$target instanceof Order) {
            return;
        }
        $OrderStatus = $this->orderStatusRepository->find(OrderStatus::NEW);
        $target->setOrderStatus($OrderStatus);
        $target->setOrderDate(new \DateTime());
    }
}

OrderUpdateProcessorの作成

本体の「OrderUpdateProcessor」をコピーしCustomizeでカスタマイズ

Payment::BANK_PAYMENTは、別途拡張して定数を追加したます。

PAID_WAIT_STATUSを配列にする事で、銀行振込以外でも入金待ちにしたい支払い方法追加可能としました。

PHP
<?php

namespace Customize\Service\PurchaseFlow\Processor;

use Eccube\Service\PurchaseFlow\Processor\AbstractPurchaseProcessor;
use Eccube\Entity\ItemHolderInterface;
use Customize\Entity\Master\OrderStatus;
use Customize\Entity\Payment;
use Eccube\Entity\Order;
use Eccube\Repository\Master\OrderStatusRepository;
use Eccube\Service\PurchaseFlow\PurchaseContext;


/**
 * 受注情報更新処理.
 */
class OrderUpdateProcessor extends AbstractPurchaseProcessor
{
    // 入金待ちにする注文ステータス
    const PAID_WAIT_STATUS = [
        Payment::BANK_PAYMENT,
    ];

    /**
     * @var OrderStatusRepository
     */
    private $orderStatusRepository;

    /**
     * OrderUpdateProcessor constructor.
     *
     * @param OrderStatusRepository $orderStatusRepository
     */
    public function __construct(OrderStatusRepository $orderStatusRepository)
    {
        $this->orderStatusRepository = $orderStatusRepository;
    }

    public function commit(ItemHolderInterface $target, PurchaseContext $context)
    {
        if (!$target instanceof Order) {
            return;
        }

        $Payment = $target->getPayment();

        // 支払い方法により、ステータスを変更する
        if (in_array($Payment->getId(), self::PAID_WAIT_STATUS, true)) {
            $OrderStatus = $this->orderStatusRepository->find(OrderStatus::PAID_WAIT);
        } else {
            $OrderStatus = $this->orderStatusRepository->find(OrderStatus::NEW);
        }
        $target->setOrderStatus($OrderStatus);
        $target->setOrderDate(new \DateTime());
    }
}

PurchaseFlowの設定変更

カスタマイズした「OrderUpdateProcessor」を読み込むように変更

Bash
services:

    # Purchase Flow for Cart

    eccube.purchase.flow.shopping.purchase:
        class: Doctrine\Common\Collections\ArrayCollection
        arguments:
            - #
                - '@Eccube\Service\PurchaseFlow\Processor\PreOrderIdValidator'
                - '@Eccube\Service\PurchaseFlow\Processor\PointProcessor'
                - '@Eccube\Service\PurchaseFlow\Processor\StockReduceProcessor'
                - '@Eccube\Service\PurchaseFlow\Processor\CustomerPurchaseInfoProcessor'
                # - '@Eccube\Service\PurchaseFlow\Processor\OrderUpdateProcessor'
                # 支払い方法で初回ステータスを変更できるようカスタマイズ
                - '@Customize\Service\PurchaseFlow\Processor\OrderUpdateProcessor'
カテゴリー
EC-CUBE

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

Entityについて説明していきます。

Entityの定義

Entityとは、データを扱うクラスです。

本体Entity:ドキュメントルート/src/Eccube/Entity

基本的には、データベースの各テーブルを定義し使用していきます。

関連するテーブルの情報を定義し「スキーマ更新コマンド」でDBへ更新も可能です。

Bash
bin/console doctrine:schema:update --dump-sql --force

商品クラスで解説

テーブル定義

PHP
    /**
     * 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

カラム定義

PHP
         * @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")
         * })

定数やメソッドも追加可能

PHP
// 編集不可ステータス
const UNEDITABLE_STATUS = [
    self::PENDING,
    self::PROCESSING,
    self::CREDIT_SLIP,
];

/**
 * 銀行支払いかチェック
 * @return bool
 */
 public function isBankPayment() {
  return $this->getId() == Payment::BANK_PAYMENT ? true:false;
}

データ登録の流れ

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

実際のDBへ登録されるタイミングは、エラーがなく正常終了してテンプレートにいくタイミング。

Entityをカスタマイズしたい場合

src配下のEntity本体ソースは、アプデで影響が出る可能性があるので、

カラムやメソッドを追加したい場合

CustomizeでTraitを使用し拡張する

この場合は、スキーマ更新コマンドでdtb_categoryへslugカラムが追加される。

更新手順↓

proxy更新→キャッシュクリア→スキーマ更新コマンド

PHP
<?php

namespace Customize\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;

/**
 * @EntityExtension("Eccube\Entity\Category")
 */
trait CategoryTrait
{
    /**
     * @var string
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $slug;

    /**
     * @return string|null
     */
    public function getSlug(): ?string
    {
        return $this->slug;
    }

    /**
     * @param string|null $slug
     * @return $this
     */
    public function setSlug(?string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }
}

定数を使用したい場合

元のEntityを継承して使用する

PHP
<?php

namespace Customize\Entity\Master;

use Eccube\Entity\Master\OrderStatus as BaseEntity;

if (!class_exists('Customize\Entity\Master\OrderStatus')) {

    /** 親クラスの定数宣言を拡張する目的に作成しています */
    class OrderStatus extends BaseEntity {

        /** 入金待ち */
        const PAY_WAIT = 2;

        // 編集不可ステータス
        const UNEDITABLE_STATUS = [
            self::PENDING,
            self::PROCESSING,
            self::CREDIT_SLIP,
        ];
    
    }
}

使用したいファイルで、useして使用する

use Customize\Entity\Master\OrderStatus;

既存の他のTrait読み込み

下記プログラムでgetFullName()が使用可能となる

PHP
<?php

namespace Customize\Entity;

use Eccube\Annotation\EntityExtension;
use Eccube\Entity\NameTrait;

/**
  * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{
    use NameTrait;
}

src/Eccube/Entity/NameTrait.php

PHP
<?php

namespace Eccube\Entity;

trait NameTrait
{
    public function getFullName()
    {
        return (string) $this->name01.' '.$this->name02;
    }

    public function getFullNameKana()
    {
        return (string) $this->kana01.' '.$this->kana02;
    }
}

以前ハマった対応があったので紹介します。

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

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

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を更新する

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

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

これで解決!

カテゴリー
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

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