リクエスト詳細
🐛 バグ報告
対応完了
対象アプリ: PurchaseFlow
新規登録時に next_request_no() が二重呼び出しされ採番がズレる
## 1. 不具合の内容
pages/edit.php の新規登録フロー($id === 0 の POST 処理)で `next_request_no()` が **2回** 呼ばれています。
- 1回目: ページ読み込み時($id === 0 の初期化ブロック)で `$request['request_no'] = next_request_no()` を取得し、フォームの「依頼番号」表示に使用。
- 2回目: POST 処理成功時に `$data['request_no'] = next_request_no()` で再取得し INSERT に使用。
```php
// 初期化(GET/POST 問わず実行される)
$request = [
'request_no' => next_request_no(), // ← 1回目
...
];
// POST 成功時
$data['request_no'] = next_request_no(); // ← 2回目
```
通常のシングルユーザー操作では同じ値が返るため問題になりませんが、**2つのタブ・ウィンドウや複数ユーザーが同時に新規登録フォームを開いている状況**では、1回目と2回目の間に別の依頼が INSERT されると採番がズレ、フォームに表示された番号と実際に登録される番号が異なります。
また、フォームにバリデーションエラー($error セット)が発生して再表示された場合、POST リクエストのたびに `next_request_no()` が2回実行されるため、エラー再表示のたびに表示番号と保存番号が乖離する可能性があります。
## 2. 根拠・発生しそうな条件
- `pages/edit.php` の `$id === 0` 初期化ブロックは GET・POST 両方で無条件実行される。
- POST 処理内で `next_request_no()` を再度呼んでいる(lib.php の `next_request_no()` はキャッシュなし)。
- バリデーションエラー時にフォームを再レンダリングする際も初期化ブロックが走る。
- 同時アクセスや連続登録時に採番の重複・欠番が発生しうる。
## 3. 期待動作
- フォームに表示される依頼番号と、実際に INSERT される依頼番号が一致すること。
- バリデーションエラー後に再表示されても番号がズレないこと。
## 4. 修正方針
`next_request_no()` の呼び出しを1か所に統一し、セッションまたは変数でキャッシュします。
```php
// edit.php 冒頭($id === 0 の場合のみ)
$new_request_no = ($id === 0) ? next_request_no() : '';
$request = [
'request_no' => $new_request_no,
// ...
];
// POST 成功時
if ($id === 0) {
$data['request_no'] = $new_request_no; // 同じ変数を使い回す
// ...
}
```
これにより GET 時も POST 時も同一リクエスト内で1回だけ採番関数が呼ばれ、表示番号と保存番号が一致します。さらに競合対策として、INSERT 直前に `SELECT ... FOR UPDATE` または `INSERT ... ON DUPLICATE KEY` でユニーク制約エラーをハンドルし、重複時はリトライする実装を推奨します(`request_no` には UNIQUE 制約があるため、重複時は PDOException が発生してユーザーにエラーを返せます)。
pages/edit.php の新規登録フロー($id === 0 の POST 処理)で `next_request_no()` が **2回** 呼ばれています。
- 1回目: ページ読み込み時($id === 0 の初期化ブロック)で `$request['request_no'] = next_request_no()` を取得し、フォームの「依頼番号」表示に使用。
- 2回目: POST 処理成功時に `$data['request_no'] = next_request_no()` で再取得し INSERT に使用。
```php
// 初期化(GET/POST 問わず実行される)
$request = [
'request_no' => next_request_no(), // ← 1回目
...
];
// POST 成功時
$data['request_no'] = next_request_no(); // ← 2回目
```
通常のシングルユーザー操作では同じ値が返るため問題になりませんが、**2つのタブ・ウィンドウや複数ユーザーが同時に新規登録フォームを開いている状況**では、1回目と2回目の間に別の依頼が INSERT されると採番がズレ、フォームに表示された番号と実際に登録される番号が異なります。
また、フォームにバリデーションエラー($error セット)が発生して再表示された場合、POST リクエストのたびに `next_request_no()` が2回実行されるため、エラー再表示のたびに表示番号と保存番号が乖離する可能性があります。
## 2. 根拠・発生しそうな条件
- `pages/edit.php` の `$id === 0` 初期化ブロックは GET・POST 両方で無条件実行される。
- POST 処理内で `next_request_no()` を再度呼んでいる(lib.php の `next_request_no()` はキャッシュなし)。
- バリデーションエラー時にフォームを再レンダリングする際も初期化ブロックが走る。
- 同時アクセスや連続登録時に採番の重複・欠番が発生しうる。
## 3. 期待動作
- フォームに表示される依頼番号と、実際に INSERT される依頼番号が一致すること。
- バリデーションエラー後に再表示されても番号がズレないこと。
## 4. 修正方針
`next_request_no()` の呼び出しを1か所に統一し、セッションまたは変数でキャッシュします。
```php
// edit.php 冒頭($id === 0 の場合のみ)
$new_request_no = ($id === 0) ? next_request_no() : '';
$request = [
'request_no' => $new_request_no,
// ...
];
// POST 成功時
if ($id === 0) {
$data['request_no'] = $new_request_no; // 同じ変数を使い回す
// ...
}
```
これにより GET 時も POST 時も同一リクエスト内で1回だけ採番関数が呼ばれ、表示番号と保存番号が一致します。さらに競合対策として、INSERT 直前に `SELECT ... FOR UPDATE` または `INSERT ... ON DUPLICATE KEY` でユニーク制約エラーをハンドルし、重複時はリトライする実装を推奨します(`request_no` には UNIQUE 制約があるため、重複時は PDOException が発生してユーザーにエラーを返せます)。
💬 返信 (3)
🛠 開発を開始しました (バグ修正 (purchase-flow))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「PurchaseFlow」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=purchase-flow
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/purchase-flow/
ご利用ありがとうございます!
ご要望いただいた「PurchaseFlow」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=purchase-flow
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/purchase-flow/
ご利用ありがとうございます!
Echo
Iris