EC-CUBE4 プラグインでマスターテーブルを追加する

#はじめに
初めての投稿となります。
よろしくお願いします。

仕事で始めてEC-CUBE4を利用したECサイトを仕事で制作しました。
その際、プラグインでマスターテーブルを新規追加することになったのですが、
テーブルの新規追加はよく見かけるのに対し、マスターテーブルの記事が少ないように感じたので作成方法を簡単に記事にまとめよう思います。

新規プラグイン作成方法については多くのサイトが存在するのでそちらを参考にしください。

#目標
マスターテーブル(mtb_sample)の新規追加。
管理画面＞設定＞システム設定＞マスタデータ管理 へ登録。


#最終的なマスターテーブル
形は以下のしたいと考えています。

| id |      name      | sort_no |     discriminator_type      |
|:---|:--------------:|:-------:|:---------------------------:|
| 1  |    テスト1   |    1    | samplemtbconfig|
| 2  |    テスト2   |    2    | samplemtbconfig|
| 3  |    テスト3   |    3    | samplemtbconfig|
| 4  |    テスト4   |    4    | samplemtbconfig|


#管理画面＞設定＞システム設定＞マスタデータ管理
以下の設定にマスターテーブル(mtb_sample)を編集出来るようにします。
![01_マスターデータ管理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355704/4014bd55-f053-104b-a948-f21b2c17a164.png)

#EC-CUBE Version 
```
　Version 4.0.4
```

#プラグイン
プラグイン生成時の項目は以下にしています。

```
name：SamplePlugin
code：SamplePlugin
ver： 1.0.0
```

#プラグインのディレクトリ構成
```
SamplePlugin\
|―― Entity\
　　|―― Master\
　　　　|―― SampleMtbConfig.php
|―― Repository\
　　|―― Master\
　　　　|―― SampleMtbRepository.php
|―― Form\
　　|―― Type\
　　　　|―― Extension\
　　　　　　|―― SampleMasterdataType.php
|―― composer.json
|―― PluginManager.php

```
#composer.json
プラグインの情報の記述

```json:composer.json
{
  "name": "ec-cube/SamplePlugin",
  "version": "1.0.0",
  "description": "SamplePlugin",
  "type": "eccube-plugin",
  "require": {
    "ec-cube/plugin-installer": "~0.0.7"
  },
  "extra": {
    "code": "SamplePlugin"
  }
}
```

#Entity\Master\SampleMtbConfig.php
まずはエンティティクラスを作成します。
普通のテーブルであればここに setId()やgetid()などを記述していくのですが、必要ありません。

以下の記述でマスターテーブルの名前を設定します。
``` @ORM\Table(name="mtb_sample") ```


```php:SampleMtbConfig.php
<?php
namespace Plugin\SamplePlugin\Entity\Master;

use Doctrine\ORM\Mapping as ORM;

/**
 * SamplePlugin
 *
 * @ORM\Table(name="mtb_sample")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Entity(repositoryClass="Plugin\SamplePlugin\Repository\Master\SampleMtbRepository")
 * @ORM\Cache(usage="NONSTRICT_READ_WRITE")
 */
class SampleMtbConfig extends \Eccube\Entity\Master\AbstractMasterEntity
{
}

```

#Repository\Master\SampleMtbRepository.php
Repositoryはテーブルのデータを操作する際に利用されます。


```php:SampleMtbRepository.php
<?php
namespace Plugin\SamplePlugin\Repository\Master;

use Eccube\Repository\AbstractRepository;
use Plugin\SamplePlugin\Entity\Master\SampleMtbConfig;
use Symfony\Bridge\Doctrine\RegistryInterface;

class SampleMtbRepository extends AbstractRepository
{
    /**
     * 
     * @param RegistryInterface $registry
     */
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, SampleMtbConfig::class);
    }
}

```

#Form\Extension\SampleMasterdataType.php
管理画面＞設定＞システム設定＞マスタデータ管理 へ登録や変更を行うことが出来る機能へ反映させるための記述です。

