Installation:
composer require autologic-web/redirect-bundle
Add to bundles.php (Symfony 4+) or AppKernel.php (Symfony <4):
Autologic\Bundle\RedirectBundle\AutologicRedirectBundle::class => ['all' => true],
Basic Configuration:
Add a single rule in config/packages/autologic_redirect.yaml (Symfony 4+) or app/config.yml:
autologic_redirect:
rules:
- { pattern: '/old-url', redirect: '/new-url' }
First Use Case:
/blog/post-1 → /articles/2023/post-1), add a rule to catch 404s and redirect users:
rules:
- { pattern: '/blog/post-1', redirect: '/articles/2023/post-1', status: 301 }
Event-Driven Redirection:
The bundle listens to kernel.exception events. When a NotFoundHttpException (404) occurs, it checks configured regex patterns against the requested URI. If a match is found, it returns a RedirectResponse instead of the 404.
Regex Matching:
/old-url matches /old-url?query=1)..* for dynamic segments (e.g., /blog/.* catches all /blog/* routes).rules:
- { pattern: '/blog/([0-9]+)/old-post', redirect: '/articles/$1/new-post' }
Dynamic Redirects with Parameters:
Use regex groups ($1, $2) in the redirect field to capture and reuse URI segments:
rules:
- { pattern: '/user/([a-z]+)', redirect: '/profile/$1' }
/user/john → /profile/john.Domain-Specific Rules:
Handle subdomains or cross-domain redirects with %base_domain%:
rules:
- { pattern: '/au\..+?\.[^\/]+.*blog/old-post',
redirect: 'au.%base_domain%/news/new-article' }
Fallback Rules: Order rules by priority (first match wins). Use broader patterns as fallbacks:
rules:
- { pattern: '/blog/2023/.*', redirect: '/articles/2023/$0' } # Exact match
- { pattern: '/blog/.*', redirect: '/articles/$0' } # Fallback
SEO-Friendly Redirects:
Use status: 301 for permanent redirects (default). Switch to 302 during testing to avoid caching issues.
Logging Unmatched 404s:
Enable logging in config/services.yaml to track unhandled 404s:
services:
Autologic\Bundle\RedirectBundle\Event\RedirectListener:
arguments:
- '@autologic_redirect.service.redirect_service'
- '@logger'
tags:
- { name: kernel.event_listener, event: kernel.exception }
Conditional Redirects:
Combine with Symfony’s RequestContext or Router to dynamically adjust redirects based on environment or user roles.
Testing:
Use Symfony’s HttpKernel to test redirect logic:
$client = static::createClient();
$client->request('GET', '/old-url');
$this->assertEquals(301, $client->getResponse()->getStatusCode());
$this->assertEquals('/new-url', $client->getResponse()->getTargetUrl());
Regex Over-Matching:
/.* are greedy. Use non-greedy quantifiers (.*?) to avoid unintended matches:
# Bad: Matches everything after `/blog`
- { pattern: '/blog/.*', redirect: '/articles/$0' }
# Good: Stops at the first `/`
- { pattern: '/blog/.*?/', redirect: '/articles/$0' }
Protocol Mismatches:
protocol is not set, the bundle inherits the original request’s protocol (e.g., http:// in dev, https:// in prod).protocol: 'https://') if redirects must always use HTTPS.Absolute vs. Relative Redirects:
absolute: false forces relative redirects (e.g., /new-url instead of https://example.com/new-url).Forwarding Quirks:
forwarding: true appends the original path to the redirect (e.g., /new-url/old-url).Case Sensitivity:
(?i) for case-insensitive matching:
rules:
- { pattern: '(?i)/old-url', redirect: '/new-url' }
Caching Issues:
status: 302 during development to bypass caches.Base Domain Placeholder:
%base_domain% only works if the original request includes a host. Test locally with localhost or a custom Host header.Log Unmatched 404s: Enable logging (as shown above) to identify missing redirect rules.
Test Regex Patterns:
Use PHP’s preg_match to validate patterns before deploying:
var_dump(preg_match('#/old-url#', '/old-url?query=1')); // Should return 1
Check Event Listener Order:
Ensure no other bundle (e.g., SensioFrameworkExtraBundle) interferes with the kernel.exception event. Use debug:event-dispatcher to inspect listener order:
php bin/console debug:event-dispatcher kernel.exception
Environment-Specific Rules:
Override config per environment (e.g., config/packages/dev/autologic_redirect.yaml) to disable redirects in dev:
autologic_redirect:
rules: [] # Disable redirects in dev
Custom Redirect Logic:
Override the RedirectService to add logic (e.g., user-based redirects):
services:
autologic_redirect.service.redirect_service:
class: App\Service\CustomRedirectService
arguments:
- '@autologic_redirect.service.redirect_service'
Dynamic Rule Loading:
Load rules from a database or API by extending the RedirectService and overriding getRules().
Add Metadata to Redirects:
Extend the RedirectResponse to include custom headers (e.g., X-Redirect-Reason):
use Symfony\Component\HttpFoundation\RedirectResponse;
$response = new RedirectResponse('/new-url', 301);
$response->headers->set('X-Redirect-Reason', 'Route renamed');
Pre-Redirect Hooks:
Subscribe to kernel.request to modify the request before redirect logic runs (e.g., rewrite URLs):
$event->setRequest($event->getRequest()->duplicate([], null, ['_route' => 'new-route']));
How can I help you explore Laravel packages today?