Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Short Url Bundle Laravel Package

genj/short-url-bundle

genj/short-url-bundle is a Symfony bundle for adding short URL generation and redirection to PHP applications. It helps turn long links into compact, shareable addresses and route visitors to their original destinations with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it's a Symfony bundle, not a Laravel package. genj/short-url-bundle is a Symfony 2-era bundle (Genj\ShortUrlBundle) that hooks into the Symfony router/kernel and resolves a request path to a Doctrine entity, then issues a redirect. There is no service provider, no facade, no config publish tag. On a modern Laravel app you cannot composer require this and get anything working — it was last released 2015-12-24, is archived, and targets PHP 5.x with Symfony 2 components and Doctrine annotations.

So "getting started" splits into two paths:

If you are on a legacy Symfony 2/3 app (the only realistic way to use it):

  1. composer require genj/short-url-bundle — expect to pin old Symfony/Doctrine versions or fight conflict resolution.
  2. Register the bundle in app/AppKernel.php and import its routing from app/config/routing.yml (check Resources/config/routing.* in the bundle for the exact resource path).
  3. Confirm the entity mapping (Resources/config/doctrine/*.orm.xml or annotations) and run doctrine:schema:update --dump-sql to see the table it wants.
  4. Insert one row (slug → target URL), clear the cache, and request /{slug} to watch the redirect fire.
  5. Where to look first, in order: the bundle's routing file, the controller/listener that performs RedirectResponse, the entity, then the DI service definitions.

If you are on Laravel (the assessment's lens): the only sensible first use case is reimplementing the idea, which takes about an hour. A short_urls table (slug, target_url, status_code, hits, expires_at), a Route::get('/{slug}') registered last, and a controller that does redirect($target, 301). That gives you everything this bundle gives you, on a supported stack, and is what I'd recommend over any interop attempt.

The genuine first use case either way: marketing/campaign slugs (/spring-sale → landing page) where the destination changes without redeploying.

Implementation Patterns

Seeding and managing links. The bundle is a redirect mechanism, not an admin tool — there's no CRUD UI. In Symfony you'd create entities in a console command or data fixture; in a Laravel port, a model plus an artisan command or Nova/Filament resource. Treat slug creation as a first-class operation: normalize to lowercase, reject reserved words (admin, api, login), and enforce uniqueness at the DB level rather than in application code.

Route ordering is the whole design. A short-URL resolver is a catch-all, so it must be the last route registered. In Symfony, routing.yml import order decides this; in Laravel, Route::fallback() or a /{slug} route declared after everything else. Constrain the slug with a regex ([A-Za-z0-9_-]+) so you don't shadow legitimate nested paths, and consider a prefix (/s/{slug}) if you want zero collision risk.

Status codes carry meaning. Use 302 for links you may retarget (campaigns, A/B tests) and 301 only for permanent moves — browsers cache 301s aggressively and you cannot take them back. If the bundle hardcodes one, that's a reason to wrap or replace the controller.

Counting hits without hurting latency. Incrementing a counter on every redirect means a write per request. Batch it (queue job, Redis INCR, or a nightly rollup), or accept the write but keep the table narrow and the index on slug covering.

Integration tips for a Laravel-side port:

  • Cache the slug→target lookup (Cache::remember with a short TTL) and bust on write; the DB hit is pure overhead on a redirect path.
  • Return the redirect from a controller, not middleware, unless you need it app-wide.
  • Add expires_at and soft-disable rather than deleting rows — dead campaign links should 410, not 404.
  • If you need multi-domain or locale-aware short links, key the lookup on (host, slug) from day one; retrofitting is painful.

Extension points, if you must stay on the bundle: override the routing resource in your app config, decorate the redirect service, or subclass the controller. Given it's archived, overriding is cheaper than forking — but a 40-line replacement controller is cheaper than both.

Gotchas and Tips

  • Archived and unmaintained. No security patches, no PHP 8 compatibility, no Symfony 5+. Doctrine annotation mapping from 2015 will not load under modern Doctrine without conversion to attributes/XML. Audit before considering it at all.
  • Catch-all route swallows 404s. A /{slug} route registered early makes every unknown URL hit your resolver, and every real route after it unreachable. Verify with the router debug command (router:debug in Symfony, route:list in Laravel) that ordering is what you think.
  • Redirect loops. A row whose target equals its own slug will loop until the browser gives up. Validate on write that target_url isn't a relative path resolving back to the resolver.
  • Cached 301s during development. Once a browser caches a permanent redirect you'll chase ghosts. Test with 302s or a private window, and prefer 302 as the default.
  • Case and trailing-slash sensitivity. /Promo vs /promo, /promo/ vs /promo are different routes. Normalize on write and either redirect or 404 the variants deliberately.
  • Schema drift. The bundle's mapping may specify column lengths/types that clash with your existing short_url table, or a table name you didn't expect. Always run doctrine:schema:validate and inspect the generated SQL before applying.
  • Debugging path. Symfony profiler → request/response panel shows which controller fired and where the redirect came from; if nothing fires, the route isn't matching (ordering or regex constraint). Add temporary logging at the top of the resolver before touching anything else.
  • Migration tip for Laravel teams: the schema is trivial (id, slug unique, target_url, status_code, hits, expires_at, timestamps). Copy the concept, not the code — you'll spend less time than making a 2015 Symfony bundle coexist with a modern framework, and you'll get tests, caching, and queueing for free.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource