Symfonyを触り始めた人へのDoctrine (ORM) 入門5:継承編

Symfonyを触り始めた人へのDoctrine (ORM) 入門5:継承編

こんにちは!くじらシステム開発の鶴田です。
今回は、Symfonyで利用するDoctrine ORMの「継承」機能について解説します。この記事では、実際に使ってみた経験を基に、分かりやすく手順を説明していきます。

Doctrineの継承とは?

Doctrineの継承機能を使うと、共通のフィールドやロジックを1つの親クラスにまとめ、子クラスでそれを継承して拡張・変更することができます。
これにより、次のようなメリットがあります:

  • コードの重複削減: 同じフィールドやロジックを複数のエンティティで重複して記述する必要がなくなります。
  • メンテナンス性向上: 親クラスを修正するだけで、すべての子クラスに変更を反映できます。

Doctrineにおける継承の種類

Doctrineには、以下の3つの継承パターンがあります:

  1. Simple Inheritance (単一テーブル継承)
    1つのテーブルにすべてのフィールドを保持します。シンプルで効率的ですが、テーブルが大きくなることがあります。
  2. Concrete Inheritance (具象テーブル継承)
    親クラスはテーブルを持たず、子クラスごとに独立したテーブルが生成されます。
  3. Class Table Inheritance (クラステーブル継承)
    親クラスと子クラスそれぞれに対応するテーブルを作り、JOINを使ってデータを管理します。

今回は、最も一般的で使いやすいSimple inheritanceを中心に説明します。

実装手順

サンプルデータ概要

  • 共通情報 (親クラス): ユーザー名 (name)、作成日時 (createdAt)、ID (id)
  • 特化情報 (子クラス): 管理者専用のメールアドレス (email) と管理レベル (adminLevel)

1. 継承元のマッピングファイル作成

まず、親クラスとなる基底クラスのマッピングファイルを作成します。
この基底クラスは、他のエンティティで共通して使用するフィールドを定義します。

User.orm.yml

User:
  type: mappedSuperclass
  fields:
    id:
      type: integer
      id: true
      generator:
        strategy: AUTO
    name:
      type: string
      length: 255
    createdAt:
      type: datetime
      column: created_at
ポイント:
  • type: mappedSuperclass
    この指定により、このクラス自体はエンティティとしては使用されず、他のクラスで継承されることを示します。
  • 共通フィールド
    ユーザー名 (name) や作成日時 (createdAt) を定義しています。

2. 継承先のマッピングファイル作成

次に、基底クラスを継承する具象クラスのマッピングファイルを作成します。
ここでは、Admin エンティティを例にします。

Admin.orm.yml

Admin:
  type: entity
  table: admin
  extends: User
  fields:
    email:
      type: string
      length: 255
      unique: true
    adminLevel:
      type: integer
      column: admin_level
ポイント:
  • extends: User
    親クラス (User) を継承します。

3. エンティティクラスの作成

マッピングファイルに対応するPHPクラスを作成します。

User.php (基底クラス)
abstract class User
{
    protected $id;
    protected $name;
    protected $createdAt;
    public function __construct()
    {
        $this->createdAt = new \DateTime();
    }
    // ゲッターとセッター
    public function getId() { return $this->id; }
    public function getName() { return $this->name; }
    public function setName($name) { $this->name = $name; }
}
Admin.php (具象クラス)
class Admin extends User
{
    private $email;
    private $adminLevel;
    // ゲッターとセッター
    public function getEmail() { return $this->email; }
    public function setEmail($email) { $this->email = $email; }
    public function getAdminLevel() { return $this->adminLevel; }
    public function setAdminLevel($level) { $this->adminLevel = $level; }
}

使用例

作成したエンティティを使用する例を示します。

// EntityManagerの取得
$entityManager = // DoctrineのEntityManagerインスタンスを取得
// Adminエンティティのインスタンスを生成
$admin = new Admin();
$admin->setName('山田太郎');
$admin->setEmail('yamada@example.com');
$admin->setAdminLevel(1);
// 保存処理
$entityManager->persist($admin);
$entityManager->flush();

まとめ

Doctrineの継承機能を使うと、共通部分を効率よく再利用でき、管理が容易になります。特に複数のエンティティで似たようなフィールドを持つ場合、非常に便利です。

初めは複雑に感じるかもしれませんが、実際に試してみるとその利便性に気づくはずです。
ぜひ、自分のプロジェクトでDoctrineの継承を活用して、よりメンテナンス性の高いコードを実現してください!