# 画面設計書 13-記事詳細画面

## 概要

本ドキュメントは、Legacy CMSの記事詳細画面の設計を記載する。

### 本画面の処理概要

記事詳細画面は、個別の記事の全内容を表示し、コメント機能を提供する画面である。サイト訪問者は、この画面で記事の導入文・本文を読み、コメントを投稿することができる。

**業務上の目的・背景**：
CMSの中核機能として、記事コンテンツの詳細表示は必須である。読者が記事の全文を閲覧し、フィードバックを残せる場を提供することで、サイトのエンゲージメントを高める。著者情報の表示により、ライターへの信頼性を確保し、ソーシャルシェア機能により記事の拡散を促進する。

**画面へのアクセス方法**：
- 記事一覧画面から記事タイトルをクリック
- カテゴリ別・著者別・タグ別記事一覧からの遷移
- URL直接入力: `/articles/article/{id}/{title}/`
- 検索結果からのリンク

**主要な操作・処理内容**：
1. 記事IDに基づいて記事データを取得・表示
2. 著者情報の表示（設定による表示/非表示制御）
3. コメント一覧の表示（Ajax経由）
4. ログインユーザーによるコメント投稿
5. ソーシャルシェア機能（AddThis）の提供

**画面遷移**：
- 遷移元: 記事一覧画面、カテゴリ別記事一覧、著者別記事一覧、タグ別記事一覧、アーカイブ画面、検索結果画面
- 遷移先: カテゴリ別記事一覧画面、タグ別記事一覧画面、著者別記事一覧画面、ログイン画面、ユーザー登録画面

**権限による表示制御**：
- コメント投稿: ログインユーザーかつgcommentnewロールを持つユーザーのみ
- コメント非投稿時: ログイン/登録への誘導メッセージ表示

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | 記事一覧表示 | 主機能 | 記事の詳細内容を表示 |
| 44 | コメント一覧表示 | 補助機能 | 記事に紐づくコメントを表示 |
| 49 | タグ一覧表示 | 補助機能 | 記事のタグを表示 |
| 54 | 添付ファイル一覧表示 | 補助機能 | 記事の添付ファイルを表示 |

## 画面種別

詳細

## URL/ルーティング

| パス | HTTPメソッド | アクション |
|------|--------------|------------|
| `/articles/article/{id}/{title}/` | GET | articleAction（記事表示） |
| `/articles/article/{id}/{title}/` | POST | articleAction（コメント投稿） |

## 入出力項目

### 入力項目（URLパラメータ）

| 項目名 | パラメータ名 | 型 | 必須 | 説明 |
|--------|-------------|-----|------|------|
| 記事ID | id | integer | Yes | 記事の一意識別子 |
| 記事タイトル | title | string | No | SEO用のURLフレンドリータイトル |

### 入力項目（POSTデータ - コメント投稿）

| 項目名 | パラメータ名 | 型 | 必須 | 説明 |
|--------|-------------|-----|------|------|
| コメント内容 | content | string | Yes | コメント本文（StripTags, StringTrimフィルタ適用） |

## 表示項目

### 記事情報

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| 記事タイトル | article_title | h2タグで表示 |
| 公開日 | article_published | ADateヘルパーでフォーマット |
| 導入文 | article_intro | HTML形式で表示 |
| 本文 | article_content | HTML形式で表示、#moreアンカー付き |
| コメントリンク | - | article_commentsが'Y'の場合のみ表示 |
| ソーシャルシェア | - | AddThisウィジェット（Bookmark & Share, Tweet, Facebook Like） |
| コメント数 | - | CCountヘルパーで取得 |
| カテゴリ | acat_title | カテゴリ別記事一覧へのリンク付き |
| タグ一覧 | - | TListヘルパーで取得・表示 |

### 著者情報（showauthorがtrueの場合）

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| 著者名 | user_alias | 著者別記事一覧へのリンク付き |
| 公開日 | article_published | ADateヘルパーでフォーマット |
| 著者紹介文 | upro_blurb | BBCodeヘルパーで整形（存在する場合） |
| 他の記事へのリンク | - | 「More articles by {著者名}」形式 |

### コメントセクション

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| コメント一覧 | Ajax読み込み | dijit.layout.ContentPaneで非同期取得 |
| コメントフォーム | - | article_commentsが'Y'の場合のみ表示 |

## イベント仕様

### 1-カテゴリリンククリック

カテゴリ名をクリックすると、該当カテゴリの記事一覧画面に遷移する。

- 遷移先: `/articles/category/{acat_title}/`

### 2-タグリンククリック

タグ名をクリックすると、該当タグの記事一覧画面に遷移する。

- 遷移先: `/articles/tag/{tag_name}/`

### 3-著者名リンククリック

著者名をクリックすると、該当著者の記事一覧画面に遷移する。

- 遷移先: `/articles/author/{user_alias}/`
- 条件: showauthorがtrueの場合のみ表示

