【EC-CUBE 4】ドロップダウンリストの選択肢をデータベースから取得する方法

ドロップダウンリスト(セレクトボックス)とデータベースを連携する方法について紹介します。いちいち手動でリストを作る必要がなく、データベースが更新されればリストの内容も自動更新されるようになります。

カスタマイズ後の管理画面(商品登録)

管理画面(商品登録)をカスタマイズし、メーカーIDをドロップダウンリストで選択→登録できるようにしました。「dtb_maker」という新しいテーブルを新規作成し、そこに保存されているメーカー名をリストとして表示させています。

同じ環境で実装する場合は、事前に以下実装を完了してください。

「dtb_product」テーブルの拡張

こちらの記事では、「maker_id」ではなく「production_area」を追加しているので、ProductTrait.phpを以下に修正してください。

修正後の ProductTrait.php はこちら
<?php

namespace Customize\Entity;

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

/**
 * 拡張したいエンティティ(ここでは「Product」エンティティ)を指定。
 * 
 * @EntityExtension("Eccube\Entity\Product")
 */
trait ProductTrait
{
    /**
     * メーカーID
     * 
     * @var integer|null
     * 
     * @ORM\Column(name="maker_id", type="integer", nullable=true)
     */
    private $maker_id = null;

    /**
     * メーカーIDを設定
     * 
     * @param integer|null $maker_id
     * 
     * @return $this
     */
    public function setMakerId(?int $maker_id): self
    {
        $this->maker_id = $maker_id;
        return $this;
    }

    /**
     * メーカーIDを取得
     * 
     * @return integer|null
     */
    public function getMakerId(): ?int
    {
        return $this->maker_id;
    }
}
「dtb_maker」テーブルの新規作成

テーブル追加後は、実装確認用に適当データ(レコード)を追加しておいてください。

商品登録画面のフォームタイプ「ProductTypeExtension.php」の作成とtwigテンプレート「product.twig」の修正

こちらの記事では、「maker_id」ではなく「production_area」を追加しているので、product.twigを以下に修正してください。

修正後の product.twig はこちら
{# メーカーの登録フォーム #}
<div class="row">
    <div class="col-3">
        <div class="d-inline-block">
          <span>メーカーID</span>
        </div>
    </div>
    <div class="col mb-2">
        <div>
          {{ form_widget(form.maker_id) }}
          {{ form_errors(form.maker_id) }}
        </div>
    </div>
</div>
開発前にデバッグモードの設定をお薦めします

デバッグモードを設定しておくと、エラーが起きたときに詳細情報が表示されるようになります。
エラー箇所を探しやすくなるので、開発前に設定しておくのをオススメします。
デバッグモードの設定方法については 以下記事 で解説しています。

カスタマイズ後は、デバッグモードの解除を忘れないように。

【動作環境】
EC CUBEのバージョン:4.3.0
サーバー:XServer

目次

ドロップダウンリストを表示するフォームを作成する

まずはドロップダウンリストを表示するためのフォームを作成します。フォームタイプの作成については こちらの記事 で解説していますが、追加したいフォームタイプに以下コードを記述します。

$builder
  ->add('maker_id', ChoiceType::class, [
    'choices' =>
    [
      'SampleCorp' => 1,
      'Noveblo Ltd.' => 2,
      'TEST Company' => 3,
    ],
    'required' => false,
    'placeholder' => '選択してください'
  ]);

本記事の例では、こちらの記事で作成した「ProductTypeExtension.php」のaddメソッドを上記コードに修正しています。なお、ChoiceTypeを使うにはuseChoiceTypeクラスを読み込んでおく必要があるので、以下コードも忘れないようにしましょう。

use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
ProductTypeExtension.php 全コード
<?php

namespace Customize\Form\Extension\Admin;

use Eccube\Form\Type\Admin\ProductType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

class ProductTypeExtension extends AbstractTypeExtension
{
  // どのフォームを拡張するかを宣言(EC-CUBEのバージョンによって記述方法が異なる)
  public static function getExtendedTypes(): iterable
  {
      yield ProductType::class; // ProductTypeを拡張
  }

  public function buildForm(FormBuilderInterface $builder, array $options)
  {
      $builder
      ->add('maker_id', ChoiceType::class, [
        'choices' =>
        [
          'SampleCorp' => 1,
          'Noveblo Ltd.' => 2,
          'TEST Company' => 3,
        ],
        'required' => false,
        'placeholder' => '選択してください'
      ]);
    }
}

ただこのコードを見てわかるとおり、リストの内容は直接addメソッド内に記述されています。
次は、このリストをデータベースから取得できるようにします。

リストの内容をデータベースから取得する

データベースからデータを取得するには、Repositoryという機能を使います。

本記事の「dtb_maker」のような新規に作成したテーブルにはRepositoryがないので、まずはRepositoryを作成する必要があります。(すでに作成済の場合、以下はスキップしてください。)

Repositoryの新規作成

以下コードを記述した「MakerRepository.php」を作成し、「app/Customize/Repository」下に保存します。
EC-CUBEのバージョンによってコードが異なります。(4.2以降ではResistoryInterfaceが使えず、ManagerRegistryを使います。)

【EC-CUBE 4.0 / 4.1】のRepositoryファイルはこちら
<?php

namespace Customize\Repository;

use Customize\Entity\Maker;
use Eccube\Repository\AbstractRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;

/**
 * MakerRepository
 */
class MakerRepository extends AbstractRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Maker::class);
    }

}
【EC-CUBE 4.2以降】のRepositoryファイルはこちら
<?php

