# 帳票設計書 15-Graphvizワークフロー図

## 概要

本ドキュメントは、Symfony Workflowコンポーネントにおけるグラフィカルなワークフロー可視化機能（`GraphvizDumper`）の設計仕様を定義する。ワークフロー定義をGraphviz DOT形式で出力し、dotユーティリティでPNG等の画像に変換可能にする。

### 本帳票の処理概要

Workflow GraphvizDumperは、Symfonyのワークフロー定義（プレース、トランジション、エッジ）をGraphviz DOT言語形式で出力する。ワークフローの状態遷移図を可視化するためのツールである。

**業務上の目的・背景**：ワークフローは業務プロセスの状態遷移を定義する仕組みであり、その構造を可視化することで、業務フローの理解、設計レビュー、ドキュメント生成が容易になる。GraphvizDumperはワークフロー定義を標準的なGraphviz形式で出力し、様々な画像フォーマットへの変換を可能にする。

**帳票の利用シーン**：ワークフローの設計確認、ドキュメントへの図の埋め込み、コードレビュー時の状態遷移確認、現在のマーキング状態の可視化に使用される。`workflow:dump`コマンドの内部処理としても利用される。

**主要な出力内容**：
1. Graphviz DOTグラフ宣言（`digraph workflow`）
2. プレース（状態）ノード定義（円形ノード）
3. トランジション（遷移）ノード定義（ボックスノード）
4. エッジ定義（プレース-トランジション間の矢印）
5. メタデータ表示（オプション）

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

**帳票の利用者**：アプリケーション開発者、業務設計者、プロジェクトマネージャー。

## 帳票種別

Graphviz DOT形式テキスト出力（ワークフロー状態遷移図）

## 利用画面

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

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | DOT（Graphviz） |
| 用紙サイズ | N/A（グラフの自動レイアウト） |
| 向き | 左から右（LR）（デフォルト） |
| ファイル名 | 任意（例: `workflow.dot`） |
| 出力方法 | 文字列として返却 |
| 文字コード | UTF-8 |

### Graphviz固有設定

| 項目 | デフォルト値 |
|-----|------------|
| graph.ratio | compress |
| graph.rankdir | LR |
| node.fontsize | 9 |
| node.fontname | Arial |
| node.color | #333333 |
| node.fillcolor | lightblue |
| node.fixedsize | false |
| node.width | 1 |
| edge.fontsize | 9 |
| edge.fontname | Arial |
| edge.color | #333333 |
| edge.arrowhead | normal |
| edge.arrowsize | 0.5 |

## 帳票レイアウト

### レイアウト概要

プレース（円形）とトランジション（ボックス）がエッジで接続される有向グラフ。

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

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | digraph宣言 | 有向グラフの開始 | 固定値 | `digraph workflow {` |
| 2 | ラベル | グラフのタイトル | options['label'] + メタデータ | `label="..."` |
| 3 | graphオプション | グラフ全体オプション | options['graph'] | `ratio="compress" rankdir="LR"` |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | プレースノード | 各プレース（状態） | Definition.getPlaces() | `place_xxx [label="...", shape=circle]` | N/A |
| 2 | トランジションノード | 各トランジション | Definition.getTransitions() | `transition_xxx [label="...", shape=box]` | N/A |
| 3 | from エッジ | プレースからトランジションへ | Transition.getFroms() | `place_xxx -> transition_xxx` | N/A |
| 4 | to エッジ | トランジションからプレースへ | Transition.getTos() | `transition_xxx -> place_xxx` | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | グラフ閉じ | 有向グラフの終了 | 固定値 | `}` |

## 出力条件

### 抽出条件

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

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | プレース | 定義順 |
| 2 | トランジション | 定義順 |

### 改ページ条件

N/A

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

