【EC-CUBE 4】複数のテーブルを連携する方法

この記事では、以下のように2つのテーブルを関連付ける方法を紹介します。

「dtb_product_class」テーブルでは、以下のように「dtb_product」や「dtb_sale_type」などのテーブルとidで関連づいている。

dtb_product_classテーブル
dtb_product_class

「dtb_product_class」テーブルの「product_id」をクリックすると、以下のように関連づいたレコードが表示される。

dtb_productテーブルのID=1レコード
dtb_product / ID = 1の商品

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

開発前にデバッグモードの設定をお薦めします

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

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

目次

テーブル連携は、所有側と非所有側の両エンティティに関連性を定義する

EC-CUBEのフレームワークであるSymfonyでは、Doctrine ORMを使用することでエンティティ間に関連性(リレーションシップ)を定義できます。

例として、メーカーの基本情報を管理するMaker エンティティと、メーカーの詳細情報を管理する MakerInfo エンティティの間に関連性を持たせる場合、以下の2つの関係が考えられます。

ManyToOne

1つの MakerInfo は、1つの Maker に属します。

OneToMany

1つの Maker は複数の MakerInfo を持つことができます。

この関連性をDoctrineで表現する際、2つのエンティティのどちらが “所有者” であるかを明示します。
“所有者” は、実際にデータベースのテーブルに外部キーとしての関連性を持つ側です。

所有権を明示するためには、 mappedByinversedByという属性を記述します。

mappedBy

非所有側で使用。
属性値は、所有側のエンティティ内のプロパティ名を記述。

inversedBy

所有側で使用。
属性値は、非所有側のエンティティ内のプロパティ名を記述。

このケースでは、

  • MakerInfo エンティティが ManyToOne という関係で所有側
  • Maker エンティティは OneToMany という関係で非所有側

したがって、MakerInfo エンティティの ManyToOne アノテーションには inversedBy 属性を使用し、その値は Maker エンティティ内の関連プロパティ名(基本的には配列形式のプロパティ)を指定します。

例えば、Maker エンティティ内で private $MakerInfos; というプロパティ名を使用する場合、MakerInfo エンティティの ManyToOne アノテーションの inversedBy 属性の値は MakerInfos となります。

以下、実際の手順やコードを公開します。

実例)「dtb_maker」と「dtb_maker_info」テーブルを作成し、連携させる

メーカー名などを管理する「dtb_maker」と、各メーカーに紐づいた情報を管理する「dtb_maker_info」を作成します。
「dtb_maker_info」では、各レコードにmaker_idを割り振ることで「dtb_maker」と関連付けます。

作成&連携後のテーブル
dtb_maker(メーカー名やコードを管理するテーブル)
dtb_maker_info(各メーカーごとの情報を管理するテーブル)
例えば、id = 1 および id = 2の情報は maker_id = 1 つまり dtb_maker のid = 1(SampleCorp)と紐づいている。

テーブルの作成については こちらの記事 にて紹介していますので、本記事では連携部分を中心に解説します。

全体の流れ
  1. メーカーの基本情報を管理する Makerエンティティを作成し、サーバーにアップ。
  2. メーカーの詳細情報を管理する MakerInfoエンティティを作成し、サーバーにアップ。
  3. サーバーにSSH接続し、SQLを実行する。
STEP

Makerエンティティを作成する

以下のコードを記載した Makerエンティティを作成し、「app/Customize/Entity」にアップします。
エンティティの連携は、コードの後半部分で定義しています。

<?php

namespace Customize\Entity;

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

/**
 * Maker
 *
 * @ORM\Table(name="dtb_maker")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Entity(repositoryClass="Customize\Repository\MakerRepository")
 */
