SearchAdd Request Side Writers
更新日期:2026-08-05
狀態:gap(Legacy NewStaging inner_text 尚未搬到 PHP 8)
完整差異見 newstaging_delta_audit_2026-08-05.md。
快速結論
這段在 quote_requests 建立後、配對前執行。它補齊 preserve 關聯表、form、landing、log、summary、tracking、abuse、abnormal scan 等 request-side side effects。
current 入口:
SearchAddHandler::handle()
-> request-side writer classes新舊程式對應
Current Legacy
主要入口:
/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer/app/Plugin/Quotes/Controller/QuoteRequestsController.php::search_add()| legacy 區段 | 職責 |
|---|---|
| form submission writes | 寫入 form submission 與 field responses。 |
| landing / tracking writes | landing page、tracking、request log。 |
| summary / form time writes | request summary、FormTime。 |
| abuse / abnormal scan | 風險記錄與異常掃描。 |
| preserve service ids | QuoteRequestsController.php:1985-2006,2689-2698 驗證、合併、去重後逐筆寫關聯表。 |
Current PHP 8.2
| current 位置 | 職責 |
|---|---|
Lib/SearchAdd/SearchAddHandler.php:225-296 | request-side writers 執行順序。 |
Lib/SearchAdd/PreserveQuoteServiceWriter.php:12-31 | 單筆/多筆指定專家關聯表。 |
Lib/SearchAdd/FormSubmissionWriter.php | form submission / field responses。 |
| 待新增 inner_text writer | inner_text 另寫 quote_request_inners,並從後續 Form payload 移除。 |
Lib/SearchAdd/LandingPageWriter.php | landing page history。 |
Lib/SearchAdd/RequestLogWriter.php | request log。 |
Lib/SearchAdd/RequestActivityWriter.php | request activity。 |
Lib/SearchAdd/RequestSecondLinkWriter.php | second link。 |
Lib/SearchAdd/RequestNotificationWriter.php | request notification marker。 |
Lib/SearchAdd/RequestSummaryUpdater.php | summary 更新。 |
Lib/SearchAdd/FormTimeWriter.php | FormTime。 |
Lib/SearchAdd/RequestFeeUpdater.php | request fee。 |
Lib/SearchAdd/ExternalIntegrationWriter.php | 外部整合。 |
Lib/SearchAdd/RequestTrackingWriter.php | tracking。 |
Lib/SearchAdd/AbuseCheckWriter.php | abuse check。 |
Lib/SearchAdd/AbnormalScanWriter.php | abnormal scan 與 warning response 分支。 |
行號對照
| new 行號 | 對應 legacy | 職責 |
|---|---|---|
SearchAddHandler.php:225-296 | QuoteRequestsController.php:2639-3219 | request 建好後補所有 request-side writers,abnormal scan 命中時提前回 response。 |
PreserveQuoteServiceWriter.php:12-31 | QuoteRequestsController.php:1985-2006,2689-2698 | multi 全組驗證、合併單筆、原始值去重後,每個 id 寫一列。 |
FormSubmissionWriter.php:18-74 | QuoteFormSubmission.php:42-203, QuoteRequestsController.php:2925-2931 | 建立 quote_form_submissions 與 quote_form_submission_fields。 |
待新增 | QuoteRequestsController.php:2896-2918 | active inner_text 另寫 quote_request_inners,寫後從 Form unset。 |
FormSubmissionWriter.php:81-147 | QuoteFormSubmission.php:97-197 | 依 DB field type 正規化 response;travelpref JSON string-array 使用 decode 後原字串。 |
RequestSummaryUpdater.php:20-30 | QuoteRequestsController.php:2890-2966, 3120-3127 | 根據已寫入 form fields 回補 request/profile 欄位,reload summary,寫 limit id。 |
RequestSummaryUpdater.php:64-88 | QuoteRequestsController.php:2890-2954 | travelpref、due_date、region profile address、single travel preference。 |
RequestSummaryUpdater.php:102-137 | QuoteRequestsController.php:2904-2931 | object JSON、單一字串、JSON 字串陣列轉三個 travel flags,object 保留 customer note。 |
RequestSummaryUpdater.php:142-155 | QuoteRequestsController.php:2946-2954 | category 只有單一 travel preference 時補預設 travel flags。 |
RequestFeeUpdater.php:28-43 | QuoteRequestsController.php:2559-2594 | category fee set 寫回 request fee 欄位。 |
RequestFeeUpdater.php:45-89 | QuoteRequestsController.php:3051-3056 | variable fee / campaign / booking fee / high value rule 後補。 |
AbnormalScanWriter.php:56-61 | QuoteRequestsController.php:3077-3120 | 海外電話 / Seon 風險掃描。 |
AbnormalScanWriter.php:63-77 | QuoteRequestsController.php:3122-3167 | abnormal new user / list keyword,命中 disable match 時寫 abnormal item。 |
AbnormalScanWriter.php:79-82 | QuoteRequestsController.php:3169-3180 | legacy old keyword scan,命中時後續回 warning。 |
AbnormalScanWriter.php:84-101 | QuoteRequestsController.php:3182-3207 | category keyword scan。 |
AbnormalScanWriter.php:103-107, 155-176 | QuoteRequestsController.php:3210-3219, 3313-3319 | 掃描命中時寫 pending params,並把 request 改成 abnormal check / 停止配對。 |
Side Effects
同步可能寫入:
quote_request_preserve_quote_service_idsquote_form_submissionsquote_form_submission_fieldsquote_request_inners(NewStaging pending)quote_request_landing_pages- request log / activity 相關資料
- second link 相關資料
- tracking / abuse / abnormal scan 相關資料
quote_requests.form_summaryquote_requests.is_provider_travelquote_requests.is_customer_travelquote_requests.is_remotequote_requests.customer_travel_note(只有 object 格式且有非空 comment)- request fee 相關欄位
不可改變的契約
- writers 必須在 request create 後、auto quote 前執行。
- multi preserve 必須是 array 且每項
is_numeric();任一 invalid 清空 multi,再合併單筆。 array_unique()依輸入原始值去重;不能先 cast 成 int 再去重。- 關聯表包含單筆 preserve id,但
quote_requests.has_preserve/preserve_quote_service_id仍只依單筆輸入。 - abnormal scan 命中時可能提前回 success / warning,不應再進 match。
- form response normalization 要維持 legacy 對 checkbox / multi-select / travel preference 的處理;legacy form value contract 以純值字串為主。
- current 額外支援
{value: "..."}/[{value: "..."}]攤平成純值,是為了相容新版 client payload shape,避免寫入quote_form_submission_fields.responses後污染form_summary、job_center_summary、language_summary。這不是 legacy 原本支援的資料格式。 travelpref的{travel_vendor:{value:...}, ...}是既有 JSON object 語意,不能套用{value}攤平規則。travelpref也接受精確單值travel_vendor/travel_customer/remote與 JSON string-array;比對使用 strictin_array,大小寫不同或未知值不啟用 flag。- JSON string-array 必須原樣寫進
quote_form_submission_fields.responses;不能寫成 normalizer 的逗號字串。 - request-side writers 不應建立 provider bid。
inner_text只在同 category 且is_active=1時分流;missing /NULL不寫,空字串與字串"0"仍寫。inner_text不可寫入quote_form_submission_fields,也不可再參與 variable fee、abnormal scan、special flow 或 matching。- request create 與 first-field category guard 仍要先看到完整 Form;已提供的
FormSummary不因 inner field 分流而重算。
SQL 與 response
- 寫入:
INSERT INTO quote_request_preserve_quote_service_ids (created, quote_request_id, quote_service_id) VALUES (NOW(), ?, ?),每個合併後 id 一列。 - 寫入:
INSERT INTO quote_form_submissions ...、INSERT INTO quote_form_submission_fields (... responses, type)。 - NewStaging pending:
INSERT INTO quote_request_inners (created, quote_category_id, quote_request_id, quote_form_field_id, input_value) VALUES (NOW(), ?, ?, ?, ?)。 - 更新:
UPDATE quote_requests SET is_provider_travel = ?, is_customer_travel = ?, is_remote = ? ... WHERE id = ?。 - API success response shape 不變;reload 後三個 travel flag 反映 DB 最終值,欄位型別仍由既有 response formatter 決定。
Preserve 關聯表欄位分類:
| 欄位 | 來源 |
|---|---|
created | Legacy Cake timestamp callback,PHP 8 使用 NOW()。 |
quote_request_id | 新建 quote_requests.id。 |
quote_service_id | SearchAddInput::getPreserveQuoteServiceIds() 的驗證/合併/去重結果。 |
本地 PHP 8.2 SHOW COLUMNS:id int auto_increment、created datetime NULL、quote_request_id int NOT NULL、quote_service_id int NOT NULL。
quote_request_inners 欄位分類:
| 欄位 | 來源 |
|---|---|
created | DB NOW()。 |
quote_category_id | request category id。 |
quote_request_id | 新建 request id。 |
quote_form_field_id | active inner_text field id。 |
input_value | Legacy 開頭已 raw-url-decode 的 Form[field_id]。 |
本地 PHP 8.2 已用 DBFactory 核對 quote_request_inners schema;目前 active fixture 為 field 14293 / category 614。此 id 只供本地測試,不當成 staging / production 固定值。
Verification
主要測試:
tests/SearchAddStep4IntegrationTest.php
tests/SearchAddTravelPreferenceTest.php
tests/SearchAddTravelPreferenceIntegrationTest.php
tests/SearchAddInputTest.php
tests/FormSubmissionWriterTest.php
tests/SearchAddStep7IntegrationTest.php
tests/SearchAddStep9IntegrationTest.php2026-08-04:Core 5 tests / 20 assertions、Other 4 tests / 8 assertions;三種格式、negative cases、DB 原值與 flags 均通過,DB 測試使用 transaction 並 rollback。既有 Step4 category 280 測試因固定 session 失效,在 writer 前回 error 11,與本次調整無關。
2026-08-05 preserve 專用結果:
- Input:
2 tests / 3 assertions。 - Step 7 Core:
2 tests / 30 assertions;單筆與 multi-only 寫表,指定專家留在 auto pool。 - Step 7 Other:
1 test / 10 assertions;invalid multi 整組不寫,一般 bid 的is_preserve/reason/requestor_note為NULL。 - Regression:
SearchAddHandlerTest為3 tests / 9 assertions、SearchAddInputTest全檔為7 tests / 18 assertions。 - Step 9 Core:
1 test / 12 assertions;manual worker 能從本表讀出兩筆 multi preserve。既有 manual / related baseline1 test / 15 assertions亦通過。 - 兩個既有 Step 5 narrow reflection tests 在進 matcher 前由 request validation 回
error 11(Email 格式),因此不列為本次通過結果。
待確認 / 風險
- 本次已用 PHP 8.2 容器
SHOW COLUMNS核對quote_form_fields、quote_form_submissions、quote_form_submission_fields、quote_requests;field3082為 category280的travelpref。 - 本次沒有新增 config key,也沒有 queue、payment、notification 或額外 response 欄位。
- staging/production 的關聯表 schema 尚未在本輪核對;部署前必須確認與上述四欄一致。
FormSubmissionWriter.php:18-74目前會把inner_text當一般 field 寫入,是已確認的 parity gap。- 不能只在
FormSubmissionWriterskip;RequestFeeUpdater、AbnormalScanWriter、special flow 與 matcher 也會讀SearchAddInput::getFormPayload()。實作應在 request create 後建立 filtered input,讓所有下游使用移除後的 Form。 inner_textCore test:assertquote_request_inners有一列、quote_form_submission_fields無該 field、一般 field仍存在,且 pricing / match 不受 inner value 影響。- Other test:missing /
NULL、空字串 /"0"、inactive / other-category、FormSummary不被重算。