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

Redirect Bundle Laravel Package

enhavo/redirect-bundle

Enhavo Redirect Bundle is a subtree split of the Enhavo CMS, an open-source PHP project built on the full-stack Symfony framework for flexible, complex data structures. See the main repository for full documentation and details.

View on GitHub
Deep Wiki
Context7

Getting Started

The README is a stub — it exists only to point you at the monorepo. Treat enhavo/EnhavoRedirectBundle as a read-only mirror of a subtree split, not a standalone library. Your first stop is not this repo but enhavo/enhavo: browse src/Enhavo/Bundle/RedirectBundle there for the entity, repository, manager service, admin routes and any Resources/config/routing.yaml. The split repo has no issue tracker of its own; bug reports and docs live upstream.

Minimal path to a working install in an existing Enhavo project:

composer require enhavo/redirect-bundle

Then register the bundle alongside the rest of Enhavo in config/bundles.php:

Enhavo\Bundle\RedirectBundle\EnhavoRedirectBundle::class => ['all' => true],

Import its routing (Enhavo projects normally centralise this under config/routes/enhavo.yaml); check the bundle's Resources/config/routing directory for the exact resource name rather than guessing. Finally, make sure the Doctrine schema exists — either run the bundle's migrations or diff the schema:

bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate

First use case: an editor renames a landing page and you need the old URL to keep working. Create the from → to pair (through the admin UI if the bundle ships one, or directly via the repository), flush caches, then verify with a real request:

curl -sI https://your-site.test/old-url | grep -Ei '^(HTTP|location)'

You want a 301 and a Location: pointing at the new path. If you get a 404, the request listener isn't wired up — that's the diagnosis to chase, not the data.

Implementation Patterns

Editor-managed redirects vs. programmatic ones. In day-to-day Enhavo use, redirects are content: editors add a handful via the admin interface when a page moves. Reach for code only for the cases editors can't cover — bulk imports and automatic creation on slug change. Keep those two paths writing to the same entity so the admin list stays the single source of truth.

Bulk import from a legacy site. Parse the old site's URL map (CSV of old_path,new_path), normalise both sides, then persist in batches:

$em = $this->getDoctrine()->getManagerForClass(Redirect::class);

foreach ($rows as $i => $row) {
    if ($repository->findOneBy(['from' => $row['old']])) {
        continue; // idempotent re-runs
    }
    $em->persist($this->factory->create($row['old'], $row['new']));
    if ($i % 100 === 0) {
        $em->flush();
        $em->clear();
    }
}
$em->flush();

Wrap it in a console command, not a migration — migrations that depend on content tables are painful to replay.

Auto-redirect on slug change. The highest-value pattern: when a page's slug changes, the old route should not 404. Hook the update event of your content entity (a Doctrine postUpdate listener or your admin controller's update flow) and create a redirect from the previously generated URL to the new one. Prefer storing route names plus parameters over absolute URLs if the bundle's entity supports it, so the redirect survives a domain migration; otherwise store the path, not the host.

Resolution order / integration with the 404 flow. The bundle's request handling is what turns a DB row into a RedirectResponse. Understand where it hooks in — usually a kernel.request or kernel.exception listener — so that real routes always win over a redirect row. If you have wildcard or prefix needs (/blog/*), check whether the entity supports pattern matching before you build it yourself; if you do need a custom matcher, write a listener with high-enough priority that delegates to the bundle's manager for exact matches and only falls back to your regex logic.

Testing. Prove redirects in functional tests, not unit tests — the value is in the wiring:

$this->client->request('GET', '/old-url');
$this->assertResponseStatusCodeSame(301);
$this->assertResponseRedirects('/new-url');

Seed fixtures for dev/test; never let local runs depend on data you entered by hand in the admin, or CI will be green on your machine and red on everyone else's.

Gotchas and Tips

The split is the biggest gotcha. Composer tags mirror the monorepo's releases, and the bundle declares dependencies on sibling enhavo/* packages (ResourceBundle, admin, Doctrine helpers). Installing it standalone in a non-Enhavo Symfony app will drag in far more than a redirect table. In practice, install via the Enhavo meta-package and pin versions; do not expect this repo's README, CHANGELOG or issue tracker to be useful.

Exact-match lookups bite. DB-backed redirects are almost always matched against the request path verbatim. Trailing slashes, case, and query strings all cause misses, and — worse — cause duplicate rows that look correct in the admin list but never fire. Normalise on write (strip trailing slash, lowercase, strip the query string) and apply the identical normalisation on read.

Loops and chains. Validate from !== to in your import and in any admin form extension. If you allow A→B and B→C, cap the chain at one hop or you'll get infinite redirects and browser cache poisoning that only surfaces after a deploy.

Multi-site leakage. If your Enhavo instance serves more than one host, check the entity schema for a host/site column before you rely on the admin. Without one, /kontakt → /contact defined for site A will silently apply to site B. If the column doesn't exist, this is a legitimate place to extend the entity and form via Enhavo's admin configuration rather than fight it.

Caching. Redirects are consulted on the miss path, which is exactly the path you want to be cheap. High-traffic legacy URLs warrant an HTTP cache in front. Conversely, page caches and reverse proxies can mask a freshly added redirect — flush after adding one, and remember that browsers cache 301s aggressively, so test with curl and incognito, not your daily browser.

Debugging a redirect that won't fire, in order: is the listener/controller registered (bin/console debug:router | grep -i redirect, bin/console debug:event-dispatcher | grep -i redirect)? Is the row enabled? Does the stored from exactly match the normalised request path? Did an earlier route already match? That sequence resolves nearly every report.

Extension points. Enhavo leans on service overrides and compiler passes; overriding the redirect manager or repository in your app's services.yaml is the sanctioned way to add caching or custom matching. Extra fields (HTTP status, host, expiry, notes) belong in the admin form configuration and a Doctrine schema update — keep them nullable so the bundle's own code paths keep working.

SEO hygiene. Use 301 for permanent moves and 302 sparingly; never redirect to a target that itself 404s (assert this in the import command). And don't use redirects as a substitute for generating URLs from routes in templates — they exist for inbound links you don't control.

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.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table