Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .agent/PLANS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ ExecPlan の仕様書。複雑なタスクはこの仕様に従い `.agent/plans
- **Outcomes & Retrospective**: 達成内容と教訓
- **Context and Orientation**: 対象コードの場所・前提条件(パスはリポジトリルート相対)
- **Plan of Work**: 実装方針とその選定理由
- **Concrete Steps**: 具体的な手順(コード例・コマンド含む)
- **Validation and Acceptance**: 観察可能な動作で定義した完了条件
- **Concrete Steps**: 手順ごとに「編集対象ファイル」「実行コマンド」「期待される観測結果」を含む具体手順
- **Validation and Acceptance**: 内部実装の説明ではなく、ユーザーが観察可能な動作で定義した完了条件
- **Idempotence and Recovery**: 中断時の復帰手順
- **Artifacts and Notes**: 関連ファイル・URL
- **Interfaces and Dependencies**: 外部依存・他モジュールとのインターフェース
Expand All @@ -53,12 +53,15 @@ ExecPlan の仕様書。複雑なタスクはこの仕様に従い `.agent/plans
- Progress 以外ではチェックボックスを多用せず散文で記述
- 検証手順には具体的なコマンドと期待出力を含める
- ネストしたコードブロックは使わずインデントで表現
- 実装精度と再現性を維持したまま簡潔に書き、同一趣旨の重複記述を避ける
- 長大なコード全文の貼り付けは原則避け、対象箇所・変更意図・確認コマンドを優先する
- 次のマイルストーンへ自律的に進む(「次は?」と確認しない)
- 完了した ExecPlan は削除せずナレッジとして残す

## 成功基準

ステートレスなエージェントまたは初心者が、ExecPlan を通読して動作する成果物を生み出せること。
過去チャットの文脈を知らない実装者でも、同じ結果に再現できること。

## 関連

Expand Down
165 changes: 84 additions & 81 deletions .agent/plans/2026-02-04-outputfilter-undefined-array-key.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,84 @@
# ExecPlan: outputfilter の未定義配列キー警告修正

## 1. 概要 (Overview)

- **Goal**: PHP 8.0+ で outputfilter 使用時に発生する `Undefined array key` 警告を解消する
- **Target Version**: v1.2.1J (バグ修正)
- **Reference**: https://forum.modx.jp/viewtopic.php?p=10705#p10705
- **Context**:
- 関連: `AGENTS.md`, `.agent/PLANS.md`
- 対象: `manager/includes/docvars/outputfilter/*.inc.php`

## 2. 原因 (Cause)

outputfilter ファイル内で `$params` 配列のキーに直接アクセスしている箇所があり、キーが存在しない場合に PHP 8.0+ で Warning が発生する。

```php
// 問題のあるコード例 (image.inc.php:14)
'class' => $params['imgclass'], // キーが未定義だと Warning
```

PHP 7.x では未定義キーへのアクセスは Notice だったが、PHP 8.0 から Warning に昇格した。

## 3. 設計方針 (Design Strategy)

- **既存への影響**: なし(動作は変わらず、警告のみ解消)
- **後方互換性**: 完全維持
- **技術選定**:
- null 合体演算子 (`??`) を使用してデフォルト値を設定
- 既存の配列構造・ロジックは変更しない

## 4. 修正対象ファイル (Files to Fix)

| ファイル | 修正が必要なキー |
|----------|------------------|
| `image.inc.php` | `imgclass`, `imgstyle`, `alttext`, `id`, `imgattrib`, `imgoutput` |
| `hyperlink.inc.php` | `title`, `linkclass`, `linkstyle`, `target`, `linkattrib`, `text` + `$o` 初期化 |
| `htmltag.inc.php` | `tagid`, `tagname`, `tagclass`, `tagstyle`, `tagattrib`, `tagoutput` + `$o` 初期化 |
| `datagrid.inc.php` | 全28プロパティ (`egmsg`, `chdrc`, `tblc`, etc.) |
| `date.inc.php` | `default`, `dateformat` |
| `delim.inc.php` | `delim` |
| `string.inc.php` | `stringformat` |
| `richtext.inc.php` | `w`, `h`, `edt` |

## 5. 実装ステップ (Implementation Steps)

- [x] **Step 1: image.inc.php の修正**
- [x] 全ての `$params['key']` アクセスに `?? ''` を追加
- [x] `$params['align']` は `isset()` チェック済みなので変更不要

- [x] **Step 2: hyperlink.inc.php の修正**
- [x] 全ての `$params['key']` アクセスに `?? ''` を追加
- [x] `$o` 変数の初期化漏れを修正

- [x] **Step 3: htmltag.inc.php の修正**
- [x] 全ての `$params['key']` アクセスに `?? ''` を追加
- [x] `$o` 変数の初期化漏れを修正