### 4-コメント投稿ボタン押下

フォームからコメントを投稿する。

- 前提条件: ユーザーがログイン済み、gcommentnewロールを持っている
- 処理: POSTデータのバリデーション後、commentsテーブルにINSERT
- 成功時: コメントが登録され、ページがリロードされる
- 失敗時: エラーメッセージを表示

### 5-コメント一覧読み込み

ページ読み込み時にAjaxでコメント一覧を取得する。

- 取得先: `/comments/comments/type/A/slave/{article_id}/`
- 表示: dijit.layout.ContentPane内に表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | articles | SELECT | 記事データを取得 |
| 画面表示 | articles_categories | SELECT | 記事カテゴリ情報を取得 |
| 画面表示 | users | SELECT | 著者情報を取得 |
| 画面表示 | users_profiles | SELECT | 著者プロフィール情報を取得 |
| コメント投稿 | comments | INSERT | 新規コメントを登録 |

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

#### articles（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | article_id | WHERE article_id = {id} | 記事ID |
| SELECT | article_title | - | 記事タイトル |
| SELECT | article_intro | - | 導入文 |
| SELECT | article_content | - | 本文 |
| SELECT | article_published | article_published <= NOW() | 公開日（現在日時以前） |
| SELECT | article_status | article_status = 'published' | 公開ステータス |
| SELECT | article_comments | - | コメント許可フラグ |
| SELECT | article_moderate | - | コメント承認制フラグ |
| SELECT | article_day | DAY(article_published) | 公開日（日） |
| SELECT | article_month | MONTH(article_published) | 公開日（月） |
| SELECT | article_year | YEAR(article_published) | 公開日（年） |

#### articles_categories（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | acat_title | - | カテゴリ名 |

#### users（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | user_alias | - | 著者のエイリアス |

#### users_profiles（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | upro_blurb | - | 著者紹介文 |

#### comments（INSERT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | comment_type | 'A' | コメント種別（記事） |
| INSERT | comment_slave | {article_id} | 関連記事ID |
| INSERT | comment_approved | 'Y' or 'N' | 承認ステータス（article_moderateに依存） |
| INSERT | comment_content | POSTデータ | コメント本文（フィルタ適用済） |
| INSERT | comment_user | ログインユーザーID | 投稿者ID |
| INSERT | comment_date | NOW() | 投稿日時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ | 表示条件 |
|-------------|------|----------|---------|
| MSG001 | エラー | You did not enter a comment | コメント内容が空の場合 |
| MSG002 | 情報 | Comment moderation is enabled | article_moderateが'Y'の場合 |
| MSG003 | 情報 | Please login or register to post a comment | 未ログインユーザーの場合 |
| MSG004 | 情報 | You don't have permission to post a comment | ログイン済みだがgcommentnewロールがない場合 |
| MSG005 | 情報 | You must have JavaScript enabled to view comments. | JavaScript無効時（noscript） |

## 例外処理

| 例外 | 処理 |
|------|------|
| 記事ID未指定 | 404エラー画面へフォワード |
| 該当記事が存在しない | 404エラー画面へフォワード |
| 記事が非公開ステータス | 404エラー画面へフォワード |
| コメントバリデーション失敗 | エラーメッセージを表示し、入力内容を保持 |

## 備考

- コメント承認制（article_moderate='Y'）の場合、投稿されたコメントはcomment_approved='N'で登録され、管理者承認後に表示される
- コメント一覧はAjaxで非同期読み込みされるため、JavaScript無効時は閲覧不可のメッセージが表示される
- AddThisによるソーシャルシェア機能は外部スクリプト（s7.addthis.com）に依存
- Atom/RSSフィードへのリンクがhead内に設定される

---

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

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

### 推奨読解順序

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

まず、記事データの構造とコメントデータの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | articles テーブル | DB Schema | article_comments, article_moderate カラムの役割 |
| 1-2 | users_profiles テーブル | DB Schema | upro_blurb の著者紹介文 |
| 1-3 | comments テーブル | DB Schema | comment_type, comment_slave, comment_approved の関連 |

**読解のコツ**: コメントのタイプ（'A'=記事）とスレーブID（記事ID）の紐付けに注目。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ArticlesController.php | `application/modules/default/controllers/ArticlesController.php` | articleActionメソッドがエントリーポイント |

**主要処理フロー**:
1. **272行目**: articleAction()メソッド開始
2. **275行目**: setRefer()でログイン後のリダイレクト先を設定
3. **279行目**: URLパラメータから記事IDを取得
4. **281行目**: 記事ID存在チェック
5. **287-295行目**: SQLクエリ構築（articles, articles_categories, users, users_profilesのJOIN）
6. **297-302行目**: 記事存在チェックとビューへの受け渡し
7. **311行目**: コメント値初期化
8. **313行目**: POSTリクエストチェック（コメント投稿処理）
9. **314-360行目**: コメント投稿処理（バリデーション、DB INSERT）

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

