# 機能設計書 14-ページ削除

## 概要

本ドキュメントは、LEGACY CMSにおける固定ページの削除機能について記述する。この機能は管理画面のAjaxダイアログを通じて、確認メッセージ表示後にページを完全削除する。関連するタグと検索インデックスも同時に削除される。

### 本機能の処理概要

**業務上の目的・背景**：不要になった固定ページをシステムから完全に削除し、データベースと検索インデックスの整合性を維持する。誤削除防止のため、確認ダイアログによる2段階の操作を要求する。

**機能の利用シーン**：管理者がページ一覧画面で削除リンクをクリックした際にAjaxダイアログが表示され、確認後に削除を実行する。保護ページ（page_protected='Y'）は削除リンクが表示されない。

**主要な処理内容**：
1. ユーザーの権限チェック（ppages + ppagedelete権限の確認）
2. 確認ダイアログの表示（confirm=未指定時）
3. 削除実行（confirm=1時）
   - 関連タグの削除（Tags::deleteSlaveTag）
   - 検索インデックスの削除（Search::deleteEntry）
   - ページレコードの削除（Pages::deletePage）
4. 完了メッセージの表示

**関連システム・外部連携**：
- Zend_Search_Lucene：検索インデックスからの削除
- タグシステム：関連タグの削除

**権限による制御**：`ppages`および`ppagedelete`リソースへのアクセス権限が必要。保護ページは削除不可（UI側で制限）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 60 | ページ管理画面 | 呼び出し元画面 | 削除リンクからダイアログ呼び出し |
| - | 削除確認ダイアログ | 主画面 | 確認メッセージと削除実行 |

## 機能種別

CRUD操作（Delete）/ データ削除 / 確認ダイアログ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | integer | Yes | 削除対象ページID | 数値のみ |
| confirm | string | No | 確認フラグ | '1'で削除実行 |

### 入力データソース

- URLパラメータ（ページID、確認フラグ）
- セッション（ログインユーザー情報、ACL情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| HTML | string | Ajaxダイアログ内のHTML（確認メッセージまたは完了メッセージ） |

### 出力パターン

1. **確認画面**：「Are you sure you want to delete this page?」メッセージとDelete/Cancelボタン
2. **完了画面**：「Page Deleted」メッセージとCloseボタン

### 出力先

- Ajaxダイアログへのレスポンス
- pagesテーブルからのレコード削除
- tagsテーブルからの関連レコード削除
- 検索インデックスからのドキュメント削除

## 処理フロー

### 処理シーケンス

