Installation:
composer require atoolo/rewrite-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Atoolo\RewriteBundle\AtooloRewriteBundle::class => ['all' => true],
];
Configuration:
Add a basic config/packages/atoolo_rewrite.yaml:
atoolo_rewrite:
rules:
- pattern: '/old-url'
target: '/new-url'
permanent: true
First Use Case:
Test URL rewrites by accessing /old-url—it should redirect to /new-url (if permanent: true) or rewrite internally.
config/packages/atoolo_rewrite.yaml: Central configuration for rewrite rules.src/Controller/: Example controllers demonstrating integration (if any).tests/: Unit/integration tests for edge cases (e.g., SameNavigationUrlRewriteHandler).Rule-Based Rewriting: Define rules in YAML/array format:
rules:
- pattern: '/blog/old-post'
target: '/articles/new-post'
priority: 100 # Higher priority = earlier execution
context: ['web'] # Optional: Limit to specific contexts (e.g., 'api', 'web')
{slug} and resolve them via UrlRewriteContext:
rules:
- pattern: '/products/{slug}'
target: '/catalog/{slug}'
resolver: App\Resolver\SlugResolver # Custom resolver class
Context-Aware Rewriting:
Leverage UrlRewriteContext to conditionally apply rules (e.g., per locale/microsite):
context:
locales:
- en
- de
microsites:
- shop1
- shop2
Override rules per context:
rules:
- pattern: '/contact'
target: '/support'
context: ['web', 'en'] # Only for English web context
Event-Driven Integration:
Listen to atoolo.rewrite.pre_rewrite and atoolo.rewrite.post_rewrite events to modify behavior:
// src/EventListener/CustomRewriteListener.php
public function onPreRewrite(RewriteEvent $event) {
if ($event->getRequest()->getPathInfo() === '/admin') {
$event->setTarget('/dashboard');
}
}
Controller Integration:
Use the RewriteAwareTrait in controllers to access rewrite logic:
use Atoolo\RewriteBundle\DependencyInjection\RewriteAwareTrait;
class ProductController {
use RewriteAwareTrait;
public function show(Product $product) {
$rewrittenUrl = $this->rewriteService->rewrite(
'/old-product-url',
new UrlRewriteContext(['locale' => 'en'])
);
// ...
}
}
permanent: true for 301 redirects (e.g., /old-page → /new-page).{id}) and pass them to resolvers.rules:
- pattern: '/.*'
target: '/404'
priority: -100
Rule Order Matters:
/blog/.*) precede generic ones (e.g., /.*).bin/console debug:atoolo-rewrite to list active rules.Context Mismatches:
context constraints won’t apply if the current context (e.g., locale) doesn’t match. Verify contexts in logs:
# Enable debug logging
atoolo_rewrite:
debug: true
Circular Redirects:
A → B → A. Test with:
bin/console debug:router | grep "rewrite"
Resolver Dependencies:
Atoolo\RewriteBundle\Resolver\ResolverInterface. Forgetting this causes RuntimeExceptions.Symfony Router Conflicts:
priority to force precedence. Example:
# Ensure rewrite runs before Symfony's router
framework:
router:
resource: "%kernel.project_dir%/config/routing.yaml"
rewrite_bundle_priority: 200 # Higher than default (100)
Log Rewrite Events:
Enable debug mode in config/packages/dev/atoolo_rewrite.yaml:
debug: true
Check var/log/dev.log for resolved rules and context data.
Dry-Run Rules:
Use the atoolo:rewrite:validate command to test rules without executing them:
bin/console atoolo:rewrite:validate /old-url
Common Errors:
| Error | Cause | Fix |
|---|---|---|
No rewrite rule found |
Missing or misconfigured pattern |
Add a catch-all rule or check YAML. |
Resolver not found |
Invalid resolver class |
Verify the class implements the interface. |
Context not supported |
Unmatched context |
Adjust contexts or remove constraints. |
Invalid target URL |
Malformed target (e.g., relative path) |
Use absolute paths (e.g., /new-url). |
Custom Handlers:
Extend Atoolo\RewriteBundle\Handler\AbstractRewriteHandler to create reusable logic (e.g., TrailingSlashHandler).
Dynamic Rule Loading:
Load rules from a database or API by implementing Atoolo\RewriteBundle\Loader\LoaderInterface:
class DatabaseLoader implements LoaderInterface {
public function load(array $config): array {
return $this->fetchRulesFromDatabase();
}
}
Register it in config/packages/atoolo_rewrite.yaml:
loader: App\Loader\DatabaseLoader
Middleware Integration: Use Symfony’s middleware to pre-process requests:
// src/Middleware/RewriteMiddleware.php
public function handle(Request $request, callable $next) {
$rewrittenUrl = $this->rewriteService->rewrite($request->getUri());
if ($rewrittenUrl !== $request->getUri()) {
return new RedirectResponse($rewrittenUrl);
}
return $next($request);
}
Testing:
Mock the RewriteService in PHPUnit:
$rewriteService = $this->createMock(RewriteService::class);
$rewriteService->method('rewrite')->willReturn('/rewritten-url');
$this->container->set(RewriteService::class, $rewriteService);
Lang Prefix Handling:
The bundle automatically handles /{locale}/ prefixes if framework.default_locale is set. For custom locales, ensure they’re listed in atoolo_rewrite.context.locales.
Microsite Support:
Use pparam (page parameter) for microsite-specific rules:
rules:
- pattern: '/{pparam}/product'
target: '/{pparam}/catalog'
Access pparam via $event->getPageParameter() in listeners.
Performance: Cache rules in production by enabling:
cache: true
cache_lifetime: 3600 # 1 hour
How can I help you explore Laravel packages today?