# 帳票設計書 16-StateMachine Graphviz図

## 概要

本ドキュメントは、Symfony Workflowコンポーネントにおけるステートマシン型ワークフローのGraphviz可視化機能（`StateMachineGraphvizDumper`）の設計仕様を定義する。ステートマシン型ワークフローをGraphviz DOT形式で出力する（StateMachine専用レイアウト）。

### 本帳票の処理概要

StateMachineGraphvizDumperは、GraphvizDumperを継承し、ステートマシン型ワークフロー向けに最適化されたDOT出力を行う。通常のワークフローDumperとの主な違いは、トランジションノードを独立して描画せず、プレース間を直接エッジで接続する点にある。

**業務上の目的・背景**：ステートマシンは一度に一つの状態のみを持つシンプルな状態遷移モデルである。通常のワークフロー図ではトランジションが独立ノードとして表示されるが、ステートマシンではプレース間を直接矢印で結ぶほうが直感的で理解しやすい。StateMachineGraphvizDumperはこのレイアウトの違いを実現する。

**帳票の利用シーン**：ステートマシン型のワークフロー（例: 注文ステータス管理、承認フロー）の状態遷移図を可視化する場合に使用される。`workflow:dump`コマンドでステートマシン型ワークフローを指定した場合にも利用される。

**主要な出力内容**：
1. Graphviz DOTグラフ宣言
2. プレース（状態）ノード定義（円形ノード）
3. プレース間の直接エッジ（トランジション名をラベルとして表示）
4. メタデータに基づくスタイルカスタマイズ

**帳票の出力タイミング**：`workflow:dump`コマンド実行時（ステートマシン型の場合）、またはプログラム内でDumperを直接呼び出した場合。

**帳票の利用者**：アプリケーション開発者、業務設計者。

## 帳票種別

Graphviz DOT形式テキスト出力（ステートマシン状態遷移図）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `bin/console workflow:dump {name} --dump-format=dot` | コマンド実行 |
| N/A | プログラム呼び出し | API呼び出し | StateMachineGraphvizDumper::dump() |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | DOT（Graphviz） |
| 用紙サイズ | N/A |
| 向き | 左から右（LR）（デフォルト、親クラスから継承） |
| ファイル名 | 任意 |
| 出力方法 | 文字列として返却 |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

通常のワークフローGraphvizDumperとは異なり、トランジションノードを生成せず、プレース間を直接エッジで接続する。

```
┌─────────────────────────────────────┐
│  digraph workflow {                 │
│    グラフ/ノード/エッジオプション     │
├─────────────────────────────────────┤
│    place_xxx [label="..." circle]   │
│    place_yyy [label="..." circle]   │
│    (プレースノード定義のみ)          │
├─────────────────────────────────────┤
│    place_xxx -> place_yyy           │
│       [label="transition_name"]     │
│    (プレース間の直接エッジ)          │
├─────────────────────────────────────┤
│  }                                  │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | digraph宣言 | 有向グラフの開始 | 親クラスのstartDot() | `digraph workflow {` |
| 2 | ラベル | グラフのタイトル | 親クラスのformatLabel() | `label="..."` |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | プレースノード | 各プレース | 親クラスのfindPlaces() | `place_xxx [label="...", circle]` | N/A |
| 2 | エッジ | プレース間の直接接続 | findEdges()のオーバーライド | `place_xxx -> place_yyy [label="..."]` | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | グラフ閉じ | 有向グラフの終了 | 親クラスのendDot() | `}` |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| Definition | ワークフロー定義オブジェクト | Yes |
| Marking | 現在のマーキング状態 | No |
| with-metadata | メタデータ表示フラグ | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | プレース | 定義順 |
| 2 | エッジ | from プレース順 |

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを直接参照しない。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | N/A | N/A |

### テーブル別参照項目詳細

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| エッジの構築 | from x to の全組み合わせ | N/A | 各fromプレースから各toプレースへの直接エッジ（行68-77） |
| フォント色 | metadataのcolorキー | N/A | トランジションラベルの色設定（行59-61） |
| 矢印色 | metadataのarrow_colorキー | N/A | エッジの色設定（行63-65） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[dump呼び出し] --> B[オプション処理]
    B --> C[findPlaces - プレース検出 - 親クラス]
    C --> D[findEdges - エッジ検出 - オーバーライド]
    D --> E[startDot - 親クラス]
    E --> F[addPlaces - 親クラス]
    F --> G[addEdges - オーバーライド]
    G --> H[endDot - 親クラス]
    H --> I[DOT文字列返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| N/A | 特にエラーハンドリングなし | N/A | ワークフロー定義が正しいことを前提 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数十プレース、数十トランジション |
| 目標出力時間 | 1秒以内 |
| 同時出力数上限 | 制限なし |

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

- 親クラスと同様、出力にはワークフロー名、プレース名、トランジション名が含まれる
- escape()メソッドによるエスケープ処理（親クラスから継承）

## 備考

- GraphvizDumperを継承し、dump(), findEdges(), addEdges()の3メソッドをオーバーライド
- 通常のワークフローとの最大の違いは、トランジションノードを生成しない点
- findTransitions()は呼び出されず、代わりにfindEdges()でプレース間の直接エッジを生成

---

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

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

### 推奨読解順序

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

親クラスGraphvizDumperのデータ構造を先に理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | 親クラスのデフォルトオプションとプレース/トランジション構造（行30-34） |
| 1-2 | DumperInterface.php | `src/Symfony/Component/Workflow/Dumper/DumperInterface.php` | インターフェース定義（行28） |

**読解のコツ**: StateMachineGraphvizDumperは親クラスの多くのメソッドを再利用するため、先に親クラスを理解することが重要。

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

dump()メソッドのオーバーライドが処理の起点。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StateMachineGraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php` | dump()メソッド（行28-43）。トランジションノード生成をスキップする点に注目 |

