# 機能設計書 22-データベース存在確認

## 概要

本ドキュメントは、Laravel Frameworkのデータベース存在確認機能（DatabasePresenceVerifier）の設計仕様を記載する。この機能は、バリデーションルール「exists」「unique」においてデータベースに対する存在確認・一意性検証を提供する。

### 本機能の処理概要

DatabasePresenceVerifierは、バリデーション処理の一部として、データベーステーブル内の値の存在確認や一意性検証を行う専用コンポーネントである。

**業務上の目的・背景**：アプリケーションにおいて、入力データがデータベースの参照整合性を満たしているかを検証することは重要である。例えば、外部キー参照先の存在確認（選択されたカテゴリIDが実在するか）、一意制約の事前チェック（メールアドレスの重複確認）など、データ投入前にDBレベルの整合性を検証することで、SQL制約違反エラーを未然に防ぎ、ユーザーフレンドリーなエラーメッセージを提供できる。

**機能の利用シーン**：ユーザー登録時のメールアドレス重複チェック、商品登録時のカテゴリID存在確認、注文処理時の商品ID有効性確認、管理画面でのマスタデータ参照整合性チェックなど、データベースとの整合性が必要なあらゆる入力バリデーションで利用される。

**主要な処理内容**：
1. getCount()メソッドで単一値の存在数をカウント（exists/uniqueルール用）
2. getMultiCount()メソッドで複数値の存在数をカウント（配列バリデーション用）
3. 追加条件（where句）の動的構築による柔軟な検索
4. NULL/NOT_NULL条件や否定条件（!value）のサポート
5. 特定レコードの除外（unique検証時の自己除外）

**関連システム・外部連携**：Laravelのデータベース接続管理（ConnectionResolver）、クエリビルダとの連携。複数データベース接続のサポート。

**権限による制御**：本機能自体には権限制御はない。バリデーション処理として透過的に動作する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全入力フォーム画面 | 主画面 | exists/uniqueルール使用時のDB検証 |

## 機能種別

バリデーション / データベース検証

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| collection | string | Yes | テーブル名 | 有効なテーブル名 |
| column | string | Yes | カラム名 | 有効なカラム名 |
| value | string | Yes | 検索対象の値 | - |
| excludeId | int/null | No | 除外するレコードのID | 数値または'NULL' |
| idColumn | string/null | No | IDカラム名（デフォルト: 'id'） | 有効なカラム名 |
| extra | array | No | 追加のWHERE条件 | 配列 |

### 入力データソース

- バリデーションルールからの呼び出し（Validator経由）
- exists:table,column / unique:table,column ルール構文から解析

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| count | int | 条件に一致するレコード数 |

### 出力先

- Validatorに返却され、ルール判定に使用
- exists: count > 0 で成功
- unique: count === 0 で成功

## 処理フロー

### 処理シーケンス

