# 画面設計書 61-ページ編集画面

## 概要

本ドキュメントは、Legacy CMSの管理画面における「ページ編集画面」の設計仕様を定義するものである。この画面は静的ページのコンテンツ編集機能を提供する。

### 本画面の処理概要

**業務上の目的・背景**：CMSにおいて静的ページ（固定ページ）は、企業情報、プライバシーポリシー、利用規約などの変更頻度の低いコンテンツを管理するために不可欠な機能である。本画面は、管理者がこれらの静的ページのタイトル、本文コンテンツ、URL（スラッグ）、セクション情報を編集・更新するためのインターフェースを提供する。FCKeditor（リッチテキストエディタ）を使用してHTMLコンテンツの視覚的な編集が可能であり、技術的な知識がなくてもページの作成・更新ができる。

**画面へのアクセス方法**：管理画面にログイン後、サイドメニューまたはダッシュボードから「Pages」を選択し、ページ管理画面（manage.phtml）の一覧から編集したいページをクリックするか、「Edit」リンクをクリックすることでアクセスする。URLパターンは `/admin/pages/edit/id/{page_id}/` となる。

**主要な操作・処理内容**：
1. ページタイトルの編集（必須入力、バリデーション付き）
2. ページコンテンツの編集（FCKeditorによるリッチテキスト編集）
3. URL（スラッグ）の設定・変更（英数字のみ、一意性チェック）
4. セクション（上級者向け）の設定
5. タグの追加・削除（別タブで管理）
6. ページの保存
7. ページの削除（保護されていない場合のみ）
8. ページの公開（下書き状態の場合のみ）

**画面遷移**：ページ管理画面（manage.phtml）から遷移してくる。保存後は同画面に留まり、削除後はページ管理画面へリダイレクトされる。「Pages...」ボタンでページ管理画面へ戻ることができる。

**権限による表示制御**：`ppages`権限と`ppageedit`権限の両方が必要。保護されたページ（page_protected = 'Y'）の場合、URL（スラッグ）とセクションフィールドは読み取り専用となり、削除ボタンは非表示となる。公開権限（`ppagepublish`）がある場合のみ「Publish」ボタンが表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | ページ編集 | 主機能 | ページの編集・更新処理 |
| 63 | 入力検証 | 補助機能 | ページフォームのバリデーション |
| 15 | ページ公開/非公開 | 補助機能 | 公開ステータスの切り替え |
| 60 | 検索インデックス更新 | 補助機能 | 保存時に検索インデックスを更新 |
| 64 | Ajaxダイアログ | 補助機能 | アセット選択などのダイアログ表示 |

## 画面種別

編集

## URL/ルーティング

- URL: `/admin/pages/edit/id/{page_id}/`
- モジュール: admin
- コントローラー: PagesController
- アクション: editAction

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 最大長 | 入力形式 | 備考 |
|--------|--------|----------|------|--------|----------|------|
| タイトル | title | string | Yes | - | テキスト入力 | ValidationTextBox使用 |
| コンテンツ | content | text | Yes | - | FCKeditor | HTMLリッチテキスト |
| URL（スラッグ） | slug | string | Yes | - | テキスト入力 | 英数字のみ、一意性チェック |
| セクション | section | string | No | - | テキスト入力 | 上級者向けオプション |

## 表示項目

| 項目名 | データソース | 表示形式 | 備考 |
|--------|--------------|----------|------|
| 著者名 | users.user_alias | テキスト | 詳細パネルに表示 |
| ステータス | pages.page_status | テキスト | ucwords()で整形 |
| 作成日時 | pages.page_date | d/m/Y H:i | - |
| 公開日時 | pages.page_published | d/m/Y H:i | 公開済みの場合のみ表示 |
| 最終編集日時 | pages.page_edit | d/m/Y H:i | - |

## イベント仕様

### 1-保存ボタン押下

FCKeditorの内容を更新後、Ajaxダイアログ経由で `/admin/pages/save/id/{page_id}/` にPOSTリクエストを送信する。バリデーション成功時はpagesテーブルを更新し、公開済みページの場合は検索インデックスも更新する。結果はダイアログで表示される。

### 2-削除ボタン押下