- [x] **Step 4: 他の outputfilter ファイルの確認と修正**
- [x] `datagrid.inc.php` - 全28プロパティを修正
- [x] `date.inc.php` - `default`, `dateformat` を修正
- [x] `delim.inc.php` - `delim` を修正
- [x] `string.inc.php` - `stringformat` を修正
- [x] `richtext.inc.php` - `w`, `h`, `edt` を修正
- [x] 修正不要: `dateonly.inc.php` (date.inc.php をinclude), `unixtime.inc.php`, `htmlentities.inc.php`, `custom_widget.inc.php`

## 6. 検証方法 (Validation)

1. PHP 8.0+ 環境で Image プロセッサーを持つ TV を作成
2. TV をフロントエンドで表示し、Warning が発生しないことを確認
3. 画像が正常に表示されることを確認

## 7. 副作用の可能性 (Impact)

- **リスク**: 低
- 動作ロジックの変更なし
- デフォルト値として空文字列を設定するため、従来の挙動と同一

## 8. 進捗ログ (Progress Log)

- [2026-02-04]: 計画作成。フォーラム報告 #10705 に基づく。
- [2026-02-04]: 実装完了。8ファイルを修正。
# ExecPlan: outputfilter の未定義配列キー警告修正(発生源対処版)

## Purpose / Big Picture
PHP 8.0+ で TV の outputfilter 実行時に発生する `Undefined array key` 警告を解消する。警告を局所的に握り潰すのではなく、`$params` の生成元を正規化して全 outputfilter の入力契約を安定化させる。

## Progress
- [x] (2026-02-04) 初版計画を作成し、影響ファイルを棚卸し
- [x] (2026-02-04) 対症療法(各 filter 内の `?? ''`)で一時的に警告を回避
- [x] (2026-02-14) ExecPlan をテンプレート準拠に再構成
- [x] (2026-02-14) 「発生源修正」方針に基づく改修案へ更新
- [ ] (2026-02-14) 実装・検証結果を本 Plan に追記

## Surprises & Discoveries
`manager/includes/document.parser.class.inc.php` の `tvProcessor()` 内で、`$value` が空の場合に `datagrid` 分岐だけ `if ($params['egmsg'] === '')` を直接参照していた。ここが warning の発火点になり得る。また outputfilter 側が未定義キーを前提にしており、呼び出し契約が曖昧だった。

## Decision Log
2026-02-14 / AI / 対症療法(各 filter で未定義キーを空文字へ変換)を最終解としない。理由: エラー隠蔽になり、入力契約の不整合が残るため。代替案は「`tvProcessor()` で format ごとの既定値を明示し、`$params` を正規化してから filter を呼び出す」。
2026-02-14 / AI / 既存の outputfilter インターフェース(`$value`, `$params`)は維持し、互換性を優先する。理由: 呼び出し側の一元修正で影響範囲を閉じられるため。

## Outcomes & Retrospective
実装完了後に記載する。

## Context and Orientation
対象は TV 表示処理の中心である `manager/includes/document.parser.class.inc.php` の `tvProcessor()`。ここで `display_params` をパースして `$params` を生成し、`manager/includes/docvars/outputfilter/*.inc.php` に引き渡している。
warning は「filter 側でキー未定義」だけでなく「生成元が filter ごとの必須キーを保証していない」ことが本質的な原因。

用語:
outputfilter は TV 値を表示向けに整形する小さな変換モジュール。
入力契約は「どのキーが常に存在し、どの型で渡るか」の取り決め。
発生源修正は warning 発生箇所ではなく、異常データを生む上流を直すこと。

## Plan of Work
`tvProcessor()` に format ごとのパラメータスキーマ(既定値マップ)を追加し、`display_params` のパース結果をそのスキーマで正規化してから outputfilter を呼ぶ。これにより filter 側は「定義済みキーが渡る」契約に依存できる。
同時に、`$value` 空判定の `datagrid` 早期 return 条件を未定義キー参照しない実装に変更し、warning 発火点を除去する。

