Skip to content

Add CookieResolver that delegates cookie handling to Meta's parameter builder - #14

Open
loevgaard wants to merge 1 commit into
masterfrom
use-capi-param-builder
Open

Add CookieResolver that delegates cookie handling to Meta's parameter builder#14
loevgaard wants to merge 1 commit into
masterfrom
use-capi-param-builder

Conversation

@loevgaard

@loevgaard loevgaard commented Sep 7, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to #13: instead of maintaining our own parsing of what Meta writes into _fbc/_fbp, the new Setono\MetaConversionsApi\Cookie namespace hands the raw request to facebook/capi-param-builder-php — Meta's own library for exactly this job — and converts the results into the typed Fbc/Fbp value objects.

$resolvedCookies = (new CookieResolver())->resolve($_SERVER['HTTP_HOST'], $_GET, $_COOKIE);

$event->userData->fbc = $resolvedCookies->fbc;   // ?Fbc
$event->userData->fbp = $resolvedCookies->fbp;   // ?Fbp
$resolvedCookies->cookiesToSet;                  // list<Cookie> to set on the response

The builder validates existing cookie values and upgrades legacy four-segment values to the current five-segment format, builds a new fbc from fbclid (also from the referer), generates an fbp when the request has none, and derives the cookie domain (pass your domains or an ETLDPlus1Resolver to the constructor for multi-domain setups). README section added.

Why fromString() stays hand-written

The parameter builder cannot replace the value-object parsing: its parser (preProcess) is private and request-oriented, and its validation is structural only — it happily passes a.b.c.d through as an "existing cookie". So the VO layer keeps the strict format guarantees from #13, and the resolver is where "we stop parsing": a value the builder emits that still cannot be represented as a VO comes back as null (covered by a test).

Notes

  • New direct dependency facebook/capi-param-builder-php: ^1.3.1 — dependency-free (PHP ≥ 7.4). It only ships transitively with facebook/php-business-sdk 26.x, not 25.x, so declaring it directly is required for the lowest matrix anyway.
  • FacebookAds\CookieSettings is not PSR-4 autoloadable (lives in model/, loaded by ParamBuilder via require_once; safe at runtime because the builder always loads first). PHPStan gets the file via scanFiles; the dependency analyser ignores the class. Both config entries carry comments.
  • Client IP deliberately not exposed: the builder's getClientIpAddress() returns the _fbi cookie format, which carries a trailing appendix segment — not a plain IP. Left out rather than re-parsing it here.
  • Once released, Parse the _fbc cookie the way Meta writes it MetaConversionsApiBundle#39 can build on CookieResolver instead of reading cookies itself.

Test plan

  • 7 new CookieResolverTest cases: five-segment pass-through (byte-for-byte), four-segment upgrade + Set-Cookie (max-age 90 days, derived domain), fbc from fbclid, fbp generation, regeneration on invalid appendix, null for builder-accepted-but-malformed values, domain list → cookie domain + subdomain index
  • 105 tests, 100 % line coverage; PHPStan (level max, incl. tests), ECS, dependency analyser, composer normalize all green
  • Infection: MSI 92 % / covered 92 % (thresholds 90/90). The 8 new escaped mutants are the defensive Assert calls guarding the untyped library's return values — not triggerable as long as the library behaves
  • lowest (business-sdk 25.0.0 + builder 1.3.1) on PHP 8.1 — verified locally (105 tests + PHPStan green); also covered by the CI matrix

… builder

Instead of this SDK (and its consumers) hand-parsing the _fbc/_fbp
cookies out of a request, the new Setono\MetaConversionsApi\Cookie
namespace hands the raw request to facebook/capi-param-builder-php,
Meta's own library for exactly this job. It validates existing cookie
values and upgrades them to the current format, builds a new fbc from
the fbclid query parameter, generates an fbp when the request has none,
and reports which cookies to set on the response. The resolver converts
the results into the typed Fbc/Fbp value objects.

Fbc::fromString()/Fbp::fromString() remain the strict typed layer: the
parameter builder has no public single-value parser and its internal
validation is structural only (it passes 'a.b.c.d' through), so it
cannot replace them.

facebook/capi-param-builder-php becomes a direct dependency (it only
ships transitively with facebook/php-business-sdk 26.x, not 25.x).
FacebookAds\CookieSettings does not comply with the package's PSR-4
mapping (it is loaded via require_once), so PHPStan scans the file
explicitly and the dependency analyser ignores the class.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant