第64回EC-CUBE関西UGに参加したまとめ｜会員情報に趣味の項目（テキスト）と受注情報に熨斗の項目（セレクトボックス）を追加するカスタム

2020-10-15（木）18:00～開催された第64回EC-CUBE関西UGをまとめてみました。

約2時間おかじ（qiita:@okazy twitter:[@OwOkazy](https://twitter.com/OwOkazy)）さんがぶっ通しで、説明しながらライブコーディングを行ってくれました。

資料が欲しい、YouTubeで見れないですか？といったコメントなども見たので、僕なりに資料を残してみます。

##資料サイト

EC-CUBE 4.0 開発者向けドキュメント
[https://doc4.ec-cube.net/](https://doc4.ec-cube.net/)

Symfony doc
[https://symfony.com/doc/current/index.html](https://symfony.com/doc/current/index.html)

本日のソース
[github:okazy](https://github.com/okazy/ec-cube/compare/5286a8102fea2b64d8557c5b46e28c259c482414...okazy:kansai202010?expand=1)

他にも紹介されてたような・・・

##環境
おかじさんは、「[1.コマンドラインからインストールする](https://doc4.ec-cube.net/quickstart_install#1%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B)」の方法でEC-CUBEをインストールしていました。

環境はレンタルサーバーにインストールしてもいいし、XAMPP・MAMPでもいいかと思います。
EC-CUBEが動ていれば問題なし！！

##基礎知識
カスタムするPHPファイルは「app/Customize」フォルダ内に設置します。
できるだけ「src/Eccube」フォルダ内の構成と同じように作成すると分かり易いです。

##会員情報に趣味の項目（テキスト）を追加するカスタム

フロント側の新規会員登録ページ・マイページ→会員情報編集ページ、管理側の会員登録ページ・会員編集ページに趣味の項目を追加するカスタムです。

###ENTITYのカスタマイズ

参考ページ：[Entityのカスタマイズ](https://doc4.ec-cube.net/customize_entity)
・[基本の拡張方法](https://doc4.ec-cube.net/customize_entity#%E5%9F%BA%E6%9C%AC%E3%81%AE%E6%8B%A1%E5%BC%B5%E6%96%B9%E6%B3%95)
・[Entity からフォームを自動生成する](https://doc4.ec-cube.net/customize_entity#entity-%E3%81%8B%E3%82%89%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92%E8%87%AA%E5%8B%95%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B)

会員情報（src/Eccube/Entity/Customer.php）の情報を拡張します。
CustomerTrait内でFormの設定まで行います。

```php:CustomerTrait.php
<?php
namespace Customize\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;
use Eccube\Annotation\FormAppend;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{
    /**
     * @var string|null
     * @ORM\Column(type="string", nullable=true)
     * @Assert\NotBlank(message="入力してください")
     * @FormAppend(
     *     auto_render=true,
     *     type="\Symfony\Component\Form\Extension\Core\Type\TextType",
     *     options={"required": true, "label": "趣味"}
     * )
     */
    private $hobby;

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

    /**
     * @param string|null $hobby
     */
    public function setHobby(?string $hobby): void
    {
        $this->hobby = $hobby;
    }
}
```

それでは、上記ファイルを設置してデータベースの更新などコマンドを打っていきましょう。

####ファイルの設置
「app/Customize/Entity/CustomerTrait.php」へ上記コードを追加します。
CustomerTrait.phpは新規作成します。

ファイルの設置が完了したら、ターミナルからコマンドを実行します。

###コマンドの実行
EC-CUBEを設置したフォルダへ移動して次のコマンドを実行しましょう。

**Proxy クラスを生成**
`bin/console eccube:generate:proxies`

**キャッシュクリア**
`bin/console cache:clear --no-warmup`

**実行する SQL を確認**
`bin/console doctrine:schema:update --dump-sql`

こんな感じでSQLが表示されると思います。

```
The following SQL statements will be executed:

    ALTER TABLE dtb_customer ADD hobby VARCHAR(255) DEFAULT NULL;
```

**SQL を実行**
`bin/console doctrine:schema:update --dump-sql --force`

**キャッシュ生成**
`bin/console cache:warmup`

###Formを確認
**フロント側**
新規会員登録ページ、マイページ→会員情報編集ページに趣味項目が追加されています。

![2020-10-15_22h54_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117915/fb4607ee-eb8d-0f7f-3245-09670c9c9e55.png)

**管理側**
新規会員登録、会員情報編集ページに趣味項目が追加されています。

![2020-10-15_22h55_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117915/fba489ac-6038-0522-3986-4692189b6dbc.png)

以上で、**会員情報に趣味の項目（テキスト）を追加するカスタム**は完了です。

ENTITYファイルだけで、簡単に項目が追加できるので簡単・・・ですね。
ちょっとした項目の追加ならこの方法が良いかも。

##受注情報に熨斗の項目（セレクトボックス）を追加するカスタム

フロント側のカートからレジへ進んでご注文手続きページ・ご注文内容確認ページ、管理側の受注登録ぺージ、受注編集ページへ熨斗の項目を追加するカスタムです。

熨斗の選択はセレクトボックスで選択項目は「あり・なし」です。

###ENTITYのカスタマイズ

参考ページ：[Entityのカスタマイズ](https://doc4.ec-cube.net/customize_entity)
・[基本の拡張方法](https://doc4.ec-cube.net/customize_entity#%E5%9F%BA%E6%9C%AC%E3%81%AE%E6%8B%A1%E5%BC%B5%E6%96%B9%E6%B3%95)

受注情報（src/Eccube/Entity/Order.php）の情報を拡張します。
上記の会員情報のカスタムと違いFormは別の方法でカスタムするので、ここでは熨斗の情報を登録できるようにOrderに項目を追加するだけです。

```php:OrderTrait.php
<?php
namespace Customize\Entity;

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

/**
 * @EntityExtension("Eccube\Entity\Order")
 */
trait OrderTrait
{
    /**
     * @var bool
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $noshi = false;

    /**
     * @return bool
     */
    public function isNoshi(): ?bool
    {
        return $this->noshi;
    }

    /**
     * @param bool $noshi
     */
    public function setNoshi(bool $noshi): void
    {
        $this->noshi = $noshi;
    }
}
```

熨斗の項目は「あり・なし」の選択だけなので、boolean（true/false）で0か1かみたいな感じです。
ON/OFFがしっくりくるかも？

getNoshi()ではなくisNoshi()なのは、booleanはtrueかfalseになるので、このようなときはisを使います。
`return $this->noshi;`はtrueかfalseが返ります。

####ファイルの設置
「app/Customize/Entity/OrderTrait.php」へ上記コードを追加します。
OrderTrait.phpは新規作成します。

###まずは管理側から。
####Formのカスタマイズ

参考ページ：[FormTypeのカスタマイズ](https://doc4.ec-cube.net/customize_formtype)
・[FormExtensionを使った拡張](https://doc4.ec-cube.net/customize_formtype#formextension%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%8B%A1%E5%BC%B5)

受注情報Form（src/Eccube/Form/Type/Admin/OrderType）の拡張します。
会員情報の時はENTITY内でFormの拡張を行いましたが、受注情報の拡張はFormを作成する元になるOrderType.phpを拡張します。

```php:AdminNoshiExtension.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 Customize\Form\Extension;

use Eccube\Form\Type\Admin\OrderType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class AdminNoshiExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
            $form = $event->getForm();

            $form->add('noshi', ChoiceType::class, [
                'choices' => [
                    'あり' => true,
                    'なし' => false,
                ],
            ]);
        });
    }

    public function getExtendedType()
    {
        return OrderType::class;
    }
}
```
#####ファイルの設置
「app/Customize/Form/Extension/AdminNoshiExtension.php」へ上記コードを追加します。
AdminNoshiExtension.phpは新規作成します。

準備は完了しましたが、まだ受注登録・編集のフォームへ熨斗の項目は表示されません。
表示させるには、テンプレートを作成します。

今回は、支払い方法の項目の下へ、熨斗の項目を表示させるようにします。

####テンプレート作成

EC-CUBE4では、JavaScriptを使ってHTMLの変更をする事を推奨しています。
どこかに情報があったのですが、いつも見失って見つけることができませんでした。。。
見つけれたら記事の修正をしておきます。

画面への介入については[サンプルプラグイン](https://github.com/EC-CUBE/sample-payment-plugin#%E7%94%BB%E9%9D%A2%E3%81%B8%E3%81%AE%E4%BB%8B%E5%85%A5%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)が参考になります。

```twig:order_edit.twig
<script>
    $(function () {
        $('#customize-noshi').appendTo($('#orderOverview > div > div > div:nth-child(1)'));
    });
</script>
<div class="d-none">
    <div id="customize-noshi" class="row mb-3 form-group">
        <label class="col-3 col-form-label">熨斗</label>
        <div class="col">
            {{ form_widget(form.noshi) }}
            {{ form_errors(form.noshi) }}
        </div>
    </div>
</div>
```
#####ファイルの設置
「app/template/admin/order_edit.twig」へ上記コードを追加します。
order_edit.twigは新規作成します。

次に、設置したtwigを管理側の受注登録・編集ページで読み込むためにEventファイルを作成します。

####Event作成（テンプレートイベント）

受注登録・編集フォームのtwigファイルは`src/Eccube/Resource/template/admin/Order/edit.twig`になります。
ここへ上記の`order_edit.twig`の内容を追加（拡張）する為の方法です。

参考ページ：[Symfonyの機能を使ったカスタマイズ](https://doc4.ec-cube.net/customize_symfony)
・[Symfony Event](https://doc4.ec-cube.net/customize_symfony#symfony-event)

※EventはSymfonyの機能ですが、TemplateEventはEC-CUBEの独自拡張です。

```php:NoshiEvent.php
<?php
namespace Customize\EventListener;

use Eccube\Event\TemplateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class NoshiEvent implements EventSubscriberInterface
{

    public static function getSubscribedEvents()
    {
        return [
            '@admin/Order/edit.twig' => 'onAdminOrderEditTwig',
        ];
    }

    public function onAdminOrderEditTwig(TemplateEvent $event)
    {
        $event->addSnippet('@admin/order_edit.twig');
    }
}
```
#####ファイルの設置
「app/Customize/EventListener/NoshiEvent.php」へ上記コードを追加します。
order_edit.twigは新規作成します。

###フロント側
####Formのカスタマイズ

フロント側の受注情報Form（src/Eccube/Form/Type/Shopping/OrderType）の拡張します。

参考ページ：[FormTypeのカスタマイズ](https://doc4.ec-cube.net/customize_formtype)
・[FormExtensionを使った拡張](https://doc4.ec-cube.net/customize_formtype#formextension%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%8B%A1%E5%BC%B5)

```php:NoshiExtension.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 Customize\Form\Extension;

use Eccube\Form\Type\Shopping\OrderType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class NoshiExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ShoppingController::checkoutから呼ばれる場合は, フォーム項目の定義をスキップする.
        if ($options['skip_add_form']) {
            return;
        }

        $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
            $form = $event->getForm();

            $form->add('noshi', ChoiceType::class, [
                'choices' => [
                    'あり' => true,
                    'なし' => false,
                ],
            ]);
        });
    }

    public function getExtendedType()
    {
        return OrderType::class;
    }
}
```
#####ファイルの設置
「app/Customize/Form/Extension/NoshiExtension.php」へ上記コードを追加します。
NoshiExtension.phpは新規作成します。

####テンプレートのカスタマイズ
参考ページ：[デザインテンプレートの基礎](https://doc4.ec-cube.net/design_template)
・[デザインカスタマイズ時のファイル配置](https://doc4.ec-cube.net/design_template#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E6%99%82%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E9%85%8D%E7%BD%AE)

フロント側のテンプレートを直接変更していますが、フロント側のデザインをカスタマイズする時は`/src/Eccube/Resource/template/[template_code]`を`/app/template/[template_code]`へコピーしてから変更します。
すべてコピーしなくても、必要な分だけコピーしたら大丈夫です。

コードが長いので、本日のソース「[github:okazy](https://github.com/okazy/ec-cube/compare/5286a8102fea2b64d8557c5b46e28c259c482414...okazy:kansai202010?expand=1)」から`app/template/default/Shopping/confirm.twig`と`app/template/default/Shopping/index.twig`を確認してください。

#####ファイルの設置
「app/template/default/Shopping/confirm.twig」と「app/template/default/Shopping/index.twig」へ上記コードを追加します。

####コマンドの実行
会員情報と同じようにコマンドを実行しましょう。

**Proxy クラスを生成**
`bin/console eccube:generate:proxies`

**キャッシュクリア**
`bin/console cache:clear --no-warmup`

**実行する SQL を確認**
`bin/console doctrine:schema:update --dump-sql`

こんな感じでSQLが表示されると思います。

```
The following SQL statements will be executed:

    ALTER TABLE dtb_order ADD noshi TINYINT(1) DEFAULT NULL;
```

**SQL を実行**
`bin/console doctrine:schema:update --dump-sql --force`

**キャッシュ生成**
`bin/console cache:warmup`

####Formを確認
**フロント側**
**ご注文手続き**に熨斗の選択肢
![2020-10-16_01h12_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117915/b9c492a1-c54c-3050-6ae4-d47e4feb3019.png)

**ご注文内容確認**に熨斗の選択肢の確認
![2020-10-16_01h14_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117915/7f1f7879-7a33-c3f1-c395-0a16a60a71cb.png)

**管理側**
受注管理・編集ページに熨斗の項目が追加されてます。
![2020-10-16_00h40_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117915/10225b32-93c3-ddcd-577a-93439af63a11.png)

以上で、第64回EC-CUBE関西UGの内容は終了です。

おかじ（[@OwOkazy](https://twitter.com/OwOkazy)）さん、ありがとうございました！！