# データベース設計書

## 概要

本ドキュメントは、Symfony 8.1フレームワークが内部的に使用するデータベーステーブルの設計を記載したものである。Symfonyはフレームワークとしてアプリケーション固有のエンティティを定義していないが、セッション管理、キャッシュ、ロック機構、Remember Me認証などの基盤機能において、データベーステーブルを使用する。これらのテーブルはフレームワーク利用者がオプションとして有効化することで自動作成またはマイグレーションにより作成される。

各テーブルはMySQL、PostgreSQL、SQLite、Oracle、SQL Serverなど複数のRDBMSに対応しており、プラットフォームごとにデータ型が異なる場合がある。本ドキュメントでは代表的なデータ型（MySQL基準）を記載し、プラットフォーム固有の差異は備考として補足する。

## テーブル一覧

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| rememberme_token | PersistentToken | Remember Me認証トークンの永続化テーブル |
| cache_items | - | キャッシュデータの永続化テーブル（DoctrineDbalAdapter / PdoAdapter用） |
| sessions | - | HTTPセッションデータの永続化テーブル（PdoSessionHandler用） |
| lock_keys | Key | 分散ロックのキー管理テーブル（DoctrineDbalStore / PdoStore用） |

## 各テーブル定義

### 1. rememberme_token

Remember Me（自動ログイン）機能で使用されるトークンを永続化するテーブル。ユーザーがログイン時に「次回から自動ログイン」を選択した際に発行されるトークンのシリーズID、トークン値、最終使用日時、ユーザー識別情報を保持する。`DoctrineTokenProvider` クラスによって管理される。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| series | CHAR(88) | NOT NULL | トークンシリーズID（主キー）。base64エンコードされたランダムバイト列で一意に識別 |
| value | CHAR(88) | NOT NULL | トークン値。認証検証に使用されるハッシュ値 |
| lastUsed | DATETIME | NOT NULL | トークンの最終使用日時 |
| class | VARCHAR(100) | NOT NULL (DEFAULT '') | ユーザークラス名。Symfony 8以前との後方互換性のために保持 |
| username | VARCHAR(200) | NOT NULL | ユーザー識別子（ユーザー名またはメールアドレス等） |

- 主キー: `series`
- 定義元: `src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php`

### 2. cache_items

Symfonyキャッシュコンポーネントがデータベースをバックエンドとして使用する際のキャッシュ保存テーブル。`DoctrineDbalAdapter` および `PdoAdapter` の両方で使用される。キャッシュID、データ（BLOB）、有効期限、タイムスタンプを保持する。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| item_id | VARBINARY(255) / VARCHAR(255) | NOT NULL | キャッシュアイテムの一意識別子（主キー）。MySQL: VARBINARY(255)、PostgreSQL: VARCHAR(255)、SQLite: TEXT |
| item_data | MEDIUMBLOB / BLOB / BYTEA | NOT NULL | キャッシュデータ本体。シリアライズされたバイナリデータ。MySQL: MEDIUMBLOB(16MB)、PostgreSQL: BYTEA、その他: BLOB |
| item_lifetime | INTEGER UNSIGNED | YES | キャッシュの有効期間（秒）。NULLの場合は無期限 |
| item_time | INTEGER UNSIGNED | NOT NULL | キャッシュアイテムの保存時刻（UNIXタイムスタンプ） |

- 主キー: `item_id`
- テーブル名・カラム名はオプションで変更可能（`db_table`, `db_id_col`, `db_data_col`, `db_lifetime_col`, `db_time_col`）
- 定義元: `src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php`, `src/Symfony/Component/Cache/Adapter/PdoAdapter.php`

### 3. sessions

PHPセッションデータをデータベースに永続化するためのテーブル。`PdoSessionHandler` によって管理される。セッションID、セッションデータ（バイナリ）、有効期限、最終更新タイムスタンプを保持する。行レベルロック、アドバイザリーロック、トランザクショナルロックの3つのロック戦略をサポートする。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| sess_id | VARBINARY(128) / VARCHAR(128) | NOT NULL | セッションID（主キー）。MySQL: VARBINARY(128)、PostgreSQL/Oracle/SQL Server: VARCHAR(128)、SQLite: TEXT |
| sess_data | BLOB / BYTEA | NOT NULL | セッションデータ。バイナリ形式で保存。MySQL/SQLite/Oracle: BLOB、PostgreSQL: BYTEA、SQL Server: VARBINARY(MAX) |
| sess_lifetime | INTEGER | NOT NULL | セッションの有効期限（UNIXタイムスタンプ）。この値より現在時刻が大きい場合、セッションは期限切れ |
| sess_time | INTEGER | NOT NULL | セッションの最終更新時刻（UNIXタイムスタンプ） |

- 主キー: `sess_id`
- インデックス: `sess_lifetime_idx` (`sess_lifetime`カラム)
- テーブル名・カラム名はオプションで変更可能（`db_table`, `db_id_col`, `db_data_col`, `db_lifetime_col`, `db_time_col`）
- 定義元: `src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php`

### 4. lock_keys

