EC-CUBE4 プラグインの設定画面の作り方



作成したサンプルプラグインはGithubで公開しています。
https://github.com/takeshi-du/eccube4-plugin-sample

## 設定画面を作る
サンプルプラグインのファイル構造はこんな感じ。

```
app/Plugin/MyPlugin
    - Controller/MyPluginConfigController.php
    - Entity/MyPluginConfig.php
    - Form/Type/MyPluginConfigType.php
    - Repository/MyPluginConfigRepository.php
    - Resource/template/admin/config.twig
    - composer.json
    - PluginManager.php
```

各ファイルの中身はこんな感じ。ほとんどは定型文なので基本的にはコピペして独自の処理を追記する感じになると思います。

ファイルを作ったら圧縮してインストール。

圧縮方法とインストール方法はこちら。
https://qiita.com/takeshi_du/items/42b2059867e0b780695d

```php
// controller/MyPluginConfigController.php
<?php
/*
* Plugin Name : MyPlugin
*/

namespace Plugin\MyPlugin\Controller;

use Eccube\Controller\AbstractController;
use Plugin\MyPlugin\Form\Type\MyPluginConfigType;
use Plugin\MyPlugin\Repository\MyPluginConfigRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;

/**
 * Class ConfigController.
 */
class MyPluginConfigController extends AbstractController
{
    /**
     * @Route("/%eccube_admin_route%/my_plugin/config", name="my_plugin_admin_config")
     * @Template("@MyPlugin/admin/config.twig")
     *
     * @param Request $request
     * @param MyPluginConfigRepository $configRepository
     *
     * @return array
     */
    public function index(Request $request, MyPluginConfigRepository $configRepository)
    {
        // 設定情報、フォーム情報を取得
        $Config = $configRepository->get();
        $form = $this->createForm(MyPluginConfigType::class, $Config);
        $form->handleRequest($request);

        // 設定画面で登録ボタンが押されたらこの処理を行う
        if ($form->isSubmitted() && $form->isValid()) {
            // フォームの入力データを取得
            $Config = $form->getData();

            // フォームの入力データを保存
            $this->entityManager->persist($Config);
            $this->entityManager->flush($Config);

            // 完了メッセージを表示
            log_info('config', ['status' => 'Success']);
            $this->addSuccess('プラグインの設定を保存しました。', 'admin');

            // 設定画面にリダイレクト
            return $this->redirectToRoute('my_plugin_admin_config');
        }
        // テンプレートにデータを送る
        return [
            'Config' => $Config,
            'form' => $form->createView(),
        ];
    }
}
```

```php
// Entity/MyPluginConfig.php
<?php
/*
* Plugin Name : MyPlugin
*/

namespace Plugin\MyPlugin\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Entity\AbstractEntity;

/**
 * MyPluginConfig
 *
 * @ORM\Table(name="plg_my_plugin")
 * @ORM\Entity(repositoryClass="Plugin\MyPlugin\Repository\MyPluginConfigRepository")
 */
class MyPluginConfig extends AbstractEntity
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned":true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
   * @var string
   *
   * @ORM\Column(name="title", type="text", nullable=true)
   */
    private $title;

     /**
   * @var string
   *
   * @ORM\Column(name="color", type="text", nullable=true)
   */
    private $color;

    /**
     * Get id.
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set title.
     *
     * @param string $title
     *
     * @return MyPluginConfig
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Get title.
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * Set color.
     *
     * @param string $color
     *
     * @return MyPluginConfig
     */
    public function setColor($color)
    {
        $this->color = $color;

        return $this;
    }

    /**
     * Get color.
     *
     * @return string
     */
    public function getColor()
    {
        return $this->color;
    }
}
```

```php
// Form/Type/MyPluginConfigType.php
<?php
/*
* Plugin Name : MyPlugin
*/

namespace Plugin\MyPlugin\Form\Type;

use Eccube\Common\EccubeConfig;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyPluginConfigType extends AbstractType
{
    /**
     * @var EccubeConfig
     */
    protected $eccubeConfig;

    /**
    * @var ContainerInterface
    */
    protected $containerInterface;

    /**
     * MyPluginConfigType constructor.
     *
     * @param EccubeConfig $eccubeConfig
     */
    public function __construct(EccubeConfig $eccubeConfig, ContainerInterface $container)
    {
        $this->eccubeConfig = $eccubeConfig;
        $this->containerInterface = $container;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // フォームの定義
        $builder
        ->add('title', TextType::class, [
            'label' => 'title',
            'constraints' => [
                new Assert\NotBlank(),
            ],
        ])
        ->add('color', ChoiceType::class, [
            'label' => 'カラー設定',
            'choices' => array_flip([
                'blue' => '青',
                'red' => '赤',
            ]),
            'expanded' => false,
            'multiple' => false,
            'placeholder' => false,
            'constraints' => [
                new Assert\NotBlank(),
            ],
        ]);
    }
}
```

