# 画面設計書 39-記事カテゴリ管理画面

## 概要

本ドキュメントは、Legacy CMSにおける記事カテゴリ管理画面（編集ダイアログ）の設計仕様を定義します。

### 本画面の処理概要

記事カテゴリ管理画面は、既存の記事カテゴリのタイトルを編集するためのAjaxダイアログです。記事管理画面のカテゴリ一覧でコンテキストメニューから呼び出されます。

**業務上の目的・背景**：記事をカテゴリ別に分類・管理するための基盤機能として、カテゴリ名の変更を可能にします。カテゴリは記事の整理・ナビゲーションに使用されるため、適切な名称管理が重要です。

**画面へのアクセス方法**：
1. 記事管理画面のカテゴリ一覧で右クリック
2. コンテキストメニューから「Edit」を選択
3. Ajaxダイアログとして表示される

**主要な操作・処理内容**：
1. カテゴリタイトルの編集
2. Saveボタンでカテゴリ名を更新
3. Cancelボタンでダイアログを閉じる

**画面遷移**：
- 遷移元：記事管理画面（コンテキストメニュー経由）
- 遷移先：なし（ダイアログ閉じて記事管理画面をリロード）

**権限による表示制御**：
- aarticles + acategoryedit権限：画面へのアクセス

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | 記事カテゴリ管理 | 主機能 | 記事カテゴリ一覧の管理 |
| 61 | アクセス制御 | 補助機能 | 管理者権限チェック |

## 画面種別

編集 / モーダルダイアログ

## URL/ルーティング

- URL: `/admin/articles/category/id/{id}`
- モジュール: admin
- コントローラ: articles
- アクション: category
- 表示方式: Ajaxダイアログ（dijit.Dialog）

## 入出力項目

### 入力項目

| 項目名 | 項目ID | データ型 | 必須 | バリデーション | 説明 |
|--------|--------|----------|------|---------------|------|
| カテゴリタイトル | categorytitle | 文字列 | Yes | NotEmpty, Alnum(空白許可), 重複チェック | カテゴリ名 |

## 表示項目

| 項目名 | 項目ID | データ型 | 説明 |
|--------|--------|----------|------|
| エラーメッセージ | messages | 配列 | バリデーションエラー時に表示 |
| 現在のカテゴリタイトル | categorytitle | 文字列 | 編集対象の現在値 |

## イベント仕様

### 1-ダイアログ表示

1. 記事管理画面でカテゴリを右クリック、「Edit」を選択
2. getDialog()で/admin/articles/category/id/{id}にAjaxリクエスト
3. Admin_ArticlesController::categoryAction()が呼び出される
4. aarticles + acategoryedit権限チェック
5. レイアウト無効化
6. Articles::fetchCategory()で現在のカテゴリデータ取得
7. posted = 'N' を設定してフォーム表示（現在値をセット）

### 2-Saveボタン押下

1. doDialog()でフォームデータをAjax送信
2. categoryAction()がPOSTリクエストを処理
3. バリデーション実行：
   - NotEmpty: タイトル必須
   - Alnum(true): 英数字と空白のみ許可
   - NoRecordExists: 同名カテゴリの重複チェック（自分自身を除く）
4. バリデーション成功時：
   - Articles::updateCategory()でカテゴリ名を更新
   - 「Category Saved」メッセージと「Close」ボタンを表示
   - Closeボタン押下で画面リロード
5. バリデーション失敗時：
   - エラーメッセージを表示
   - 入力値を保持してフォーム再表示

### 3-Cancelボタン押下

dijit.byId('ajaxDialog').hide()でダイアログを閉じます。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ダイアログ表示 | articles_categories | SELECT | カテゴリ情報取得 |
| カテゴリ保存 | articles_categories | UPDATE | カテゴリタイトル更新 |

### テーブル別更新項目詳細

#### articles_categories

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | acat_id | = パラメータid | カテゴリID |
| SELECT | acat_title | - | 現在のタイトル |
| UPDATE | acat_title | フォーム入力値 | 新しいタイトル |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| MSG-001 | エラー | Title is required | タイトル未入力 |
| MSG-002 | エラー | Invalid Title | 英数字以外の文字が含まれる |
| MSG-003 | エラー | Category already exists | 同名カテゴリが既に存在 |
| MSG-004 | 完了 | Category Saved | カテゴリ保存成功 |

## 例外処理

| 例外種別 | 条件 | 処理内容 |
|---------|------|---------|
| 権限エラー | aarticles/acategoryedit権限なし | 権限エラー画面へフォワード |
| バリデーションエラー | 入力値不正 | エラーメッセージ表示、フォーム再表示 |

## 備考

- 重複チェックは自分自身のIDを除外して実行（Zend_Validate_Db_NoRecordExistsのexcludeオプション）
- Alnum(true)で空白を許可している
- 保存成功後のCloseボタンは画面リロード（location.reload(true)）を実行

