# 機能設計書 65-DoctrineBridge

## 概要

本ドキュメントは、Symfony Doctrine Bridgeの機能設計書である。Doctrine BridgeはDoctrineライブラリ（ORM、DBAL、Persistence）とSymfonyフレームワークを統合するブリッジコンポーネントである。

### 本機能の処理概要

Doctrine Bridgeは、Doctrineのエンティティマネージャー、リポジトリ、クエリビルダーなどの機能をSymfonyのForm、Validator、Security、Messenger、ArgumentResolverなど各コンポーネントと統合する。

**業務上の目的・背景**：Doctrineは最も広く使用されるPHP ORM/DBALライブラリであり、Symfonyアプリケーションのデータ永続化の中核を担う。Doctrine Bridgeはこの連携を提供し、Form Type、バリデーション制約、ユーザープロバイダー、データコレクター等の統合機能を実現する。

**機能の利用シーン**：
- FormコンポーネントでEntityTypeを使用してDoctrineエンティティの選択フォームを構築
- UniqueEntityバリデーションでデータベースレベルの一意性制約を検証
- EntityValueResolverでルートパラメータからエンティティを自動解決
- DoctrineDataCollectorでクエリ情報をWeb Profilerに表示
- Security UserProviderでDoctrineからユーザーを読み込む

**主要な処理内容**：
1. ManagerRegistry - DIコンテナとDoctrineマネージャーの統合
2. Form統合 - EntityType / DoctrineType / DoctrineOrmTypeGuesser
3. Validator統合 - UniqueEntity制約 / DoctrineInitializer / DoctrineLoader
4. ArgumentResolver - EntityValueResolver（MapEntityアトリビュート対応）
5. DataCollector - DoctrineDataCollector（クエリプロファイリング）
6. Security - EntityFactory（UserProvider）
7. Messenger統合 - DoctrineTransactionMiddleware等
8. PropertyInfo統合 - DoctrineExtractor
9. Type統合 - DatePointType等のDoctrineカスタム型

**関連システム・外部連携**：Doctrine ORM/DBAL/Persistence、Symfony Form、Validator、Security、Messenger、PropertyInfo

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | Doctrineパネル | 主機能 | DoctrineDataCollectorによるDB操作のプロファイリング表示 |

## 機能種別

フレームワーク統合 / ORMブリッジ

## 入力仕様

### 入力パラメータ（EntityType）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| class | string | Yes | エンティティクラスのFQCN | Doctrineマネージド |
| em | string/null | No | エンティティマネージャー名 | null=デフォルト |
| query_builder | callable/QueryBuilder/null | No | カスタムクエリビルダー | QueryBuilderインスタンスまたはcallable |
| choice_label | string/callable/null | No | 選択肢のラベル | - |
| choice_value | string/callable/null | No | 選択肢の値 | - |

### 入力パラメータ（UniqueEntity）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fields | array/string | Yes | 一意性をチェックするフィールド | 1つ以上のフィールド名 |
| message | string | No | エラーメッセージ | デフォルト: 'This value is already used.' |
| em | string/null | No | エンティティマネージャー名 | null=デフォルト |
| repositoryMethod | string | No | チェック用メソッド名 | デフォルト: 'findBy' |
| errorPath | string/null | No | エラー紐付けフィールド | null=fieldsの先頭 |
| ignoreNull | bool/array/string | No | NULL値の無視設定 | デフォルト: true |

### 入力データソース

Doctrineエンティティマネージャー（データベース）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| EntityType選択肢 | ChoiceListView | エンティティ一覧の選択肢 |
| UniqueEntityバリデーション結果 | ConstraintViolation | 一意性違反の場合のバリデーションエラー |
| EntityValueResolver結果 | object | ルートパラメータから解決されたエンティティ |
| DoctrineDataCollector | array | クエリ実行情報（SQL、パラメータ、実行時間） |

### 出力先

Symfony各コンポーネント（Form、Validator、HttpKernel、Profiler）

## 処理フロー

### 処理シーケンス（EntityType）