```php
// Repository/MyPluginConfigRepository.php
<?php
/*
* Plugin Name : MyPlugin
*/

namespace Plugin\MyPlugin\Repository;

use Eccube\Repository\AbstractRepository;
use Plugin\MyPlugin\Entity\MyPluginConfig;
use Symfony\Bridge\Doctrine\RegistryInterface;

/**
 * MyPlugin Config.
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class MyPluginConfigRepository extends AbstractRepository
{
    /**
     * MyPluginConfigRepository constructor.
     *
     * @param RegistryInterface $registry
     */
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, MyPluginConfig::class);
    }

    /**
     * @param int $id
     *
     * @return null|MyPluginConfig
     */
    public function get($id = 1)
    {
        return $this->find($id);
    }
}
```

```php
// Resource/template/admin/config.twig
{% extends '@admin/default_frame.twig' %}

{% set menus = ['store', 'plugin', 'plugin_list'] %}

{% block title %}MyPlugin{% endblock %}
{% block sub_title %}{% endblock %}

{% form_theme form '@admin/Form/bootstrap_4_horizontal_layout.html.twig' %}

{% block main %}

    <form method="post" action="{{ url('my_plugin_admin_config') }}">
        {{ form_widget(form._token) }}
        <div class="c-contentsArea__cols">
            <div class="c-contentsArea__primaryCol">
                <div class="c-primaryCol">
                    <div class="card rounded border-0 mb-4">
                        <div class="card-header">
                            <div class="row">
                                <div class="col-8">
                                    <div class="d-inline-block" data-toggle="tooltip" data-placement="top"
                                         title="Tooltip">
                                        <span class="card-title">MyPlugin</span>
                                    </div>
                                </div>
                                <div class="col-4 text-right">
                                    <a data-toggle="collapse" href="#basicConfig" aria-expanded="false"
                                       aria-controls="basicConfig">
                                        <i class="fa fa-angle-up fa-lg"></i>
                                    </a>
                                </div>
                            </div>
                        </div>
                        <div class="collapse show ec-cardCollapse" id="basicConfig">
                            <div class="card-body">
                                <div class="form-group row">
                                    <label class="col-2 control-label">タイトル</label>
                                    <div class="col-5">
                                        {{ form_widget(form.title) }}
                                        {{ form_errors(form.title) }}
                                    </div>
                                </div>
                                <div class="form-group row">
                                    <label class="col-2 control-label">カラー</label>
                                    <div class="col-5">
                                        {{ form_widget(form.color) }}
                                        {{ form_errors(form.color) }}
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="c-conversionArea">
            <div class="c-conversionArea__container">
                <div class="row justify-content-between align-items-center">
                    <div class="col-6">
                        <div class="c-conversionArea__leftBlockItem">
                            <a class="c-baseLink" href="{{ url('admin_store_plugin') }}"><i class="fa fa-backward" aria-hidden="true"></i>
                                <span>プラグイン一覧</span></a>
                        </div>
                    </div>
                    <div class="col-6">
                        <div class="row align-items-center justify-content-end">
                            <div class="col-auto">
                                <button class="btn btn-ec-conversion px-5" type="submit">登録</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </form>
{% endblock main %}
```

```php
// PluginManager.php
<?php
/*
* Plugin Name : MyPlugin
*/

namespace Plugin\MyPlugin;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Application;
use Eccube\Plugin\AbstractPluginManager;
use Plugin\MyPlugin\Entity\MyPluginConfig;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class PluginManager.
 */
class PluginManager extends AbstractPluginManager
{
    /**
     * PluginManager constructor.
     */
    public function __construct()
    {
    }

    /**
     * @param null|array $meta
     * @param ContainerInterface $container
     *
     * @throws \Exception
     */
    public function enable(array $meta = null, ContainerInterface $container)
    {
        // プラグイン設定を追加
        $em = $container->get('doctrine.orm.entity_manager');
        $Config = $this->createConfig($em);
    }

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

    /**
     * @param null $meta
     * @param Application|null $app
     * @param ContainerInterface $container
     *
     * @throws \Exception
     */
    public function uninstall(array $meta, ContainerInterface $container)
    {
    }

    /**
     * @param array|null $meta
     * @param ContainerInterface $container
     */
    public function update(array $meta = null, ContainerInterface $container)
    {
    }

    /**
     * 設定の登録.
     *
     * @param EntityManagerInterface $em
     */
    protected function createConfig(EntityManagerInterface $em)
    {
        $Config = $em->find(MyPluginConfig::class, 1);
        if ($Config) {
            return $Config;
        }
        // 初期値を保存
        $Config = new MyPluginConfig();
        $Config->setTitle('My Plugin');
        $Config->setColor('blue');
        $em->persist($Config);
        $em->flush($Config);

        return $Config;
    }
}

```

インストールできたら設定画面を開くとこんな感じになります。
<img width="703" alt="MyPlugin_-_EC-CUBE_SHOP.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549249/c01fa024-5ca3-6be1-290a-aa1112fef1fa.png">