| @@ -4,15 +4,11 @@ | ||
| 4 | 4 | |
| 5 | 5 | use FluentSupport\App\Modules\PermissionManager; |
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | - * Resolves an optional, integration-provided one-line meta string per customer | |
| 9 | - * for MCP list surfaces (e.g. "Paying · 8,016 sent/30d · domain verified"). | |
| 10 | - * | |
| 11 | - * Fluent Support generates nothing here — it only exposes a batch filter that | |
| 12 | - * integrations (FluentCRM/FluentCart/etc.) may hook. The string can carry | |
| 13 | - * billing/CRM PII, so resolution is gated on the fst_sensitive_data capability, | |
| 14 | - * the same boundary AdminSensitivePolicy uses for customer data. | |
| 8 | + * Optional one-line customer summary for MCP lists, supplied by integrations | |
| 9 | + * through a batch filter. It can carry billing/CRM PII, so it's gated on | |
| 10 | + * fst_sensitive_data like AdminSensitivePolicy. | |
| 15 | 11 | */ |
| 16 | 12 | class CustomerMetaEnricher |
| 17 | 13 | { |
| 18 | 14 | const MAX_LEN = 120; |
| @@ -17,14 +13,10 @@ | ||
| 17 | 13 | { |
| 18 | 14 | const MAX_LEN = 120; |
| 19 | 15 | |
| 20 | 16 | /** |
| 21 | - * Build a [customer_id => meta line] map for the customers on one list page. | |
| 17 | + * [customer_id => line] for one list page. One filter call per page. | |
| 22 | 18 | * |
| 23 | - * Fires the filter ONCE per page (never per row) and returns [] for agents | |
| 24 | - * without fst_sensitive_data, so the integration round-trip is skipped and | |
| 25 | - * no PII leaks by default. | |
| 26 | - * | |
| 27 | 19 | * @param iterable $tickets The page of Ticket models (customer eager-loaded). |
| 28 | 20 | * @param array $context Extra context passed to the filter (e.g. agent_id). |
| 29 | 21 | * @return array<int,string> |
| 30 | 22 | */ |
| @@ -52,20 +44,15 @@ | ||
| 52 | 44 | * |
| 53 | 45 | * Inject a short, plain-text status line per customer for MCP list |
| 54 | 46 | * surfaces, e.g. "Paying · 8,016 sent/30d · domain verified". |
| 55 | 47 | * |
| 56 | - * CONTRACT — read before hooking: | |
| 57 | - * • BATCH ONLY. Fired ONCE per page with a deduplicated array of | |
| 58 | - * customer IDs. Do ALL work in a single query (WHERE customer_id | |
| 59 | - * IN (...)). DO NOT query per customer in a loop — that reintroduces | |
| 60 | - * N+1 and shows up in list latency. The loaded Customer models are | |
| 61 | - * passed so you can read email/user_id without an extra DB hit. | |
| 62 | - * • CHEAP. Runs on every list render. No remote HTTP calls. Cache | |
| 63 | - * anything expensive yourself (transient / object cache). | |
| 64 | - * • PLAIN STRING. The return value is sanitized to plain text: tags | |
| 65 | - * stripped, control chars removed, capped at 120 chars. HTML, | |
| 66 | - * markdown, arrays, objects and unknown keys are DISCARDED. | |
| 67 | - * • ADDITIVE. Merge into the incoming map; preserve existing keys. | |
| 48 | + * Contract: | |
| 49 | + * - Batch: fired once per page. Use one query for all IDs, not one per customer. | |
| 50 | + * Loaded Customer models are passed to save a lookup. | |
| 51 | + * - Cheap: runs on every list render. No remote calls; cache anything expensive. | |
| 52 | + * - Plain text: tags and control chars are stripped and values capped at 120 chars. | |
| 53 | + * Non-scalar values and unknown IDs are dropped. | |
| 54 | + * - Additive: merge into the incoming map, keep existing keys. | |
| 68 | 55 | * |
| 69 | 56 | * @param array<int,string> $lines Default []. Merge, don't overwrite. |
| 70 | 57 | * @param int[] $customerIds Deduped customer IDs on this page. |
| 71 | 58 | * @param array $customers [customer_id => loaded Customer model]. |
| @@ -101,15 +88,14 @@ | ||
| 101 | 88 | |
| 102 | 89 | foreach ($raw as $id => $value) { |
| 103 | 90 | $id = (int) $id; |
| 104 | 91 | |
| 105 | - // Drop keys not on this page and non-scalar (array/object) values. | |
| 106 | 92 | if (!isset($allowed[$id]) || !is_scalar($value)) { |
| 107 | 93 | continue; |
| 108 | 94 | } |
| 109 | 95 | |
| 110 | 96 | $value = wp_strip_all_tags((string) $value, true); |
| 111 | - $value = preg_replace('/[\x00-\x1F\x7F]+/u', ' ', $value); // strip control chars | |
| 97 | + $value = preg_replace('/[\x00-\x1F\x7F]+/u', ' ', $value); | |
| 112 | 98 | $value = trim(preg_replace('/\s+/u', ' ', $value)); |
| 113 | 99 | |
| 114 | 100 | if ($value === '') { |
| 115 | 101 | continue; |