```
1. EntityType::configureOptions()
   └─ query_builderノーマライザーの設定
2. DoctrineType::configureOptions()
   └─ ChoiceListのファクトリ設定
3. フォームビルド時
   └─ DoctrineChoiceLoader::loadChoiceList()
   └─ ORMQueryBuilderLoader::getEntities() → QueryBuilder::getQuery()::execute()
4. 選択肢表示
   └─ IdReader::getIdValue() でエンティティIDを取得
```

### フローチャート

```mermaid
flowchart TD
    A[EntityType設定] --> B[OptionsResolver::resolve]
    B --> C[query_builderノーマライザー]
    C --> D{callableか?}
    D -->|Yes| E[Repository取得→callable実行]
    D -->|No| F[そのまま使用]
    E --> G[QueryBuilder]
    F --> G
    G --> H[ORMQueryBuilderLoader]
    H --> I[DoctrineChoiceLoader::loadChoiceList]
    I --> J[QueryBuilder::execute]
    J --> K[エンティティ一覧]
    K --> L[選択肢リスト生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | query_builder正規化 | callableの場合はrepositoryを引数に呼び出してQueryBuilderを取得 | EntityType設定時 |
| BR-02 | UniqueEntityのNULL無視 | ignoreNull=trueの場合、NULLフィールドは一意性チェックから除外 | UniqueEntityバリデーション時 |
| BR-03 | ManagerRegistryのリセット | LazyObjectInterfaceのresetLazyObject()またはReflectionClassのresetAsLazy*()でマネージャーをリセット | マネージャーリセット時 |
| BR-04 | EntityValueResolverの解決 | MapEntityアトリビュートの設定に基づきルートパラメータからエンティティを取得 | HTTPリクエスト処理時 |

### 計算ロジック

特になし。

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| EntityType | エンティティテーブル | SELECT | 選択肢一覧取得 |
| UniqueEntity | エンティティテーブル | SELECT | 一意性チェック |
| EntityValueResolver | エンティティテーブル | SELECT | エンティティ解決 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_UNIQUE_ERROR | ConstraintViolation | UniqueEntity制約違反 | フィールド値の修正 |
| UnexpectedTypeException | FormException | query_builderがQueryBuilderでない | 正しい型を返すcallableを使用 |
| LogicException | LogicException | 非Lazyマネージャーのリセット試行 | サービスをlazyで宣言 |

### リトライ仕様

該当なし。

## トランザクション仕様

DoctrineTransactionMiddlewareでMessengerメッセージ処理をトランザクションで囲む。

## パフォーマンス要件

- DoctrineChoiceLoaderはChoiceListをキャッシュし、同一フォーム内での重複クエリを防止
- ProxyCacheWarmerでDoctrineプロキシクラスを事前生成

## セキュリティ考慮事項

- EntityFactoryによるDoctrineベースのユーザープロバイダーでSecurity統合

## 備考

- RegisterDatePointTypePassでClockコンポーネントのDatePoint型をDoctrine型として登録
- RegisterUidTypePassでUidコンポーネントの各UUID型をDoctrine型として登録

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MapEntity.php | `src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php` | EntityValueResolver用のアトリビュート定義 |
| 1-2 | UniqueEntity.php | `src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php` | 一意性制約の定義（fields, message, em, repositoryMethod, errorPath, ignoreNull） |

**読解のコツ**: UniqueEntity（22行目）はATTRIBUTE::TARGET_CLASS | IS_REPEATABLEとしてクラスレベルで複数適用可能。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ManagerRegistry.php | `src/Symfony/Bridge/Doctrine/ManagerRegistry.php` | DIコンテナとDoctrineマネージャーの統合、resetService() |

**主要処理フロー**:
- **27-29行目**: getService() - DIコンテナからサービス取得
- **31-89行目**: resetService() - LazyObjectInterface対応のマネージャーリセット

#### Step 3: Form統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DoctrineType.php | `src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php` | Doctrine基底フォーム型 |
| 3-2 | EntityType.php | `src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php` | ORM EntityType |
| 3-3 | DoctrineChoiceLoader.php | `src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php` | 選択肢ローダー |
| 3-4 | ORMQueryBuilderLoader.php | `src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php` | ORM QBローダー |
| 3-5 | DoctrineOrmTypeGuesser.php | `src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php` | フォーム型推測 |

**主要処理フロー**:
- **EntityType 30-40行目**: query_builderノーマライザー。callableの場合はrepositoryを引数に実行
- **EntityType 51-58行目**: getLoader()。ORMQueryBuilderLoaderを生成

#### Step 4: Validator統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | UniqueEntity.php | `src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php` | 制約定義 |
| 4-2 | UniqueEntityValidator.php | `src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php` | バリデーター実装 |
| 4-3 | DoctrineInitializer.php | `src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php` | Doctrineプロキシ初期化 |
| 4-4 | DoctrineLoader.php | `src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php` | メタデータローダー |

#### Step 5: その他統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | EntityValueResolver.php | `src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php` | ルートパラメータからエンティティ解決 |
| 5-2 | DoctrineDataCollector.php | `src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php` | クエリプロファイリング |

### プログラム呼び出し階層図

```
Doctrine Bridge
    │
    ├─ Form統合
    │      ├─ EntityType::configureOptions()
    │      │      └─ DoctrineType::configureOptions()
    │      │             └─ DoctrineChoiceLoader
    │      │                    └─ ORMQueryBuilderLoader::getEntities()
    │      │                           └─ QueryBuilder::getQuery()::execute()
    │      └─ DoctrineOrmTypeGuesser::guessType()
    │
    ├─ Validator統合
    │      ├─ UniqueEntityValidator::validate()
    │      │      └─ EntityManager::getRepository()::findBy()
    │      ├─ DoctrineInitializer::initialize()
    │      │      └─ ObjectManager::initializeObject()
    │      └─ DoctrineLoader::loadClassMetadata()
    │
    ├─ ArgumentResolver統合
    │      └─ EntityValueResolver::resolve()
    │             └─ ObjectRepository::findOneBy() / find()
    │
    ├─ Security統合
    │      └─ EntityFactory::createUserProvider()
    │
    └─ DataCollector統合
           └─ DoctrineDataCollector::collect()
                  └─ DebugStack::$queries