---

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

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

### 推奨読解順序

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

カテゴリテーブルの構造を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Articles モデル | `application/models/Articles.php` | fetchCategory(), updateCategory() |

**読解のコツ**: articles_categoriesテーブルはacat_id（主キー）とacat_title（タイトル）のシンプルな構造。

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

コントローラのカテゴリ編集処理を把握します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Admin_ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | categoryAction() |

**主要処理フロー（categoryAction）**:
1. **529-531行目**: categoryAction()開始
2. **531行目**: aarticles + acategoryedit権限チェック
3. **533行目**: レイアウト無効化
4. **535行目**: パラメータからカテゴリID取得
5. **537-538行目**: Articles::fetchCategory()で現在データ取得
6. **540-541行目**: ビューに現在値をセット
7. **543行目**: POSTリクエスト判定
8. **549-556行目**: バリデータ定義（NotEmpty, Alnum, NoRecordExists）
9. **554行目**: excludeオプションで自分自身を除外
10. **558行目**: Zend_Filter_Inputでバリデーション
11. **560行目**: バリデーション成功判定
12. **562-564行目**: Articles::updateCategory()呼び出し

#### Step 3: モデル層を理解する

カテゴリ取得・更新処理を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Articles.php | `application/models/Articles.php` | fetchCategory(), updateCategory() |

**主要処理フロー（fetchCategory）**:
- **202-216行目**: カテゴリ取得処理
- **204行目**: IDの数値チェック
- **205-208行目**: SELECT文構築
- **210行目**: fetchall()で結果取得
- **212行目**: 最初のレコードを返す

**主要処理フロー（updateCategory）**:
- **389-396行目**: カテゴリ更新処理
- **391-393行目**: 更新データ配列作成
- **395行目**: UPDATE実行

#### Step 4: ビューテンプレートを理解する

編集フォームの構造を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | category.phtml | `application/modules/admin/views/scripts/articles/category.phtml` | フォーム構造 |

**主要処理フロー（category.phtml）**:
- **9行目**: posted = 'N'時の条件分岐でフォーム表示
- **10行目**: RenderMessagesでエラーメッセージ表示
- **11行目**: フォーム開始（doDialog()でサブミット）
- **12-26行目**: タイトル入力（ValidationTextBox）
- **23行目**: 現在値をvalue属性にセット
- **29-34行目**: Saveボタン（doDialog呼び出し）
- **35-40行目**: Cancelボタン（ダイアログ非表示）

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

```
記事管理画面 [manage.phtml]
    │
    └─ コンテキストメニュー「Edit」
           │
           └─ getDialog('/admin/articles/category/id/{id}/', 'Edit Category')
                  │
                  └─ Admin_ArticlesController::categoryAction()
                         │
                         ├─ $acl->isAllowed('aarticles', 'acategoryedit')
                         │
                         ├─ Articles::fetchCategory($id)
                         │      └─ SELECT from articles_categories WHERE acat_id = ?
                         │
                         ├─ [GET]
                         │      └─ posted = 'N' → フォーム表示（現在値セット）
                         │
                         └─ [POST via doDialog()]
                                │
                                ├─ Zend_Filter_Input [バリデーション]
                                │      └─ NoRecordExists (exclude: 自分自身)
                                │
                                ├─ [バリデーション成功]
                                │      │
                                │      ├─ Articles::updateCategory()
                                │      │      └─ UPDATE articles_categories SET acat_title = ?
                                │      │
                                │      └─ "Category Saved" + Closeボタン
                                │             │
                                │             └─ location.reload(true)
                                │
                                └─ [バリデーション失敗]
                                       └─ エラーメッセージ + フォーム再表示
```

### データフロー図

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

[ダイアログ表示時]
カテゴリID ──────────────▶ categoryAction() [GET]
                              │
                              ├─ fetchCategory($id)
                              │      │
articles_categories ────▶   SELECT ───▶ 現在のタイトル
                              │
                              └─ フォームHTML（現在値セット）

[フォーム送信時]
categorytitle ──────────▶ categoryAction() [POST]
                              │
                              ├─ Zend_Filter_Input [バリデーション]
                              │      │
                              │      └─ NoRecordExists (exclude: self)
                              │
                              └─ [成功時]
                                    │
                                    └─ updateCategory(id, title)
                                           │
articles_categories ◀──── UPDATE ──────▶ "Category Saved" HTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticlesController.php | `application/modules/admin/controllers/ArticlesController.php` | コントローラ | カテゴリ編集の制御 |
| category.phtml | `application/modules/admin/views/scripts/articles/category.phtml` | ビュー | カテゴリ編集フォーム |
| Articles.php | `application/models/Articles.php` | モデル | カテゴリデータの操作 |
| common.js | `public/_scripts/admin/common.js` | JavaScript | getDialog(), doDialog()関数 |