保護されていないページの場合のみ表示。Ajaxダイアログで `/admin/pages/delete/id/{page_id}/` を呼び出し、確認ダイアログを表示する。確認後、ページとそれに紐づくタグを削除し、検索インデックスからもエントリを削除する。削除後はページリロードで一覧画面に戻る。

### 3-公開ボタン押下

下書き状態のページでのみ表示。FCKeditorの内容を更新後、Ajaxダイアログ経由で `/admin/pages/publish/id/{page_id}/` にPOSTリクエストを送信する。確認後、ページステータスを「published」に更新し、公開日時を設定する。

### 4-Pages...ボタン押下

ページ管理画面（/admin/pages/）にリダイレクトする。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | pages | UPDATE | ページ情報を更新 |
| 保存ボタン押下 | search_index | UPDATE | 公開済みの場合、検索インデックスを更新 |
| 削除ボタン押下 | pages | DELETE | ページを削除 |
| 削除ボタン押下 | tags_slave | DELETE | 関連タグを削除 |
| 削除ボタン押下 | search_index | DELETE | 検索インデックスから削除 |
| 公開ボタン押下 | pages | UPDATE | ステータスと公開日時を更新 |

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

#### pages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | page_title | フォーム入力値 | 保存・公開時 |
| UPDATE | page_content | フォーム入力値（html_entity_decode適用） | 保存・公開時 |
| UPDATE | page_slug | フォーム入力値 | 保存・公開時 |
| UPDATE | page_section | フォーム入力値 | 保存・公開時 |
| UPDATE | page_edit | NOW() | 保存・公開時 |
| UPDATE | page_status | 'published' | 公開時のみ |
| UPDATE | page_published | NOW() | 公開時のみ |
| DELETE | - | WHERE page_id = {id} | 削除時 |

## メッセージ仕様

| メッセージID | メッセージ種別 | メッセージ内容 | 表示条件 |
|-------------|---------------|---------------|----------|
| MSG001 | 成功 | Page Saved | 保存成功時 |
| MSG002 | 成功 | Page Deleted | 削除成功時 |
| MSG003 | 成功 | Page Published | 公開成功時 |
| MSG004 | 確認 | Are you sure you want to delete this page? | 削除確認時 |
| MSG005 | 確認 | Are you sure you want to publish this page? | 公開確認時 |
| MSG006 | エラー | Page Not Specified! | ページID未指定時 |
| MSG007 | エラー | Title is required | タイトル未入力時 |
| MSG008 | エラー | Content is required | コンテンツ未入力時 |
| MSG009 | エラー | URL is required | スラッグ未入力時 |
| MSG010 | エラー | Invalid URL | スラッグに無効な文字時 |
| MSG011 | エラー | URL in use | スラッグ重複時 |

## 例外処理

| 例外状態 | 対応処理 |
|----------|----------|
| ページIDが未指定または無効 | ページ管理画面へリダイレクト |
| 該当ページが存在しない | ページ管理画面へリダイレクト |
| 権限不足（ppagesまたはppageedit権限なし） | 権限エラー画面へフォワード |
| バリデーションエラー | エラーメッセージをダイアログに表示 |
| 保護されたページの削除試行 | 削除ボタンが非表示のため通常は発生しない |

## 備考

- FCKeditorはレガシーなWYSIWYGエディタであり、セキュリティ上の観点から最新のエディタへの移行を検討すべきである
- タグ管理は別タブ（tagspane.phtml）で行われ、ページID（slave）とタイプ'P'を使用してタグを関連付ける
- 保護されたページ（page_protected = 'Y'）は通常、システム上重要なページであり、誤って削除やURL変更されないよう設計されている

---

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

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

### 推奨読解順序

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

まず、ページデータの構造とデータベーステーブルの関係を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Pages.php | `application/models/Pages.php` | pagesテーブルのカラム構造、CRUD操作の実装を確認 |

**読解のコツ**: Zend Framework 1.xのZend_Db_Selectを使用したクエリビルダーの記法に注意。`$this->registry->db`がデータベースアダプタへの参照となっている。

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

処理の起点となるコントローラーアクションを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PagesController.php | `application/modules/admin/controllers/PagesController.php` | editAction()メソッドが画面表示の起点 |

