SearchAdd Request Create
更新日期:2026-08-05
程式 commit:region 8ad6ebc5;multi preserve 為尚未 commit 工作區
快速結論
這段在 actor 與建單前 guard 通過後建立 quote_requests。region 欄位可傳地區名稱或郵遞區號;multi preserve 只寫關聯表,不可反向改寫主表的單筆 preserve 欄位。
SearchAddHandler::handle()
-> QuoteRequestCreator::create()新舊程式位置
Legacy root:
/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer| 職責 | Legacy | PHP 8.2 |
|---|---|---|
| API 入口 | QuoteRequestsController.php:1808 | Endpoint/V1/SearchAdd.php:53-119 |
| guard 後建單 | QuoteRequestsController.php:2464-2478 | SearchAddHandler.php:205-223 |
| 組主表欄位並寫入 | QuoteRequestsController.php:2480-2524, 2579-2675 | QuoteRequestCreator.php:28-79 |
| location fallback | QuoteRequestsController.php:2526-2577 | QuoteRequestCreator.php:101-143 |
| active region field、地址與 zip 判斷 | QuoteRequestsController.php:2537-2573 | QuoteRequestCreator.php:146-189 |
empty_zip_code log | QuoteRequestsController.php:2574-2576 | QuoteRequestCreator.php:194-235 |
| phone fallback | QuoteRequestsController.php:2579-2595 | QuoteRequestCreator.php:295-307 |
| match type | QuoteRequestsController.php:1929-1937 | QuoteRequestCreator.php:312-326 |
| multi-request tag | QuoteRequestsController.php:2665-2669 | QuoteRequestCreator.php:328-335 |
| preserve 主表欄位 | QuoteRequestsController.php:2630,2645-2647 | QuoteRequestCreator.php:58-59 |
Preserve 主表邊界
quote_requests.has_preserve只依單筆preserve_to_quote_service_id;只有 multi 時保持0。quote_requests.preserve_quote_service_id只保存單筆 alias;只有 multi 時保持NULL。- multi list 另由
PreserveQuoteServiceWriter寫入quote_request_preserve_quote_service_ids,不新增主表欄位。 - 直接預約仍只使用單筆指定專家與預約時間;multi list 不擴張直接預約語意。
Region / zip 規則
只有原始 QuoteRequest.zip_code 為空時,才讀 region form response。
SELECT id
FROM quote_form_fields
WHERE quote_category_id = ?
AND type = 'region'
AND is_active = 1;依序判斷 active region 欄位:
- response 是地區名稱:由 address map 反查 zip,log note 為
area_name。 - response 本身是 address map 內的 zip:直接採用,log note 為
area_code。 - 都不符合:zip 保持空字串,log note 保持空字串。
取得 zip 後,以預設 AreaUtil 補 address、state_id、city_id。不新增 Legacy 沒有的地區有效性條件。
empty_zip_code log
- 觸發:原始
QuoteRequest.zip_code為空;無論 region 是否成功解析都會寫。 - channel / level:
empty_zip_code/ERROR。 - message:
{zip}|{area_name|area_code|空字串}|c_id:{category_id}。 - context:完整 request payload,並帶解析後的
QuoteRequest.zip_code/address/state_id/city_id。 - handler:DB log 固定寫入;Slack 只在
production啟用,與 LegacyEnvFactory條件一致。
風險:context 沿用 Legacy 的完整 request payload,可能包含 password、social token 或其他敏感 body 欄位,也會與 RouterV3 generic request log 重複。本次為 Legacy parity 未自行省略或過濾;若要縮減,需另做 migration decision。
流程對照
| 項目 | 行為 |
|---|---|
| guard | category、form/category、actor、risk control 先於 QuoteRequestCreator 執行。 |
| input | category、title、description、location、phone、travel、match、preserve 與 tracking 欄位由 SearchAddInput 提供。 |
| DB read | 讀 category;原始 zip 為空時讀 active region form field。 |
| DB write | 寫一列 quote_requests,再依 id reload。 |
| payment | 本段沒有付款。 |
| queue | 本段不寫 queue。 |
| activity / notification | 本段不寫;由後續 writer 處理。 |
| response | creator 回傳 reload 後的 request row;外層成功 response 由 SearchAddHandler 組裝。 |
不可改變的契約
- 建單必須發生在 actor 與 pre-create guard 成功之後。
quote_requests.user_id必須來自已解析好的 actor。match_type必須依 category 規則正規化,不能只用 raw payload。quote_service_id、preserve_quote_service_id只有大於 0 才能落成有效 id。- multi preserve 不可把
has_preserve或preserve_quote_service_id改成多筆推導值。 - 台灣手機
9xxxxxxxx要補成09xxxxxxxx。 - 原始 zip 為空時,region 地址名稱、region 直接 zip、invalid region 三種路徑都必須寫
empty_zip_codelog。
測試
檔案:tests/SearchAddStep2IntegrationTest.php
Core:
testRegionFormResponseCanBeDirectZipCode():100落表為100 / 台北市,中正區 / state 5466 / city 360,message 為area_code。
Other:
testRegionFormAddressNameStillResolvesZipCode():既有地址名稱反查仍為100,message 為area_name。testInvalidRegionFormResponseKeepsEmptyLocationAndLogsIt():invalid response 保持空 location,message note 為空。
2026-08-04 PHP 8.2 container 結果:
- Core:
1 test, 10 assertions,通過。 - Other:
2 tests, 12 assertions,通過。 - 既有明確 zip 建單 regression:
2 tests, 33 assertions,通過;其中明確 zip 不會寫empty_zip_codelog。 - 整檔另有 2 個既有固定 session 測試失敗:session 已失效,與 region 修改無關。
- 測試建立的
region response parity testrequest 殘留數:0。
Config / 部署
- 沒有新增 config key,也不修改 ALB。
- location 仍讀既有
area/sys_area設定;台灣環境不可新增area = tw。 - log 沿用既有 LogHelper / Slack 部署設定;本次沒有新增 webhook。
待確認 / 風險
- Legacy 在建單前先計算 fee;PHP 8.2 拆到 request create 後的
RequestFeeUpdater,需以最終 DB 欄位維持 parity。 empty_zip_codecontext 的敏感資料與重複 logging 風險如上;未取得 reviewer 決定前保持 Legacy 行為。