class Maker extends AbstractEntity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned":true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     *
     * メーカーの一意識別ID(自動連番)です。
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     *
     * メーカーの名前です。
     */
    private $name;

    /**
     * @var string|null
     *
     * @ORM\Column(name="code", type="string", length=8, nullable=true)
     *
     * メーカーのコードです。null(未入力)も許容されます。
     */
    private $code;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="create_date", type="datetimetz")
     *
     * メーカー情報の作成日時です。
     */
    private $create_date;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="update_date", type="datetimetz")
     *
     * メーカー情報の最終更新日時です。
     */
    private $update_date;
    
    /**
     * Get id.
     *
     * @return int
     * 
     * メーカーのIDを取得します。
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name.
     *
     * @param string $name
     *
     * @return Maker
     * 
     * メーカーの名前を設定します。
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name.
     *
     * @return string
     * 
     * メーカーの名前を取得します。
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set code.
     *
     * @param string|null $code
     *
     * @return Maker
     * 
     * メーカーのコードを設定します。null(未入力)も許容されます。
     */
    public function setCode($code = null)
    {
        $this->code = $code;

        return $this;
    }

    /**
     * Get code.
     *
     * @return string|null
     * 
     * メーカーのコードを取得します。
     */
    public function getCode()
    {
        return $this->code;
    }

    /**
     * Set createDate.
     *
     * @param \DateTime $createDate
     *
     * @return Maker
     * 
     * メーカー情報の作成日時を設定します。
     */
    public function setCreateDate($createDate)
    {
        $this->create_date = $createDate;

        return $this;
    }

    /**
     * Get createDate.
     *
     * @return \DateTime
     * 
     * メーカー情報の作成日時を取得します。
     */
    public function getCreateDate()
    {
        return $this->create_date;
    }

    /**
     * Set updateDate.
     *
     * @param \DateTime $updateDate
     *
     * @return Maker
     * 
     * メーカー情報の最終更新日時を設定します。
     */
    public function setUpdateDate($updateDate)
    {
        $this->update_date = $updateDate;

        return $this;
    }

    /**
     * Get updateDate.
     *
     * @return \DateTime
     * 
     * メーカー情報の最終更新日時を取得します。
     */
    public function getUpdateDate()
    {
        return $this->update_date;
    }

    // エンティティ連携のconstruct
    public function __construct()
    {
        $this->makerInfos = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // MakerInfoエンティティの連携
    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Customize\Entity\MakerInfo", mappedBy="maker")
     */
    private $makerInfos;

    /**
     * Makerに新しいMakerInfoを追加するメソッド
     *
     * @param \Customize\Entity\MakerInfo $makerInfo
     *
     * @return Maker
     */
    public function addMakerInfo(MakerInfo $makerInfo)
    {
        $this->makerInfos[] = $makerInfo;

        return $this;
    }

    /**
     * 特定のMakerInfoをMakerから削除するメソッド
     *
     * @param \Customize\Entity\MakerInfo $makerInfo
     *
     * @return boolean
     */
    public function removeMakerInfo(MakerInfo $makerInfo)
    {
        return $this->makerInfos->removeElement($makerInfo);
    }

    /**
     * 現在のMakerに関連付けられているすべてのMakerInfoを取得するメソッド
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getMakerInfos()
    {
        return $this->makerInfos;
    }
}

MakerInfoエンティティとの連携は、アノテーションで以下のようなことが示されています。

@ORM\OneToMany

MakerMakerInfoの間の関係が「一対多」であることを示します。
つまり、一つのMakerは複数のMakerInfoを持つことができます。

targetEntity=”Customize\Entity\MakerInfo”

連携対象となるエンティティを示します。

mappedBy=”maker”

MakerInfo側にmakerという名前のプロパティが存在し、そのプロパティを通じてこの関係が管理されていることを示します。

加えて、関連エンティティを操作するためのメソッドも定義しています。
これらのメソッドを使って、MakerMakerNoteの間の関係を管理できます。

addMakerInfo

新しいMakerInfoMakerに関連付けるためのメソッド。

removeMakerInfo

既存のMakerInfoの関連付けを解除するためのメソッド。

getMakerInfos

Makerに関連付けられているすべてのMakerInfoを取得するためのメソッド。

STEP

MakerInfoエンティティを作成する

続いて、以下のコードを記載した MakerInfoエンティティを作成し、「app/Customize/Entity」にアップします。

<?php

namespace Customize\Entity;

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

/**
 * MakerInfo
 *
 * @ORM\Table(name="dtb_maker_info")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
 * @ORM\HasLifecycleCallbacks()
 * @ORM\Entity(repositoryClass="Customize\Repository\MakerInfoRepository")
 */
class MakerInfo extends AbstractEntity
{
    /**
     * 一意の識別子(ID)
     *
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", options={"unsigned":true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * このMakerInfoが関連付けられているMakerエンティティ
     *
     * @var \Customize\Entity\Maker
     *
     * @ORM\ManyToOne(targetEntity="Customize\Entity\Maker", inversedBy="makerInfos")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="maker_id", referencedColumnName="id")
     * })
     */
    private $maker;

    /**
     * メーカーに関する追加情報
     *
     * @var string|null
     *
     * @ORM\Column(name="info", type="string", length=4000)
     */
    private $info;

    /**
     * エンティティが作成された日時
     *
     * @var \DateTime
     *
     * @ORM\Column(name="create_date", type="datetimetz")
     */
    private $create_date;

    /**
     * エンティティが最後に更新された日時
     *
     * @var \DateTime
     *
     * @ORM\Column(name="update_date", type="datetimetz")
     */
    private $update_date;

    /**
     * IDを取得します。
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Makerエンティティを設定します。
     *
     * @param \Customize\Entity\Maker|null $maker
     *
     * @return MakerInfo
     */
    public function setMaker(Maker $maker = null)
    {
        $this->maker = $maker;

        return $this;
    }

    /**
     * Makerエンティティを取得します。
     *
     * @return \Customize\Entity\Maker|null
     */
    public function getMaker()
    {
        return $this->maker;
    }

    /**
     * メーカー情報を設定します。
     *
     * @param string|null $info
     *
     * @return MakerInfo
     */
    public function setInfo($info = null)
    {
        $this->info = $info;

        return $this;
    }

    /**
     * メーカー情報を取得します。
     *
     * @return string|null
     */
    public function getInfo()
    {
        return $this->info;
    }

    /**
     * 作成日を設定します。
     *
     * @param \DateTime $createDate
     *
     * @return MakerInfo
     */
    public function setCreateDate($createDate)
    {
        $this->create_date = $createDate;

        return $this;
    }

    /**
     * 作成日を取得します。
     *
     * @return \DateTime
     */
    public function getCreateDate()
    {
        return $this->create_date;
    }

    /**
     * 更新日を設定します。
     *
     * @param \DateTime $updateDate
     *
     * @return MakerInfo
     */
    public function setUpdateDate($updateDate)
    {
        $this->update_date = $updateDate;

        return $this;
    }

    /**
     * 更新日を取得します。
     *
     * @return \DateTime
     */
    public function getUpdateDate()
    {
        return $this->update_date;
    }
}

Makerエンティティとの連携は、アノテーションで以下のようなことが示されています。

@ORM\ManyToOne

MakerInfoMaker と「多対一」の関係にあることを示します。
つまり、一つのMakerは複数のMakerInfoを持つことができます。

targetEntity=”Customize\Entity\Maker”

連携対象となるエンティティを示します。

inversedBy=”makerInfos”

Maker 側には、この関連を逆向きに参照するプロパティ makerInfos が存在することを示します。

@ORM\JoinColumns

MakerInfo テーブルの maker_id カラムは、Maker テーブルの id カラムと結合されています。

STEP

サーバーにSSH接続し、SQLを実行してテーブルを生成する

2つのエンティティをアップしたら、サーバーにSSH接続して以下コマンドを入力します。
(新規テーブルを作成する場合と手順は同じです。)

まずは以下コマンドでキャッシュを削除します。

bin/console cache:clear --no-warmup

実行すると、
[OK] Cache for the ・・・・・・・ was successfully cleared.
というような文言が表示される。

次にデータベースを更新するためのSQLコマンドを入力します。

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

上は確認用のコマンドで、実行する場合は「–force」を付けた以下コマンドを入力します。

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

このコマンド実行後、問題がなければテーブルが新規作成(更新)されているはずです。

まとめ & 次のステップ

以上、複数のテーブルを関連付けて管理する方法を紹介しました。
本記事の例のように、テーブル同士を連携して管理したい場面は多々あると思いますので、ぜひ応用してもらえればと思います。

既存テーブルへの連携や、フォーム追加方法も以下に公開しているので、合わせてご覧ください。

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