namespace Customize\Repository;

use Customize\Entity\Maker;
use Eccube\Repository\AbstractRepository;
use Doctrine\Persistence\ManagerRegistry as RegistryInterface;

/**
 * MakerRepository
 */
class MakerRepository extends AbstractRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Maker::class);
    }

}

Repositoryの作成と活用法については、以下記事も参考にしてみてください。

フォームタイプでRepositoryを使い、リストデータを取得する

Repositoryを用意できたら、フォームタイプを以下の通り修正していきます。
本記事では「ProductTypeExtension.php」を修正しています。

STEP

useでRepositoryを読み込む

使いたいRepositoryをuseで読み込みます。

use Customize\Repository\MakerRepository;

本記事では、先程作成したMakerRepositoryを読み込みます。

STEP

Repositoryの初期化設定

ProductTypeExtensionクラス内で、読み込んだRepositoryを初期化します。

class ProductTypeExtension extends AbstractTypeExtension
{
  /**
   * @var MakerRepository
   */
  protected $makerRepository;
  
  /**
   * @param MakerRepository $makerRepository
   */
  public function __construct(MakerRepository $makerRepository)
  {
      $this->makerRepository = $makerRepository;
  }

なお、ステップ1とステップ2については以下記事にて解説しています。

STEP

Repositoryを使ってリストデータを取得する

RepositoryのfindAll()メソッドを使って「dtb_maker」の全レコードを取得し、配列$choicesに「メーカー名 => ID」となるようデータを格納します。

$makers = $this->makerRepository->findAll();
$choices = array_combine(
    array_map(fn($maker) => $maker->getName(), $makers),
    array_map(fn($maker) => $maker->getId(), $makers)
);

なお、findAll()などRepositoryのメソッドについては以下記事にて解説しています。

STEP

取得したリストデータをaddメソッドにセットする

リストデータを格納した$choicesaddメソッドの'choices'にセットし、完成です。

$builder
  ->add('maker_id', ChoiceType::class, [
    'choices'  => $choices,
    'required' => false,
    'placeholder' => '選択してください'
  ]);

以上でカスタマイズは終了です。

上述のとおりフォームタイプの修正点が多く、コードの記述ミスや記述場所を間違いやすいです。
以下に「ProductTypeExtension.php」の全コードを載せておくので、参考にしてください。

ProductTypeExtension.php(修正後)
<?php

namespace Customize\Form\Extension\Admin;

use Eccube\Form\Type\Admin\ProductType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Customize\Repository\MakerRepository;

class ProductTypeExtension extends AbstractTypeExtension
{
    /**
     * @var MakerRepository
     */
    protected $makerRepository;

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

    /**
     * どのフォームを拡張するかを宣言(EC-CUBEのバージョンによって記述方法が異なる)
     *
     * @return iterable
     */
    public static function getExtendedTypes(): iterable
    {
        return [ProductType::class]; // ProductTypeを拡張
    }

    /**
     * フォームにメーカーIDの選択肢を追加
     *
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $makers = $this->makerRepository->findAll();
        $choices = array_combine(
            array_map(fn($maker) => $maker->getName(), $makers),
            array_map(fn($maker) => $maker->getId(), $makers)
        );

        $builder
            ->add('maker_id', ChoiceType::class, [
                'choices'  => $choices,
                'required' => false,
                'placeholder' => '選択してください',
            ]);
    }
}

まとめ

以上、ドロップダウンリスト(セレクトボックス)の選択肢をデータベースから取得する方法について紹介しました。

本記事で取り上げた実装例は、データベース拡張やRepository、FormTypeなど、Symfonyの基本的な機能が一通り理解できていないと難しいと思います。ぜひ他の記事を参考に、トライしてみてください!


よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次