**主要処理フロー**:
1. **54-56行目**: 権限チェック（ppagesとppageedit）
2. **58行目**: URLパラメータからページIDを取得
3. **63-64行目**: Pagesモデルを使用してページデータを取得
4. **66-68行目**: ページが存在しない場合は一覧画面へリダイレクト

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

画面表示を担当するビューファイルを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit.phtml | `application/modules/admin/views/scripts/pages/edit.phtml` | 編集フォームのUI構造、Dojo Toolkitウィジェット |
| 3-2 | details.phtml | `application/modules/admin/views/scripts/pages/details.phtml` | Ajax読み込みされる詳細・機能ボタンパネル |
| 3-3 | tagspane.phtml | `application/modules/admin/views/scripts/_partials/tagspane.phtml` | タグ管理タブのUI |

**主要処理フロー**:
- **44-117行目** (edit.phtml): メインの編集フォーム
- **67-74行目** (edit.phtml): FCKeditorの初期化と設定
- **121行目** (edit.phtml): タグ管理パーシャルのインクルード
- **31行目** (details.phtml): 保存ボタンのJavaScript処理

#### Step 4: 保存処理を理解する

保存ボタン押下時のサーバーサイド処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PagesController.php | `application/modules/admin/controllers/PagesController.php` | saveAction()メソッド（126-211行目） |
| 4-2 | Pages.php | `application/models/Pages.php` | updatePage()メソッド（207-237行目） |

**主要処理フロー**:
- **141-160行目**: Zend_Filter_Inputによるバリデーション定義
- **166-172行目**: ページデータの更新呼び出し
- **219-236行目** (Pages.php): 公開済みページの場合の検索インデックス更新

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

```
editAction() [PagesController.php:54]
    │
    ├─ acl->isAllowed() [権限チェック]
    │
    ├─ Pages->fetchPage() [Pages.php:146]
    │      └─ registry->db->fetchall() [DB検索]
    │
    └─ View rendering [edit.phtml]
           │
           ├─ Ajax: /admin/pages/details [details.phtml]
           │
           └─ partial: tagspane.phtml

saveAction() [PagesController.php:126]
    │
    ├─ Zend_Filter_Input [バリデーション]
    │
    └─ Pages->updatePage() [Pages.php:207]
           │
           ├─ registry->db->update() [pages更新]
           │
           └─ Search->updateEntry() [検索インデックス更新]

deleteAction() [PagesController.php:81]
    │
    └─ Pages->deletePage() [Pages.php:187]
           │
           ├─ Tags->deleteSlaveTag() [関連タグ削除]
           ├─ Search->deleteEntry() [検索インデックス削除]
           └─ registry->db->delete() [pages削除]
```

### データフロー図

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

フォーム入力 ─────────▶ PagesController ─────────▶ Ajaxダイアログ
(title, content,        saveAction()               (成功/エラーメッセージ)
 slug, section)              │
                             │
                             ▼
                        Zend_Filter_Input
                        (バリデーション)
                             │
                             ▼
                        Pages->updatePage()
                             │
                             ├──────────▶ pagesテーブル
                             │            (UPDATE)
                             │
                             └──────────▶ Search->updateEntry()
                                          (検索インデックス更新)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PagesController.php | `application/modules/admin/controllers/PagesController.php` | ソース | ページ管理のコントローラー |
| Pages.php | `application/models/Pages.php` | ソース | ページデータのモデル |
| edit.phtml | `application/modules/admin/views/scripts/pages/edit.phtml` | テンプレート | 編集画面のビュー |
| details.phtml | `application/modules/admin/views/scripts/pages/details.phtml` | テンプレート | 詳細パネルのビュー |
| tagspane.phtml | `application/modules/admin/views/scripts/_partials/tagspane.phtml` | テンプレート | タグ管理パーシャル |
| Tags.php | `application/models/Tags.php` | ソース | タグデータのモデル |
| Search.php | `application/models/Search.php` | ソース | 検索インデックスのモデル |
| common.js | `public/_scripts/admin/common.js` | JavaScript | 共通ユーティリティ関数 |
| tags.js | `public/_scripts/admin/tags.js` | JavaScript | タグ管理用スクリプト |
| fckeditor.php | `public/_scripts/fckeditor/fckeditor.php` | ライブラリ | FCKeditorのPHPラッパー |
| template.css | `public/_styles/admin/template.css` | スタイル | 管理画面共通スタイル |
