pgs-soft/hashid-bundle
Symfony bundle that integrates Hashids to encode and decode numeric IDs, helping obfuscate database identifiers in URLs. Provides a configurable service and Twig filters for generating short, unique hashes in templates and routes, with simple bundle configuration.
Architecture fit. The first thing to flag is a naming mismatch: pgs-soft/hashid-bundle is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no config/hashid.php publishable config, and no Laravel facade. In a Laravel codebase this package cannot be dropped in as-is; it would need a thin adapter (service provider + config + facade) around the underlying hashids/hashids library. The underlying library itself is framework-agnostic, PSR-friendly, and trivial to wire into Laravel's container, so the capability fits a Laravel stack well even though the package does not.
Integration feasibility. High, if we treat the bundle as a reference implementation rather than a dependency. The bundle is essentially a DI wrapper, a Twig extension, and a route-parameter converter around hashids/hashids. In Laravel the equivalent work is: bind a singleton hasher in a service provider, add a Hashid cast or route-binding resolver, and override getRouteKey()/resolveRouteBinding() on affected models. That is roughly 1–3 days of work for a competent engineer, most of it spent on tests and URL-generation audit rather than the hashing itself.
Technical risk.
.env, repo history, logs, error pages) can enumerate every ID. This must not be positioned as an access-control or anti-IDOR control; authorization must remain server-side.hashids/hashids is the real long-term surface and should be assessed separately (it is more established but still low-velocity).BIGINT IDs (beyond 2^53) and 32-bit PHP builds are a real edge case; verify against the largest ID we expect in each table.Key questions.
URL::signedRoute) or UUID/ULID primary keys instead?Stack fit. Poor as a package, good as a pattern. Recommendation: do not install the Symfony bundle in a Laravel app. Instead, depend on hashids/hashids directly and implement a small in-house HashidService plus a route-binding trait. If the team is actually on Symfony, the bundle is a reasonable convenience wrapper, but with 13 stars and stale releases the same fork-and-own calculus applies.
Migration path.
BIGINT-scale IDs.HashidService::encode() / ::decode(), bound as a singleton, config in config/hashid.php, salt from env. No route changes yet.HasHashidRouteKey trait applied per model (not globally — blast radius matters). Override getRouteKey() and resolveRouteBinding(); keep integer resolution as a fallback so inbound integer URLs continue to work during transition.route() call, url(), Blade link, API resource, email template, sitemap generator, and PDF export that embeds a model ID. This is the largest and least glamorous work item; budget accordingly.Compatibility.
composer.json will not know about current Laravel releases, and even the underlying library has had major-version naming churn (Hashids vs Hashids\Hashids).Sequencing. Salt/config and service first → per-model trait → URL generation sweep → dual-read + redirects → fallback removal. Keep it behind a feature flag per entity so a single bad model doesn't take down checkout or auth flows. Do the sweep before enabling generation, not after — otherwise you ship half-hashed, half-integer URLs and break nothing visibly until a customer clicks a bookmark.
Maintenance. We will effectively own this code. With 0 dependents and a 2023 last release, upstream responsiveness is not something to plan around. MIT allows vendoring; vendoring a ~300-line library into app/Support (or an internal Composer package with a replace) removes the supply-chain question entirely and costs us nothing but a composer update. Treat the underlying hashids/hashids dependency as the thing to watch, not the Symfony wrapper.
Support. Community-only, no SLA, no vendor. Internal ownership is the only realistic support model. Document the salt, the alphabet, the min-length, and — critically — the reversibility property in the runbook so no one later mistakes this for a security boundary during a threat model review or a pen test debrief.
Scaling. Negligible compute cost — Hashids is a cheap arithmetic/string transform, microseconds per call, no I/O, no external service. It scales linearly with app servers and is safely cacheable. The scaling risk is not CPU; it is URL cardinality and cache-key churn: every cached page, CDN entry, and search index entry keyed by URL becomes tied to a salt that we may need to rotate. If the app is heavily cache-keyed on URLs, salt rotation becomes a cache-invalidation event, not just a link-breaking event.
Failure modes.
decode() on malformed input → returns empty array; naive code that assumes $decoded[0] will throw or, worse, silently bind to ID 0/null. Mitigation: always guard, and return 404 on decode failure.Ramp-up. Low for the hashing itself; the real onboarding cost is organizational. Engineers need roughly half a day to learn the library and the trait, and then a recurring reminder in code review that Hashids ≠ encryption. The riskiest ramp-up failure is a well-meaning engineer "improving security" by using the hash as an authorization token. Given the low package score (1.59) and zero dependents, I would not adopt the Symfony bundle directly, but the pattern is cheap, reversible, and worth the opportunity score of 4.41 if and only if the requirement is genuinely cosmetic or anti-scraping — and if the team is prepared to own a small vendored utility rather than depend on a dormant third-party bundle.
How can I help you explore Laravel packages today?