Symfonyロックコンポーネントがデータベースを使用した分散ロック機構で使用するテーブル。`DoctrineDbalStore` および `PdoStore` によって管理される。ロックキーのハッシュ値、トークン、有効期限を保持する。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| key_id | VARCHAR(64) | NOT NULL | ロックキーのSHA-256ハッシュ値（主キー）。MySQL: VARCHAR(64)、SQLite: TEXT、Oracle: VARCHAR2(64) |
| key_token | VARCHAR(44) / VARCHAR(64) | NOT NULL | ロックトークン。base64エンコードされた32バイトのランダム値。DoctrineDbalStore: VARCHAR(44)、PdoStore(pgsql等): VARCHAR(64) |
| key_expiration | INTEGER UNSIGNED / INTEGER | NOT NULL | ロックの有効期限（UNIXタイムスタンプ）。期限切れのロックはGCにより自動削除される |

- 主キー: `key_id`
- テーブル名・カラム名はオプションで変更可能（`db_table`, `db_id_col`, `db_token_col`, `db_expiration_col`）
- GC確率: デフォルト0.01（1%の確率で期限切れロックを削除）
- 定義元: `src/Symfony/Component/Lock/Store/DoctrineDbalStore.php`, `src/Symfony/Component/Lock/Store/PdoStore.php`, `src/Symfony/Component/Lock/Store/DatabaseTableTrait.php`

## 備考

### プラットフォーム別のデータ型差異

Symfonyは複数のデータベースプラットフォームをサポートしており、テーブル作成時にプラットフォームに応じてデータ型が自動的に選択される。以下に主要な差異を記す。

#### cache_items テーブル

| カラム | MySQL | PostgreSQL | SQLite | Oracle | SQL Server |
| --- | --- | --- | --- | --- | --- |
| item_id | VARBINARY(255) | VARCHAR(255) | TEXT | VARCHAR2(255) | VARCHAR(255) |
| item_data | MEDIUMBLOB | BYTEA | BLOB | BLOB | VARBINARY(MAX) |
| item_lifetime | INTEGER UNSIGNED | INTEGER | INTEGER | INTEGER | INTEGER |
| item_time | INTEGER UNSIGNED | INTEGER | INTEGER | INTEGER | INTEGER |

#### sessions テーブル

| カラム | MySQL | PostgreSQL | SQLite | Oracle | SQL Server |
| --- | --- | --- | --- | --- | --- |
| sess_id | VARBINARY(128) | VARCHAR(128) | TEXT | VARCHAR2(128) | VARCHAR(128) |
| sess_data | BLOB | BYTEA | BLOB | BLOB | VARBINARY(MAX) |
| sess_lifetime | INTEGER UNSIGNED | INTEGER | INTEGER | INTEGER | INTEGER UNSIGNED |
| sess_time | INTEGER UNSIGNED | INTEGER | INTEGER | INTEGER | INTEGER UNSIGNED |

#### lock_keys テーブル

| カラム | MySQL | PostgreSQL | SQLite | Oracle | SQL Server |
| --- | --- | --- | --- | --- | --- |
| key_id | VARCHAR(64) | VARCHAR(64) | TEXT | VARCHAR2(64) | VARCHAR(64) |
| key_token | VARCHAR(44) | VARCHAR(64) | TEXT | VARCHAR2(64) | VARCHAR(64) |
| key_expiration | INTEGER UNSIGNED | INTEGER | INTEGER | INTEGER | INTEGER |

### DynamoDB対応（Lock）

ロックコンポーネントにはAWS DynamoDBを使用する `DynamoDbStore` も存在する（`src/Symfony/Component/Lock/Bridge/DynamoDb/Store/DynamoDbStore.php`）。DynamoDBはNoSQLサービスであり、以下の属性を使用する。

| 属性名 | 型 | 説明 |
| --- | --- | --- |
| key_id | S (String) | ロックキーのハッシュ値（パーティションキー） |
| key_token | S (String) | ロックトークン |
| key_expiration | N (Number) | 有効期限（UNIXタイムスタンプ） |

### PostgreSQL アドバイザリーロック

`DoctrineDbalPostgreSqlStore` はテーブルを使用せず、PostgreSQL固有のアドバイザリーロック機構（`pg_advisory_lock`, `pg_try_advisory_lock`）を使用する。これは物理テーブルを作成しないため、本テーブル定義には含まない。

### Doctrine スキーマリスナー

Symfonyは `Symfony\Bridge\Doctrine\SchemaListener` 配下のリスナーを通じて、Doctrine MigrationsのDiffコマンド実行時にこれらのテーブルスキーマを自動的にマイグレーションに含めることができる。

- `PdoSessionHandlerSchemaListener`: sessionsテーブル
- `DoctrineDbalCacheAdapterSchemaListener`: cache_itemsテーブル
- `LockStoreSchemaListener`: lock_keysテーブル
- `RememberMeTokenProviderDoctrineSchemaListener`: rememberme_tokenテーブル
- `MessengerTransportDoctrineSchemaListener`: Messengerトランスポートテーブル（外部パッケージで定義）

### MySQLにおけるVARBINARY使用理由

`cache_items` および `sessions` テーブルのIDカラムにMySQLではVARBINARYが使用される理由は以下の通り。

- 文字セット変換の防止（サーバーとクライアント間）
- 末尾スペースの自動削除の防止
- 大文字小文字の区別
- 言語固有の文字処理（例: e == eの防止）の回避
