integrated/slug-bundle
A Laravel bundle for generating clean, URL-friendly slugs from strings, helping you build readable routes and permalinks with consistent, SEO-friendly formatting across your application.
Architecture fit — poor, and that is the first thing to resolve. The artifact is a Symfony bundle (integrated/slug-bundle, container-tagged event listeners, Doctrine lifecycle hooks), not a Laravel package. There is no Illuminate\Support\ServiceProvider, no package auto-discovery, no config/slug.php. A TPM should treat this as an architecture mismatch that must be surfaced before any backlog item is written: the only reusable part is a pure-PHP string-to-slug transform, and the wiring — which is the bundle's actual value — has no execution path in our stack.
Integration feasibility. A Composer install likely succeeds in the sense that the bundle class sits inert, but the real feasibility question is version-constraint conflict against Laravel's pinned Symfony components (console, http-foundation, process, string). The second feasibility question is the transform itself: its output quality, transliteration coverage, and truncation behavior must be exercised against our own title corpus, not synthetic strings. Both are cheap to check and should gate the decision.
Technical risk.
Key questions a TPM should put to engineering before committing.
Recommendation: do not adopt as a dependency. Use it as a reference implementation. The capability — normalize, transliterate, lowercase, replace separators, de-duplicate — is commodity: roughly 50–150 lines against Str::slug() or cocur/slugify for the transform, plus an Eloquent observer or a saving hook for the persistence behavior. Buying a 0-dependency, 1-star bundle to save a few hours of engineering expands our audit and patching surface for negligible return.
Stack fit. Laravel + Eloquent + service container, no Doctrine kernel. The port target is exactly two things: one pure-PHP slugger service bound in a service provider, and one observer (or model trait hook) that populates the field. Everything else in the bundle is scaffolding we discard.
Migration path.
composer.json for Symfony version constraints, call the slugger class standalone against a golden-file corpus built from our own product titles.Str::slug() / cocur/slugify on our corpus, vendor the single class with MIT attribution in a NOTICE file and drop the bundle wiring. If it doesn't, use the alternative. Our integration code is identical either way, which is the point — the decision is cheap and reversible.Compatibility checks to run during the spike. PHP runtime version against the package's support matrix; no hard pin on symfony/string that collides with ours; deterministic truncation to our slug column length rather than a hard error on long titles; correctness under utf8mb4 collation.
Sequencing (one sprint, behind a feature flag).
slug column added nullable, non-unique.-2, -3); add the unique index in a follow-up migration once the table is clean.Guardrail. Auto-regenerate on update should be off by default, or scoped to never-published records. URL stability is a product requirement, not an implementation detail. If we ever do regenerate, the old-slug → new-slug 301 redirect table ships in the same change, not a follow-up ticket. No slugger package gives us that table, which is precisely why this belongs to product.
Maintenance. The realistic ongoing cost is the vendored class — a pure function, near zero. What we buy by not depending on the package is upgrade independence; what we pay is ownership. Budget roughly half a day per year for transliteration table refreshes, plus scoped work whenever we add a locale. That is a far better liability profile than tracking a Symfony major on an unmaintained bundle.
Support. 1 star / 0 dependents means upstream support is the maintainer's goodwill: no SLA, no security advisory channel we can rely on, no downstream users generating field-tested edge cases. If any of this code enters production, name an internal owner in the service catalogue. An unowned slug library becomes a mystery box within two quarters.
Scaling. Generation runs per write, not per read, and is CPU-trivial — negligible request-path impact. Watch two things instead: (a) the uniqueness lookup adds one indexed read per write, fine at our volume but a problem during bulk import unless batched, and (b) the backfill must be chunked and throttled or it will hold locks and drive replication lag. Both are operational hazards of our rollout, not of the package.
Failure modes to instrument.
Ramp-up. Low — well under a day for an engineer comfortable with Laravel observers. The genuine unknown is not the code but the input corpus. Expect QA on day one to surface transliteration and length-truncation cases that no test in a 1-star repo covers. Make a golden-file suite seeded from our own titles the acceptance gate, and treat transliteration quality as the thing we are actually evaluating — it is the entire value of any slugger, and the worst place to inherit risk is an unmaintained package.
Bottom line for the roadmap. Slugs are table stakes, not differentiation. Fund this as an implementation detail inside the content-modeling epic, not as its own initiative. The decisions that actually matter are product decisions and are independent of which library we pick: slug immutability after publish (with redirect coverage), collision policy, per-locale uniqueness, and transliteration quality for non-Latin content. Get those specified, then let engineering write the ~50 lines.
How can I help you explore Laravel packages today?