表示処理を担当するビューファイルを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | article.phtml | `application/modules/default/views/scripts/articles/article.phtml` | メインテンプレート |
| 3-2 | commentform.phtml | `application/modules/default/views/scripts/_partials/commentform.phtml` | コメント投稿フォーム |

**主要処理フロー**:
- **article.phtml 30行目**: 記事タイトル表示
- **article.phtml 42-44行目**: 導入文・本文表示
- **article.phtml 47-55行目**: コメントリンク・ソーシャルシェア
- **article.phtml 63-64行目**: カテゴリ・タグ表示
- **article.phtml 71-86行目**: 著者情報セクション（showauthorがtrue時）
- **article.phtml 96行目**: Ajax経由のコメント一覧読み込み
- **article.phtml 105-112行目**: コメントフォーム（article_commentsが'Y'時）

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

```
articleAction() [ArticlesController.php:272]
    │
    ├─ setRefer() - ログインリファラー設定
    │
    ├─ Zend_Registry::getInstance() - レジストリ取得
    │
    ├─ $registry->db->select() - SQLクエリ構築
    │      ├─ from('articles')
    │      ├─ join('articles_categories')
    │      ├─ join('users')
    │      ├─ join('users_profiles')
    │      ├─ where('article_published <= NOW()')
    │      ├─ where('article_status = published')
    │      ├─ where('article_id = ?')
    │      └─ limit(1,0)
    │
    ├─ [POST時] Zend_Filter_Input - コメントバリデーション
    │      ├─ filters: StringTrim, StripTags
    │      └─ validators: NotEmpty
    │
    ├─ [POST成功時] $registry->db->insert('comments', $data)
    │
    └─ View rendering
           ├─ article.phtml
           │      ├─ ADate() - 日付フォーマット
           │      ├─ BBCode() - 著者紹介文整形
           │      ├─ CCount() - コメント数
           │      ├─ TList() - タグ一覧
           │      ├─ dijit.layout.ContentPane (Ajax)
           │      │      └─ /comments/comments/type/A/slave/{id}/
           │      └─ partial('_partials/commentform.phtml')
           │             └─ RenderMessages() - エラーメッセージ
           └─ articles.phtml (layout)
```

### データフロー図

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

URLパラメータ
  └─ id(記事ID) ───────▶ ArticlesController::articleAction()
                              │
                              ▼
                    Zend_Db_Select (クエリ構築)
                              │
                              ▼
                    ┌─────────────────────┐
                    │     Database        │
                    │  ├─ articles        │
                    │  ├─ articles_categories │
                    │  ├─ users           │
                    │  └─ users_profiles  │
                    └─────────────────────┘
                              │
                              ▼
                    View (article.phtml)
                              │
            ┌─────────────────┴─────────────────┐
            ▼                                   ▼
    ┌──────────────┐                   ┌──────────────┐
    │ 記事表示     │                   │ コメント     │
    │ ├─ タイトル  │                   │ ├─ Ajax読込  │
    │ ├─ 本文      │                   │ └─ 投稿フォーム│
    │ └─ 著者情報  │                   └──────────────┘
    └──────────────┘

[コメント投稿フロー]

POSTデータ
  └─ content ──────────▶ Zend_Filter_Input
                              │
                              ▼
                    バリデーション成功?
                     │Yes          │No
                     ▼             ▼
              comments INSERT   エラーメッセージ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticlesController.php | `application/modules/default/controllers/ArticlesController.php` | コントローラー | 記事関連アクションの制御 |
| article.phtml | `application/modules/default/views/scripts/articles/article.phtml` | ビュー | 記事詳細画面のメインテンプレート |
| commentform.phtml | `application/modules/default/views/scripts/_partials/commentform.phtml` | パーシャル | コメント投稿フォーム |
| articles.phtml | `application/layouts/scripts/articles.phtml` | レイアウト | 記事セクション用レイアウト |
| articles.ini | `application/configs/articles.ini` | 設定 | 記事モジュールの設定ファイル（showauthor等） |
| CMS_Controller_Action_Default | `library/CMS/Controller/Action/Default.php` | 基底クラス | デフォルトモジュール用コントローラー基底クラス |
| ADate.php | `library/CMS/View/Helper/ADate.php` | ヘルパー | 日付フォーマット |
| BBCode.php | `library/CMS/View/Helper/BBCode.php` | ヘルパー | BBCodeパース |
| CCount.php | `library/CMS/View/Helper/CCount.php` | ヘルパー | コメント数取得 |
| TList.php | `library/CMS/View/Helper/TList.php` | ヘルパー | タグ一覧表示 |
| RenderMessages.php | `library/CMS/View/Helper/RenderMessages.php` | ヘルパー | エラーメッセージ表示 |
