QuoteServices Search
GET /quote_services/search.json
GET /quote_services/search/tag:{tag}.json
GET /quote_services/search/page:{page}.json快速結論
- legacy 入口:
/Users/mattsu/Documents/Site/get-lancer-php56/app/Plugin/Quotes/Controller/QuoteServicesController.php:2729-2802 - new 入口:
Endpoint/V1/QuoteServices.php:102-159,helperEndpoint/V1/QuoteServices.php:161-366。 - new routing:
Lib/Common/RouterRule/Mapping.php:57-64。 - new model helper:
Lib/Model/QuoteServiceTag.php:19-27。 - 搬移狀態:已補 compatibility endpoint、routing 與 PHPUnit;目前 web-app active caller 走
/quote_services/pro_list...,本 API 主要保留 legacy 相容。
流量與 caller
2026-06-17 查 legacy 正式機 ip-10-5-2-242 Apache access log,範圍含目前 log、get-lancer_access.log-20260617、get-lancer_access.log.1、get-lancer_access.log-202606*.gz、get-lancer_access.log.[0-9]*.gz。
有前台/API 200 流量:
8 GET /quote_services/search.json?keyword=a&page:1 200
3 GET /quote_services/search.json?keyword=cleaning 200
3 GET /quote_services/search.json?keyword=a 200
2 GET /quote_services/search.json?keyword=a&page:2 200
1 GET /quote_services/search/tag:%e5%86%b7%e6%b0%a3.json 200
1 GET /quote_services/search/tag:%E9%99%A4%E8%9F%B2.json 200
1 GET /quote_services/search/tag:%E7%B6%B2%E9%A0%81%E8%A8%AD%E8%A8%88.json 200
1 GET /quote_services/search/tag:%E6%B3%A5%E4%BD%9C.json 200
1 GET /quote_services/search/tag:%E6%B2%B9%E6%BC%86.json 200
1 GET /quote_services/search/tag:%E6%94%9D%E5%BD%B1.json 200
1 GET /quote_services/search/tag:%E5%AE%A4%E5%85%A7%E8%A8%AD%E8%A8%88.json 200
1 GET /quote_services/search/tag:%E5%A9%9A%E7%A6%AE.json 200
1 GET /quote_services/search/tag:%E5%86%B7%E6%B0%A3.json 200同次查詢 quote_bids/index、quote_requests/leads、quote_services/index|view 前台/API 正常流量都沒有比這支更適合優先搬:quote_bids/index 只有 admin HTML 命中、quote_requests/leads 無命中、quote_services/index 只有 2 筆 403、quote_services/view 無命中。
web-app caller:
| 檔案 | 行號 | 行為 |
|---|---|---|
/Users/mattsu/Documents/Site/web-app/modules/utils/api-manager.js | 3463-3469 | getServicesWithTag(tag) 呼叫 /quote_services/search/tag:{tag}.json;目前 active caller 已註解。 |
/Users/mattsu/Documents/Site/web-app/modules/utils/api-manager.js | 2630-2647 | 現行 active pro list 改走 /quote_services/pro_list/page_size:{pageSize}/page:{page}/.../sort:hired_count/direction:desc.json。 |
Legacy 行為
JSON branch 只處理 named params:
| legacy 行號 | 行為 |
|---|---|
2731-2735 | 只在 JSON request 進入;把 GET query 轉 named params,允許 tag、page、tag_category_id。 |
2736-2744 | 讀 tag、tag_category_id、page;每頁固定 20 筆;page < 1 時改為 1。 |
2746-2754 | 有 tag 時用 QuoteServiceTag::getServiceIdsByTag($tag, $tag_category_id) 取 service ids,並加 QuoteService.is_active = 1、QuoteService.is_archived = 0。 |
2756-2758 | $tag_svc_ids truthy 時加 QuoteService.id = $tag_svc_ids;空陣列 / false 時不加 id filter。 |
2760-2769 | contain Attachment.amazon_s3_thumb_url、User 基本欄位 / avatar / profile、QuoteServicePhoto.amazon_s3_thumb_url、QuoteFaqAnswer。 |
2771-2774 | 用相同 conditions 計算總筆數。 |
2776-2778 | 讀所有 category display name list。 |
2780-2788 | 查 service list,欄位限 id,user_id,address,business_name,description,quote_category_ids,is_active,is_archived,feedback_count,feedback_score_total,排序 QuoteService.id desc。 |
2790-2799 | 把 quote_category_ids 轉成 QuoteService.categories map,然後 unset quote_category_ids。 |
2801 | response:{"services": result, "total_pages": ceil(count / 20), "page": page}。 |
相容決策
keywordquery:正式 log 有/quote_services/search.json?keyword=...200,但 legacysearch()JSON branch 沒有讀keyword,只允許tag/page/tag_category_id。legacy staging 實測確認keyword等同 no-tag list;new 不新增文字搜尋。- no-tag 行為:legacy 沒有
tag時仍回 service list;new 保留 no-tag 無 filter 行為,不補 active / archived guard。 - tag not found:legacy
$tag_svc_idsfalsy 時不加QuoteService.idfilter,會回 active/non-archived service list;new 保留此行為,不改成空結果。 Search::index()不作為替代:新專案既有Endpoint/V1/Search.phpresponse shape、排序與 fallback 不同;本次補QuoteServices::search()專用相容 action。
Legacy staging 實測
2026-06-17 legacy staging:
GET /quote_services/search/tag:%E5%86%B7%E6%B0%A3.json
response: 200
shape: services[0].QuoteService / Attachment / User / QuoteFaqAnswer / QuoteServicePhoto確認 response key 與 legacy code 對齊:top-level services,每筆 service 會把 quote_category_ids 轉為 QuoteService.categories,並包含 Attachment.amazon_s3_thumb_url、User、QuoteFaqAnswer、QuoteServicePhoto.amazon_s3_thumb_url。
高風險分支實測:
| request | count | total_pages | page | first_id | 結論 |
|---|---|---|---|---|---|
/quote_services/search/tag:notfound-codex-test-20260617.json | 20 | 117 | 1 | 13732 | tag 找不到仍回 200 與 service list,不可改成空結果。 |
/quote_services/search.json?keyword=a&page:1 | 20 | 345 | 1 | 13732 | keyword 不做文字搜尋,行為等同 no-tag list。 |
/quote_services/search.json | 20 | 345 | 1 | 13732 | 無參數回 200 與 service list。 |
實作時需保留上述相容行為;keyword query 不應新增文字搜尋 side effect。
New 實作
| 檔案 | 行號 | 說明 |
|---|---|---|
Lib/Common/RouterRule/Mapping.php | 57-64 | 新增 /quote_services/search.json 與 /quote_services/search/(.*).json 精準 route。 |
Endpoint/V1/QuoteServices.php | 102-159 | search() action:API key、named params、tag filter、pagination、response。 |
Endpoint/V1/QuoteServices.php | 161-366 | response formatter 與 nested data helper。 |
Lib/Model/QuoteServiceTag.php | 19-27 | 補 legacy getServiceIdsByTag();只用 tag LIKE "%tag" 與 quote_category_id,不加 public/date filter。 |
tests/QuoteServicesSearchTest.php | 全檔 | 覆蓋 tag search shape、missing tag fallback、keyword ignored fallback。 |
測試
legacy staging 已測 2026-06-17:
/quote_services/search/tag:{tag}.json/quote_services/search/tag:{missing_tag}.json/quote_services/search.json?keyword=a&page:1/quote_services/search.json
local container PHP 8.2:
docker exec -w /project-data cd63f9147e8d php vendor/bin/phpunit tests/QuoteServicesSearchTest.php
OK (3 tests, 23 assertions)new staging 待切換後確認:
- response JSON key:
services,total_pages,page - service 欄位與 nested
Attachment/User/QuoteServicePhoto/QuoteFaqAnswer QuoteService.categoriesmap 與quote_category_idsunset- page size 固定 20、排序
QuoteService.id desc