```
1. deleteAction()が呼び出される（Ajaxダイアログ経由）
   └─ レイアウト/ビュー無効化

2. 権限チェック
   ├─ ppages権限チェック
   └─ ppagedelete権限チェック
      ├─ 権限なし → privileges画面へフォワード
      └─ 権限あり → 次のステップへ

3. パラメータ取得
   ├─ idパラメータ（ページID）
   └─ confirmパラメータ（確認フラグ）

4. confirmパラメータによる分岐
   ├─ confirm != '1' → 確認ダイアログ表示
   │     └─ Delete/Cancelボタンを含むHTML出力
   └─ confirm == '1' && id存在 → 削除処理実行

5. 削除処理（confirm=1の場合）
   └─ Pages::deletePage($id)
      ├─ Tags::deleteSlaveTag('P', $id) [関連タグ削除]
      ├─ Search::deleteEntry('p'.$id) [検索インデックス削除]
      └─ DELETE FROM pages WHERE page_id = $id

6. 完了表示
   └─ 「Page Deleted」メッセージとCloseボタン出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始: deleteAction] --> B[レイアウト/ビュー無効化]
    B --> C{ppages+ppagedelete権限あり?}
    C -->|No| D[privileges画面へフォワード]
    C -->|Yes| E[パラメータ取得 id, confirm]
    E --> F{confirm='1' かつ id存在?}
    F -->|No| G[確認ダイアログHTML出力]
    F -->|Yes| H[Pages::deletePage実行]
    H --> I[Tags::deleteSlaveTag]
    I --> J[Search::deleteEntry]
    J --> K[DELETE FROM pages]
    K --> L[完了メッセージHTML出力]
    G --> M[終了]
    L --> M
    D --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 2段階確認 | 確認ダイアログ表示後に削除実行 | 常時 |
| BR-02 | 関連データ削除 | ページと共に関連タグも削除 | 常時 |
| BR-03 | 検索インデックス同期 | 削除時に検索インデックスからも削除 | 常時 |
| BR-04 | 保護ページ制限 | 保護ページは削除リンク非表示 | page_protected='Y'（UI側制御） |
| BR-05 | 物理削除 | 論理削除ではなく物理削除を実行 | 常時 |

### 計算ロジック

検索インデックスキー生成：`'p' + page_id`（例：p42）

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| タグ削除 | tags | DELETE | 関連タグの削除 |
| ページ削除 | pages | DELETE | ページレコードの削除 |

### テーブル別操作詳細

#### tagsテーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | tag_type='P' AND tag_slave={id} | ページに関連するタグ |

#### pagesテーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | page_id={id} | 対象ページ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | ppages/ppagedelete権限なし | privileges画面へフォワード |
| - | パラメータ不正 | id未指定またはconfirm=1でない | 確認ダイアログ表示 |

### リトライ仕様

削除処理にリトライ機構はない。削除失敗時はエラー画面表示（ただし明示的なエラーハンドリングは未実装）。

## トランザクション仕様

複数テーブルへの削除操作が行われるが、明示的なトランザクション管理は行っていない。以下の順序で処理される：
1. tagsテーブルから削除
2. 検索インデックスから削除
3. pagesテーブルから削除

途中で失敗した場合、部分的にデータが削除された状態になる可能性がある。

## パフォーマンス要件

- 単一レコードの削除操作
- 検索インデックス削除はファイルI/Oを伴う
- タグ削除は該当ページに関連するタグ数に依存

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

- ACLによる権限チェック（ppages + ppagedeleteリソース）
- 2段階確認による誤削除防止
- 保護ページの削除はUI側で制限（削除リンク非表示）
- SQLインジェクション対策：数値パラメータのみ使用

## 備考

- 物理削除のため、一度削除すると復元不可
- 削除後はページをリロードして一覧を更新（location.reload(true)）
- Dojo Toolkitのダイアログウィジェット使用

---

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

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

### 推奨読解順序

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

削除対象のテーブルと関連データを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | database.sql | `database.sql` | pagesテーブル（206-220行目）、tagsテーブル（335-341行目） |

**読解のコツ**: tagsテーブルの`tag_type`='P'がページのタグを示す。`tag_slave`がページIDと対応。

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

deleteActionの実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PagesController.php | `application/modules/admin/controllers/PagesController.php` | deleteAction（81-121行目） |

**主要処理フロー**:
1. **83行目**: ppages + ppagedelete権限の複合チェック
2. **85-86行目**: レイアウト/ビュー無効化
3. **88-89行目**: confirm, idパラメータ取得
4. **91行目**: confirm='1' && id存在の条件判定
5. **93-94行目**: Pages::deletePage()呼び出し
6. **96-101行目**: 完了メッセージHTML出力
7. **105-111行目**: 確認ダイアログHTML出力

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

Pagesモデルの削除処理と関連データの削除を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Pages.php | `application/models/Pages.php` | deletePage()（187-201行目） |

**主要処理フロー**:
- **189行目**: IDの存在確認と数値チェック
- **191-192行目**: Tags::deleteSlaveTag('P', $id)で関連タグ削除
- **194-195行目**: Search::deleteEntry('p'.$id)で検索インデックス削除
- **197行目**: DELETE FROM pages WHERE page_id = {id}

#### Step 4: 一覧画面の削除リンクを理解する

削除リンクの表示条件と呼び出し方を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | manage.phtml | `application/modules/admin/views/scripts/pages/manage.phtml` | 削除リンクの表示（110行目） |

**主要処理フロー**:
- **110行目**: ppagedelete権限チェック + page_protected != 'Y'で削除リンク表示
- **110行目**: getDialog()でAjaxダイアログ呼び出し

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

```
manage.phtml [Deleteリンククリック]
    │
    └─ getDialog('/admin/pages/delete/id/{id}/','Delete Page')
           │
           └─ PagesController::deleteAction()
                  │
                  ├─ ACL::isAllowed() [権限チェック x2]
                  │
                  ├─ [confirm未設定] 確認ダイアログHTML出力
                  │     │
                  │     └─ [Deleteボタンクリック]
                  │            │
                  │            └─ getDialog('/admin/pages/delete/id/{id}/confirm/1/')
                  │
                  └─ [confirm=1] Pages::deletePage()
                         │
                         ├─ Tags::deleteSlaveTag('P', id)
                         │      └─ DELETE FROM tags
                         │
                         ├─ Search::deleteEntry('p' + id)
                         │      └─ Lucene::delete(term)
                         │
                         └─ Zend_Db::delete('pages')
                                │
                                └─ 完了メッセージ表示
                                       │
                                       └─ [Closeボタン] location.reload(true)
```

### データフロー図

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

Deleteリンク       ───▶ deleteAction (confirm未設定) ───▶ 確認ダイアログ
                                                           ├─ Deleteボタン
                                                           └─ Cancelボタン

                                    │
                                    ▼

確認Deleteボタン   ───▶ deleteAction (confirm=1)    ───▶
                         │
                         ├─ Tags::deleteSlaveTag()
                         │      └─ tagsテーブルDELETE
                         │
                         ├─ Search::deleteEntry()
                         │      └─ Luceneインデックス削除
                         │
                         └─ Pages::deletePage()           完了メッセージ
                                └─ pagesテーブルDELETE     └─ Closeボタン
                                                              └─ 一覧リロード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PagesController.php | `application/modules/admin/controllers/PagesController.php` | コントローラー | deleteActionの実装 |
| Pages.php | `application/models/Pages.php` | モデル | deletePage()メソッド |
| Tags.php | `application/models/Tags.php` | モデル | deleteSlaveTag()関連タグ削除 |
| Search.php | `application/models/Search.php` | モデル | deleteEntry()検索インデックス削除 |
| manage.phtml | `application/modules/admin/views/scripts/pages/manage.phtml` | ビュー | 削除リンク配置 |
| common.js | `public/_scripts/admin/common.js` | JavaScript | getDialog()関数 |
| database.sql | `database.sql` | スキーマ | pages, tagsテーブル定義 |