```php:SampleMasterdataType.php
<?php
namespace Plugin\SamplePlugin\Form\Type\Extension;

use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Eccube\Form\Type\Admin\MasterdataType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;


class SampleMasterdataType extends AbstractTypeExtension
{
    /**
     *
     * @var EntityManagerInterface
     */
    protected $entityManager;

    /**
     *
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    /**
     *
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $masterdata = [];

        /** @var MappingDriverChain $driverChain */
        $driverChain = $this->entityManager->getConfiguration()->getMetadataDriverImpl();
        /** @var MappingDriver[] $drivers */
        $drivers = $driverChain->getDrivers();

        foreach ($drivers as $namespace => $driver) {
            if ($namespace == 'Eccube\Entity' || $namespace == 'Plugin\SamplePlugin\Entity') {
                $classNames = $driver->getAllClassNames();
                foreach ($classNames as $className) {
                    /** @var ClassMetadata $meta */
                    $meta = $this->entityManager->getMetadataFactory()->getMetadataFor($className);
                    if (strpos($meta->rootEntityName, 'Master') !== false
                        && $meta->hasField('id')
                        && $meta->hasField('name')
                        && $meta->hasField('sort_no')
                    ) {
                        $metadataName = str_replace('\\', '-', $meta->getName());
                        $masterdata[$metadataName] = $meta->getTableName();
                    }
                }
            }
        }

        $builder
            ->add('masterdata', ChoiceType::class, [
                'choices' => array_flip($masterdata),
                'expanded' => false,
                'multiple' => false,
                'constraints' => [
                    new Assert\NotBlank(),
                ],
            ])
            ;
    }

    /**
     *
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'admin_system_masterdata';
    }

    /**
     *
     * {@inheritdoc}
     */
    public function getExtendedType()
    {
        return MasterdataType::class;
    }
}

```

#PluginManager.php
PluginManager.phpはプラグインのインストールやアンインストール時に呼び出されますので、プラグインインストール時に、マスターデータを書き込む記述をします。

```php:PluginManager.php
<?php
namespace Plugin\SamplePlugin;

use Eccube\Plugin\AbstractPluginManager;
use Plugin\SamplePlugin\Entity\Master\SampleMtbConfig;
use Symfony\Component\DependencyInjection\ContainerInterface;


class PluginManager extends AbstractPluginManager
{
    /**
     *
     * @param array $meta
     * @param ContainerInterface $container
     */
    public function install(array $meta, ContainerInterface $container) {

        $em = $container->get('doctrine.orm.entity_manager');

        $CustomerQuestionnaire = new SampleMtbConfig();
        $CustomerQuestionnaire->setId('1');
        $CustomerQuestionnaire->setName('テスト1');
        $CustomerQuestionnaire->setSortNo('1');
        $em->persist($CustomerQuestionnaire);
        $em->flush();

        $CustomerQuestionnaire = new SampleMtbConfig();
        $CustomerQuestionnaire->setId('2');
        $CustomerQuestionnaire->setName('テスト2');
        $CustomerQuestionnaire->setSortNo('2');
        $em->persist($CustomerQuestionnaire);
        $em->flush();

        $CustomerQuestionnaire = new SampleMtbConfig();
        $CustomerQuestionnaire->setId('3');
        $CustomerQuestionnaire->setName('テスト3');
        $CustomerQuestionnaire->setSortNo('3');
        $em->persist($CustomerQuestionnaire);
        $em->flush();

        $CustomerQuestionnaire = new SampleMtbConfig();
        $CustomerQuestionnaire->setId('4');
        $CustomerQuestionnaire->setName('テスト4');
        $CustomerQuestionnaire->setSortNo('4');
        $em->persist($CustomerQuestionnaire);
        $em->flush();

    }

    /**
     *
     * @param array $meta
     * @param ContainerInterface $container
     */
    public function enable(array $meta, ContainerInterface $container) {
    }

    /**
     *
     * @param array $meta
     * @param ContainerInterface $container
     */
    public function disable(array $meta, ContainerInterface $container) {
    }
}

```

#プラグインインストール
以上のコードを記述後、プラグインをインストールすれば(mtb_sample)が生成されます。
マスターデータ管理にも以下のように追加されて編集出来るようになりました。
![03_マスターデータ管理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355704/5ffb468d-3594-0444-3642-4c18d99be23e.png)


#参考サイト
https://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=22996&forum=10


#最後に
拙い記事を最後まで見ていただきありがとうございました。