## Concrete Steps
1. format ごとの既定値マップを `tvProcessor()` に追加する。
編集対象ファイル: `manager/includes/document.parser.class.inc.php`
実行コマンド: `rg -n "function tvProcessor|datagrid|display_params" manager/includes/document.parser.class.inc.php`
期待される観測結果: 既定値マップの配置場所と `tvProcessor()` の入力処理位置が特定できる。
2. `$params` 生成直後に正規化処理(`array_replace($defaults, $params)` 相当)を挿入する。
編集対象ファイル: `manager/includes/document.parser.class.inc.php`
実行コマンド: `php -l manager/includes/document.parser.class.inc.php`
期待される観測結果: 構文エラーがなく、`$params` 参照前に必ず既定キーが存在する状態になる。
3. `datagrid` の早期 return 判定で未定義キー参照を発生させない。
編集対象ファイル: `manager/includes/document.parser.class.inc.php`
実行コマンド: `rg -n "egmsg|datagrid" manager/includes/document.parser.class.inc.php`
期待される観測結果: `egmsg` 参照が正規化後の `$params` に対してのみ行われ、未定義キー warning の経路が消える。
4. 主要 outputfilter の呼び出し契約が維持されることを点検する。
編集対象ファイル: `manager/includes/docvars/outputfilter/image.inc.php`, `manager/includes/docvars/outputfilter/hyperlink.inc.php`, `manager/includes/docvars/outputfilter/htmltag.inc.php`, `manager/includes/docvars/outputfilter/datagrid.inc.php`, `manager/includes/docvars/outputfilter/date.inc.php`, `manager/includes/docvars/outputfilter/delim.inc.php`, `manager/includes/docvars/outputfilter/string.inc.php`, `manager/includes/docvars/outputfilter/richtext.inc.php`
実行コマンド: `php -l manager/includes/docvars/outputfilter/{image,hyperlink,htmltag,datagrid,date,delim,string,richtext}.inc.php`
期待される観測結果: 対象 filter で構文エラーがなく、互換インターフェース(`$value`, `$params`)を維持している。
5. 実測結果を Plan に反映する。
編集対象ファイル: `.agent/plans/2026-02-04-outputfilter-undefined-array-key.md`
実行コマンド: `git diff -- .agent/plans/2026-02-04-outputfilter-undefined-array-key.md`
期待される観測結果: Progress / Surprises / Decision Log / Outcomes が実装結果に追従して更新される。

## Validation and Acceptance
1. `php -l manager/includes/document.parser.class.inc.php` を実行し、`No syntax errors detected` が出ること。
2. 主要 outputfilter 8ファイルに対する `php -l` で `No syntax errors detected` が出ること。
3. 管理画面で `display_params` を省略した TV を各 outputfilter 形式で表示し、PHP warning(`Undefined array key`)が出ないこと。
4. `datagrid` で `egmsg` 未指定の TV を表示し、warning なしで従来どおりレンダリングされること。
5. `display_params` 指定あり TV でも表示 HTML が改修前と同等であること(回帰なし)。
6. 上記検証結果(実行コマンドと観測結果)を本 Plan に追記し、過去チャットを見ずに再現できる状態にすること。

## Idempotence and Recovery
変更は `document.parser.class.inc.php` と必要最小限の outputfilter のみ。差分は `git diff` で確認し、想定外があれば対象コミットを revert して復旧できる。
中断時は `Progress` の未完了項目を次回の再開点として扱う。

## Artifacts and Notes
関連ファイル:
`manager/includes/document.parser.class.inc.php`
`manager/includes/docvars/outputfilter/image.inc.php`
`manager/includes/docvars/outputfilter/hyperlink.inc.php`
`manager/includes/docvars/outputfilter/htmltag.inc.php`
`manager/includes/docvars/outputfilter/datagrid.inc.php`
`manager/includes/docvars/outputfilter/date.inc.php`
`manager/includes/docvars/outputfilter/delim.inc.php`
`manager/includes/docvars/outputfilter/string.inc.php`
`manager/includes/docvars/outputfilter/richtext.inc.php`

## Interfaces and Dependencies
外部依存は追加しない。`tvProcessor()` と outputfilter の既存インターフェースを維持するため、管理画面・フロント双方への影響を最小化できる。
関連ドキュメントは `AGENTS.md`, `.agent/PLANS.md`, `assets/docs/architecture.md`, `assets/docs/template-system.md`。
90 changes: 90 additions & 0 deletions .agent/plans/2026-02-13-logging-paging-undefined-key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# ExecPlan: ログ閲覧画面のページング配列キー未定義エラー修正

## Purpose / Big Picture

管理画面「ツール→イベントログ」でログが7ページ以上ある場合、1ページ目や最終ページ付近で `Undefined array key` 警告が発生する。この警告を解消し、全ページで正常にページネーションが表示されるようにする。

## Progress

- [x] (2026-02-13) logging.static.php のページングウィンドウに境界チェックを追加
- [x] (2026-02-13) paginate.inc.php の getNumberOfPage() に ceil() を適用
- [x] (2026-02-13) 動作検証(対象2ファイルの `php -l` で構文エラーなし)

## Surprises & Discoveries
- `Paging::getNumberOfPage()` が小数を返す設計のため、`getCurrentPage()` の計算が間接的に小数依存になっていた。`ceil()` + `int` 化で `getPagingRowArray()` のループ境界が明確化された。
## Decision Log