### 参照テーブル一覧

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

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

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| プレースノードID | `hash('sha1', $id)` | N/A | SHA1ハッシュによるID生成（行276-278） |
| 初期プレーススタイル | style=filled | N/A | 初期プレースはfilled表示（行76-77） |
| マーキングスタイル | color=#FF0000, shape=doublecircle | N/A | マーキング済みプレースの強調（行79-80） |
| 重み付きエッジ | weight > 1の場合ラベル表示 | N/A | アークの重みが1より大きい場合に数値表示（行237） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[dump呼び出し] --> B[オプション処理]
    B --> C[findPlaces - プレース検出]
    C --> D[findTransitions - トランジション検出]
    D --> E[findEdges - エッジ検出]
    E --> F[startDot - グラフ開始]
    F --> G[addPlaces - プレースノード追加]
    G --> H[addTransitions - トランジションノード追加]
    H --> I[addEdges - エッジ追加]
    I --> J[endDot - グラフ終了]
    J --> K[DOT文字列返却]
```

## エラー処理

### エラーケース一覧

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

## パフォーマンス要件

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

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

- 出力にはワークフロー名、プレース名、トランジション名が含まれる
- メタデータオプション有効時はプレース/トランジションのメタデータも出力される
- addslashes()によるエスケープ処理（行283-286）

## 備考

- 画像変換コマンド例: `dot -Tpng workflow.dot > workflow.png`
- DumperInterfaceを実装しており、他のワークフローDumperと互換性がある
- StateMachineGraphvizDumperの基底クラスとしても機能する

---

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

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

### 推奨読解順序

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

ワークフロー定義（Definition）のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DumperInterface.php | `src/Symfony/Component/Workflow/Dumper/DumperInterface.php` | dump()メソッドのシグネチャ（行28）。Definition, Marking, optionsの3引数 |
| 1-2 | Definition.php | `src/Symfony/Component/Workflow/Definition.php` | getPlaces(), getTransitions(), getInitialPlaces(), getMetadataStore() |
| 1-3 | Marking.php | `src/Symfony/Component/Workflow/Marking.php` | has()メソッドで特定プレースがマーキング済みか判定 |

**読解のコツ**: ワークフローの「プレース」は状態、「トランジション」は状態間の遷移、「マーキング」は現在の状態を表す。

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

GraphvizDumperのdump()メソッドが処理の起点。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | dump()メソッド（行45-62）がエントリーポイント |

**主要処理フロー**:
1. **行47**: with-metadataオプションの取得
2. **行49-51**: プレース、トランジション、エッジの検出
3. **行53**: オプションのマージ
4. **行55**: ラベルフォーマット
5. **行57-61**: DOT文字列の組み立て

#### Step 3: プレース/トランジション検出を理解する

findPlaces(), findTransitions()で定義からノード情報を抽出する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | findPlaces()（行67-104）で初期プレース/マーキング/背景色/メタデータを処理 |
| 3-2 | GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | findTransitions()（行109-139）でトランジション情報を抽出 |

#### Step 4: エッジ検出を理解する

findEdges()でプレース-トランジション間のエッジを生成する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GraphvizDumper.php | `src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php` | findEdges()（行193-223）でfrom/toのArcを処理。weightも考慮 |

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

```
GraphvizDumper::dump()
    |
    +-- findPlaces()
    |       +-- Definition::getPlaces()
    |       +-- Definition::getInitialPlaces()
    |       +-- MetadataStore::getMetadata()
    |       +-- Marking::has()
    |
    +-- findTransitions()
    |       +-- Definition::getTransitions()
    |       +-- MetadataStore::getMetadata()
    |
    +-- findEdges()
    |       +-- Transition::getFroms(true)  [Arc形式]
    |       +-- Transition::getTos(true)    [Arc形式]
    |
    +-- formatLabel()
    +-- startDot()
    +-- addPlaces()
    +-- addTransitions()
    +-- addEdges()
    +-- endDot()
```

### データフロー図

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

Definition ──────────> GraphvizDumper::dump() ──────> DOT文字列
  |-- Places                |                          |-- digraph workflow {
  |-- Transitions           |-- findPlaces()           |--   place_xxx [circle]
  |-- MetadataStore         |-- findTransitions()      |--   transition_xxx [box]
Marking (optional) ──> |-- findEdges()            |--   place -> transition
                            +-- DOT組み立て            |-- }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| 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` | ソース | トランジション定義 |
| Arc.php | `src/Symfony/Component/Workflow/Arc.php` | ソース | アーク（重み付きエッジ） |
| MetadataStoreInterface.php | `src/Symfony/Component/Workflow/Metadata/MetadataStoreInterface.php` | ソース | メタデータストア |