```

### データフロー図

```
[入力]                         [処理]                           [出力]

フォーム設定(class,QB)  ───▶  EntityType                  ───▶  ChoiceListView
                              └─ DoctrineChoiceLoader
                              └─ DB SELECT

エンティティ            ───▶  UniqueEntityValidator       ───▶  ConstraintViolation
                              └─ Repository::findBy()

HTTPリクエスト          ───▶  EntityValueResolver         ───▶  Entity object
(route params)                └─ Repository::findOneBy()

DBクエリログ           ───▶  DoctrineDataCollector       ───▶  Profilerパネル
                              └─ DebugStack
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ManagerRegistry.php | `src/Symfony/Bridge/Doctrine/ManagerRegistry.php` | ソース | DI統合 |
| EntityType.php | `src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php` | ソース | ORM EntityType |
| DoctrineType.php | `src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php` | ソース | 基底DoctrineType |
| DoctrineChoiceLoader.php | `src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php` | ソース | 選択肢ローダー |
| ORMQueryBuilderLoader.php | `src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php` | ソース | QBローダー |
| DoctrineOrmTypeGuesser.php | `src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php` | ソース | 型推測 |
| UniqueEntity.php | `src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php` | ソース | 一意性制約 |
| UniqueEntityValidator.php | `src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php` | ソース | 一意性バリデーター |
| DoctrineInitializer.php | `src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php` | ソース | プロキシ初期化 |
| DoctrineLoader.php | `src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php` | ソース | メタデータローダー |
| EntityValueResolver.php | `src/Symfony/Bridge/Doctrine/ArgumentResolver/EntityValueResolver.php` | ソース | エンティティ解決 |
| MapEntity.php | `src/Symfony/Bridge/Doctrine/Attribute/MapEntity.php` | ソース | アトリビュート定義 |
| DoctrineDataCollector.php | `src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php` | ソース | クエリプロファイリング |
| EntityFactory.php | `src/Symfony/Bridge/Doctrine/DependencyInjection/Security/UserProvider/EntityFactory.php` | ソース | UserProvider |
| ContainerAwareEventManager.php | `src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php` | ソース | DIコンテナ対応EventManager |
| ProxyCacheWarmer.php | `src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php` | ソース | プロキシ事前生成 |