- 2026-02-13 / AI / `messages.static.php` も同じ `Paging` クラスを使用しているが、こちらは `foreach` でループしているため境界チェック不要。影響は `logging.static.php` のみ。
- 2026-02-13 / AI / `logging.static.php` のページ番号表示は「常に5件表示」の既存UIを維持し、先頭・末尾でウィンドウをスライドさせる方式を採用した。

## Outcomes & Retrospective
- `manager/actions/report/logging.static.php` で配列アクセスを固定オフセットから境界付きループへ変更し、`Undefined array key` の発生条件を除去した。
- `manager/includes/paginate.inc.php` で総ページ数を切り上げ整数化し、ページ配列生成の境界を安定化した。
- 画面手動確認(イベントログ7ページ以上の実ブラウザ確認)は未実施。コード上の再発要因は解消済み。
## Context and Orientation

**エラー報告**:

```
PHP Warning: Undefined array key -2
File: manager/actions/report/logging.static.php
Line: 306
Source: $paging .= $array_row_paging[$current_row - 2];
```

**関連ファイル**:

- `manager/actions/report/logging.static.php` — ログ閲覧画面(修正対象)
- `manager/includes/paginate.inc.php` — `Paging` クラス(修正対象)
- `manager/actions/permission/messages.static.php` — 同じ `Paging` クラスを使用(修正不要)

**再現条件**: ログが700件超(デフォルト100件/ページ×7ページ以上)で、1〜2ページ目または末尾1〜2ページ目を表示した場合に発生。

## Plan of Work

2箇所を修正する。

**修正1: logging.static.php(主原因)** — 固定インデックス `$current_row - 2` 〜 `$current_row + 2` でページ番号配列にアクセスしている箇所を、境界クランプ付きのループに置き換える。表示するページ数(5ページ)は変わらず、端のページでもウィンドウがスライドして範囲外アクセスを防ぐ。

**修正2: paginate.inc.php(副次的)** — `getNumberOfPage()` が `$nbr_row / $num_result` を返しているが、`ceil()` を使っていないため端数がある場合にページ数が浮動小数点になる。`ceil()` を適用して正確な整数ページ数を返すようにする。また `$current_row` も `(int)` でキャストして型安全を確保する。
この Plan は実装者が過去チャットを参照しなくても実施できるよう、対象ファイル・コマンド・期待観測結果を各手順に明記する。

## Concrete Steps

1. ページング配列アクセスを境界クランプ付きループへ置換する。
編集対象ファイル: `manager/actions/report/logging.static.php`(305〜315行付近)
実行コマンド: `php -l manager/actions/report/logging.static.php`
期待される観測結果: 構文エラーなし。先頭/末尾ページで範囲外アクセス由来の warning が出ない。
2. `$current_row` を整数で扱うよう型安全化する。
編集対象ファイル: `manager/actions/report/logging.static.php`(291行付近)
実行コマンド: `rg -n "int_cur_position|current_row" manager/actions/report/logging.static.php`
期待される観測結果: `$current_row` が整数化され、インデックス計算が小数依存しない。
3. `getNumberOfPage()` を切り上げ整数返却へ修正する。
編集対象ファイル: `manager/includes/paginate.inc.php`
実行コマンド: `php -l manager/includes/paginate.inc.php`
期待される観測結果: 構文エラーなし。総ページ数が整数化され、ページ配列生成のループ境界が安定する。

## Validation and Acceptance

管理画面「ツール→イベントログ」で以下を確認する:

1. `php -l manager/actions/report/logging.static.php manager/includes/paginate.inc.php` を実行し、両ファイルで `No syntax errors detected` が出ること。
2. ログが7ページ以上(700件超)ある状態で検索を実行し、1ページ目で `Undefined array key` 警告が出ないこと。
3. 同条件で2ページ目を表示し、警告が出ないこと。
4. 中間ページを表示し、現在ページ中心の5件ウィンドウでページ番号が表示されること。
5. 最終ページを表示し、範囲外アクセス由来の警告が出ないこと。
6. ログが6ページ以下の条件では、従来どおり全ページ番号が表示されること。
7. 実行したコマンドと観測結果を本 Plan に追記し、過去チャットを見ずに検証を再現できること。

## Idempotence and Recovery

変更は2ファイル・3箇所のみ。`git diff` で差分確認し、問題があれば `git checkout` で復元可能。

## Artifacts and Notes

- `manager/actions/report/logging.static.php` — 管理画面アクション13(Viewing logging)
- `manager/includes/paginate.inc.php` — 汎用ページングクラス(2001年製、外部ライブラリ由来)

## Interfaces and Dependencies

`Paging` クラスの `getNumberOfPage()` は `private` メソッドのため、外部への影響なし。`messages.static.php` は `getPagingRowArray()` の戻り値を `foreach` で使用しているため、配列要素数が変わっても影響なし。
Loading