jongotlin/ratsit-bundle
A PHP bundle that integrates the Ratsit API for Swedish people and company lookups, letting developers fetch address, age, and contact details directly in their applications. Lightweight and straightforward to configure, though documentation and community adoption are still limited.
Architecture fit — the headline is a framework-layer mismatch, not a code-quality problem. jongotlin/ratsit-bundle is a Symfony bundle: a Bundle subclass, a DependencyInjection extension, and a YAML configuration tree loaded from config/packages/*.yaml. Laravel has no bundle concept, no compiler passes, and no YAML config tree, so the package cannot boot in a Laravel application as shipped. Its only Laravel-relevant asset is the underlying jongotlin/ratsit client, which is plain PHP and installable via Composer. The TPM framing that follows from this: we are not evaluating a package, we are evaluating a data vendor, and the package's contribution (DI wiring, config schema) is roughly 100 lines we would write ourselves in a day.
Integration feasibility — moderate, contingent on the underlying client's coupling and transport hygiene. Direct library consumption is a routine Composer install. The feasibility questions worth 30 minutes of engineering time are: does the core pull symfony/* transitively (http-client, serializer, options-resolver)? Symfony components coexist with illuminate/* but are a recurring source of version-pin conflicts and a maintenance tax. Equally important: does the client accept an injected PSR-18/PSR-17 HTTP client and PSR-3 logger, or does it instantiate its own transport? If the latter, we cannot apply our own retry, timeout, circuit-breaker, or redaction policy, which is disqualifying for a PII-bearing call path.
Technical risk — concentrated in maturity, vendor dependency, and legal basis, in that ascending order of severity.
SECURITY.md, no CVE history in either direction, no production references. "No known vulnerabilities" and "never examined" are different statements, and only the second applies here.Key questions
symfony/*?Stack fit. Target Laravel 10/11/12 on PHP 8.2+. Do not install the bundle; the symfony/* transitives buy nothing. Confirm Octane and queue-worker safety early — long-lived workers cache container state, so the client must be stateless and free of per-request mutable state (auth tokens aside, which should be resolved per call or refreshed explicitly).
Migration path — four options, in preference order:
| Option | Effort | When to choose |
|---|---|---|
A. Consume jongotlin/ratsit directly, wrap in a RatsitServiceProvider + config/services.php entry + facade |
2–3 days | Default. Skip the bundle entirely. |
| B. Port the bundle's DI wiring by reading its extension and config tree as a blueprint for our provider | 3–4 days | Only if the bundle encodes non-obvious object-graph assembly (custom HTTP client, signer, middleware stack) worth preserving. |
| C. Sidecar / queue-isolated worker in a minimal Symfony or plain-PHP service, called over HTTP or a queue | 1–2 weeks | If the client drags in incompatible dependencies, holds credentials we do not want in the Laravel container, or must run on a different egress/network boundary. |
| D. Defer / select an alternate vendor | — | If the legal basis, vendor terms, or threat model fails review — or if UC, Creditsafe, Bisnode/D&B, or Veriff/Persona fit better on coverage and price. |
Compatibility. Pin the library to an exact version in composer.json, not a caret range — pre-1.0 semver offers no stability guarantee. Register bindings as singletons only where the object is genuinely stateless. Keep the config file free of closures so php artisan config:cache works.
Sequencing.
App\Services\Registry\PersonLookup with findByPersonnummer(Personnummer $ssn): ?PersonData — and bind the vendor behind it. Nothing outside the adapter may import Jongotlin\Ratsit\*.Maintenance. We own the Laravel glue permanently, and we are tracking a pre-1.0 upstream with a single maintainer. Budget for breakage on minor releases, and note that upstream fixes will arrive in Symfony-bundle shape and never apply to our adapter directly — we re-derive them. Mitigate with an internal fork or vendored-patch policy under MIT, a pinned lockfile, and a dependency-diff gate in CI.
Support. MIT with no SLA, no commercial backing, no escalation path. The supportable contract is with Ratsit, not with the package — negotiate terms, rate limits, and change notice with the vendor, and treat the PHP code as unsupported glue we maintain. Name a single internal owner who has read the client's source.
Scaling. The binding constraint is commercial, not technical: billing is per request, so cost scales with call volume rather than CPU. Cache by personnummer for 24h–7d, tag entries for purge-on-request, and do not cache negative results for long — a "not found" may mean the person was registered yesterday. Queue lookups on a low-concurrency worker so a slow third-party call never blocks a web request; back off explicitly on 429s rather than retrying into the rate limit. Model monthly cost at realistic signup volume before committing — a per-lookup price that looks trivial becomes a line item at scale.
Failure modes, ranked by business severity:
NotFound from VendorError in the adapter's return type and test it explicitly.PersonLookup seam buys us.Ramp-up. Engineering ramp is small: 2–3 days for a competent Laravel developer to wire the client, normalise personnummer, add caching, and write tests. Compliance ramp is the real cost — DPA negotiation, lawful-basis documentation, notice updates, and a retention policy are typically weeks, involve legal and often a DPO, and gate the feature regardless of how fast the code lands. Plan the two tracks in parallel and do not let a green build signal readiness to ship.
Recommendation. Do not adopt jongotlin/ratsit-bundle. Approve a one-week vendor-selection spike that returns a build-vs-buy decision on Ratsit versus two alternates, plus a legal review of the lawful basis for the specific flow. If Ratsit wins on merit, consume the underlying jongotlin/ratsit library behind an internal interface and own the ~100 lines of container glue — that is cheaper than inheriting an unmaintained wrapper, and it is the only version of this decision we can support in production.
How can I help you explore Laravel packages today?