**主要処理フロー**:
1. **行30**: with-metadataオプション取得
2. **行32**: 親クラスのfindPlaces()呼び出し
3. **行33**: オーバーライドしたfindEdges()呼び出し（findTransitionsは呼ばない）
4. **行39-42**: startDot + addPlaces + addEdges + endDot（addTransitionsは呼ばない）

#### Step 3: エッジ生成のオーバーライドを理解する

findEdges()のオーバーライドでプレース間直接エッジを生成する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StateMachineGraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php` | findEdges()（行48-81）でfromプレースをキーとするエッジ配列を生成 |

**主要処理フロー**:
- **行54-57**: トランジション名とスタイル（label, fontcolor）の取得
- **行59-65**: メタデータからcolor, arrow_color属性の取得
- **行68-76**: 全from-toの組み合わせでエッジ生成

#### Step 4: エッジ出力のオーバーライドを理解する

addEdges()でプレース間の直接エッジをDOT形式で出力する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | StateMachineGraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php` | addEdges()（行86-104）でplace_xxx -> place_yyy形式で出力 |

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

```
StateMachineGraphvizDumper::dump()
    |
    +-- [親] findPlaces()
    |       +-- Definition::getPlaces()
    |       +-- MetadataStore::getMetadata()
    |
    +-- [override] findEdges()
    |       +-- Definition::getTransitions()
    |       +-- Transition::getFroms(true)
    |       +-- Transition::getTos(true)
    |       +-- MetadataStore::getMetadata()
    |
    +-- [親] formatLabel()
    +-- [親] startDot()
    +-- [親] addPlaces()
    +-- [override] addEdges()
    |       +-- [親] dotize()
    |       +-- [親] escape()
    |       +-- [親] addAttributes()
    +-- [親] endDot()
```

### データフロー図

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

Definition ──────────> StateMachineGraphvizDumper::dump() ──> DOT文字列
  |-- Places                |                                  |-- digraph workflow {
  |-- Transitions           |-- findPlaces() [親]              |--   place_xxx [circle]
  |-- MetadataStore         |-- findEdges() [override]         |--   place_xxx -> place_yyy
Marking (optional) ──> +-- DOT組み立て                    |-- }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StateMachineGraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/StateMachineGraphvizDumper.php` | ソース | ステートマシン専用Graphvizダンプ |
| GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | ソース | 親クラス（ワークフロー用Graphvizダンプ） |
| DumperInterface.php | `src/Symfony/Component/Workflow/Dumper/DumperInterface.php` | ソース | ダンパーインターフェース |
| Definition.php | `src/Symfony/Component/Workflow/Definition.php` | ソース | ワークフロー定義 |
| Marking.php | `src/Symfony/Component/Workflow/Marking.php` | ソース | マーキング状態 |
| Transition.php | `src/Symfony/Component/Workflow/Transition.php` | ソース | トランジション定義 |