```
1. Validatorからexists/uniqueルールで呼び出し
   └─ getCount()またはgetMultiCount()を実行

2. クエリビルダでSELECT文を構築
   └─ テーブルとカラムを指定
   └─ WHERE条件を追加
   └─ 除外IDがあれば追加条件

3. 追加条件（extra）を処理
   └─ NULL/NOT_NULL判定
   └─ 否定条件（!value）判定
   └─ 通常のWHERE条件追加

4. カウントクエリを実行
   └─ WritePdoを使用（レプリケーション遅延対策）

5. 結果をValidatorに返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Validatorからルール呼び出し]
    B --> C{ルール種別}
    C -->|exists| D[getCount呼び出し]
    C -->|unique| E[getCount呼び出し<br>excludeId付き]
    C -->|配列| F[getMultiCount呼び出し]
    D --> G[クエリビルダ生成]
    E --> G
    F --> G
    G --> H[WHERE条件追加]
    H --> I{追加条件あり?}
    I -->|Yes| J[addConditions処理]
    J --> K{条件タイプ}
    K -->|NULL| L[whereNull追加]
    K -->|NOT_NULL| M[whereNotNull追加]
    K -->|!value| N[where != 追加]
    K -->|通常| O[where = 追加]
    L --> P[count実行]
    M --> P
    N --> P
    O --> P
    I -->|No| P
    P --> Q[結果返却]
    Q --> R[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 存在確認 | テーブル内に指定値が1件以上存在すれば成功 | existsルール |
| BR-02 | 一意性確認 | テーブル内に指定値が0件であれば成功 | uniqueルール |
| BR-03 | 自己除外 | uniqueルールで更新時は自身のレコードを除外 | excludeId指定時 |
| BR-04 | NULL条件 | 'NULL'文字列はwhereNull条件として処理 | extra条件で'NULL'指定時 |
| BR-05 | NOT_NULL条件 | 'NOT_NULL'文字列はwhereNotNull条件として処理 | extra条件で'NOT_NULL'指定時 |
| BR-06 | 否定条件 | '!'で始まる値は不等号条件として処理 | extra条件で'!'prefix指定時 |

### 計算ロジック

- getCount: COUNT(*)相当のカウントクエリ
- getMultiCount: COUNT(DISTINCT column)で重複を除いたカウント

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| exists検証 | 指定テーブル | SELECT | 値の存在確認 |
| unique検証 | 指定テーブル | SELECT | 値の一意性確認 |

### テーブル別操作詳細

#### 任意テーブル（ルールで指定）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT COUNT | 指定カラム | WHERE column = value | getCount |
| SELECT COUNT DISTINCT | 指定カラム | WHERE column IN (values) | getMultiCount |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| QueryException | DBエラー | テーブル/カラム不存在 | テーブル名・カラム名の確認 |
| ConnectionException | 接続エラー | DB接続失敗 | 接続設定の確認 |

### リトライ仕様

DB接続エラー時のリトライはデータベース接続管理の責務。PresenceVerifier自体にリトライ機能はなし。

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

SELECT専用のため、トランザクションは使用しない。ただし、WritePdoを使用することでレプリケーション遅延の影響を回避する。

## パフォーマンス要件

- 各クエリはインデックスを活用した高速検索が前提
- 大量データでもCOUNTクエリのため軽量
- 複数のexists/uniqueルールがある場合は複数回クエリが発行される

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

- SQLインジェクション対策：クエリビルダのパラメータバインディングを使用
- テーブル名・カラム名は信頼できるソースから取得すること
- 本番データへの不正アクセスを防ぐため、バリデーションルールは適切に設計すること

## 備考

- ValidationServiceProviderで'validation.presence'として登録される
- setConnection()で特定のDB接続を指定可能
- Closureを使用した複雑な条件指定も可能

---

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

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

### 推奨読解順序

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

まず、インターフェースと基本構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PresenceVerifierInterface.php | `src/Illuminate/Validation/PresenceVerifierInterface.php` | 存在確認の基本契約 |
| 1-2 | DatabasePresenceVerifierInterface.php | `src/Illuminate/Validation/DatabasePresenceVerifierInterface.php` | DB接続設定の契約 |

**読解のコツ**: PresenceVerifierInterfaceはDB以外の実装（例：Elasticsearchなど）も想定した抽象化となっている。

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

サービスプロバイダでの登録を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ValidationServiceProvider.php | `src/Illuminate/Validation/ValidationServiceProvider.php` | PresenceVerifierの登録処理 |

**主要処理フロー**:
- **50-55行目**: registerPresenceVerifier()でシングルトン登録
- **52-54行目**: DatabasePresenceVerifierインスタンスを生成、ConnectionResolverを注入

#### Step 3: コア実装を理解する

DatabasePresenceVerifierの詳細実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DatabasePresenceVerifier.php | `src/Illuminate/Validation/DatabasePresenceVerifier.php` | メインの存在確認処理 |

**主要処理フロー**:
- **28-32行目**: コンストラクタでConnectionResolverを受け取る
- **45-54行目**: getCount()で単一値のカウントを実行
- **65-70行目**: getMultiCount()で複数値のカウントを実行
- **79-92行目**: addConditions()で追加条件を処理
- **102-113行目**: addWhere()でNULL/NOT_NULL/否定条件を処理
- **121-124行目**: table()でクエリビルダを取得、useWritePdo()を設定

#### Step 4: バリデーションルールとの連携を理解する

exists/uniqueルールからの呼び出しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ValidatesAttributes.php | `src/Illuminate/Validation/Concerns/ValidatesAttributes.php` | validateExists/validateUnique |
| 4-2 | Exists.php | `src/Illuminate/Validation/Rules/Exists.php` | Existsルールオブジェクト |
| 4-3 | Unique.php | `src/Illuminate/Validation/Rules/Unique.php` | Uniqueルールオブジェクト |

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

```
ValidationServiceProvider::registerPresenceVerifier()
    │
    └─ new DatabasePresenceVerifier(ConnectionResolver)

Validator::validateExists()
    │
    └─ DatabasePresenceVerifier::getCount()
           │
           ├─ table() ─── QueryBuilder
           │      └─ useWritePdo()
           │
           ├─ where(column, value)
           │
           └─ addConditions(extra)
                  └─ addWhere()
                         ├─ whereNull()
                         ├─ whereNotNull()
                         └─ where()

Validator::validateUnique()
    │
    └─ DatabasePresenceVerifier::getCount(excludeId)
           │
           └─ where(idColumn, '<>', excludeId)
```

### データフロー図

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

バリデーションルール
exists:users,email
    │
    ▼
DatabasePresenceVerifier::getCount()
    │
    ├─ table: 'users'
    ├─ column: 'email'
    └─ value: 入力値
           │
           ▼
    QueryBuilder
    SELECT COUNT(*) FROM users
    WHERE email = ?
           │
           ▼
    [結果]
    count: int ───▶ Validator
                    count > 0 → 成功
                    count = 0 → 失敗
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DatabasePresenceVerifier.php | `src/Illuminate/Validation/DatabasePresenceVerifier.php` | ソース | DB存在確認の実装 |
| PresenceVerifierInterface.php | `src/Illuminate/Validation/PresenceVerifierInterface.php` | インターフェース | 契約定義 |
| DatabasePresenceVerifierInterface.php | `src/Illuminate/Validation/DatabasePresenceVerifierInterface.php` | インターフェース | DB接続契約 |
| ValidationServiceProvider.php | `src/Illuminate/Validation/ValidationServiceProvider.php` | ソース | サービス登録 |
| ValidatesAttributes.php | `src/Illuminate/Validation/Concerns/ValidatesAttributes.php` | ソース | ルール実装 |
| Exists.php | `src/Illuminate/Validation/Rules/Exists.php` | ソース | Existsルールクラス |
| Unique.php | `src/Illuminate/Validation/Rules/Unique.php` | ソース | Uniqueルールクラス |
| DatabaseRule.php | `src/Illuminate/Validation/Rules/DatabaseRule.php` | ソース | DB系ルール基底トレイト |
