路由高级 #
一、URL生成 #
1.1 控制器中生成URL #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class LinkController extends AbstractController
{
#[Route('/links', name: 'app_links')]
public function links(): Response
{
$url = $this->generateUrl('app_user_show', ['id' => 123]);
return new Response("<a href=\"$url\">User 123</a>");
}
#[Route('/user/{id}', name: 'app_user_show')]
public function show(int $id): Response
{
return new Response("User ID: $id");
}
}
1.2 生成绝对URL #
php
<?php
class UrlController extends AbstractController
{
#[Route('/url-test', name: 'app_url_test')]
public function test(): Response
{
$relativeUrl = $this->generateUrl('app_user_show', ['id' => 1]);
$absoluteUrl = $this->generateUrl('app_user_show', ['id' => 1], UrlGeneratorInterface::ABSOLUTE_URL);
return new Response("
Relative: $relativeUrl<br>
Absolute: $absoluteUrl
");
}
}
1.3 使用Router服务 #
php
<?php
use Symfony\Component\Routing\RouterInterface;
class UrlService
{
public function __construct(
private RouterInterface $router
) {}
public function generateUserUrl(int $id): string
{
return $this->router->generate('app_user_show', ['id' => $id]);
}
public function generateAbsoluteUrl(int $id): string
{
return $this->router->generate(
'app_user_show',
['id' => $id],
RouterInterface::ABSOLUTE_URL
);
}
}
1.4 Twig模板中生成URL #
twig
{# 相对URL #}
<a href="{{ path('app_user_show', {id: user.id}) }}">查看用户</a>
{# 绝对URL #}
<a href="{{ url('app_user_show', {id: user.id}) }}">查看用户</a>
{# 带查询参数 #}
<a href="{{ path('app_search', {q: 'symfony', page: 1}) }}">搜索</a>
{# 当前URL #}
<p>当前URL: {{ app.request.uri }}</p>
{# 检查当前路由 #}
{% if app.request.attributes.get('_route') == 'app_home' %}
当前是首页
{% endif %}
二、路由条件 #
2.1 请求方法条件 #
php
<?php
class ApiController extends AbstractController
{
#[Route('/api/users', name: 'api_users_get', methods: ['GET'])]
public function getUsers(): Response
{
return $this->json(['users' => []]);
}
#[Route('/api/users', name: 'api_users_post', methods: ['POST'])]
public function createUser(): Response
{
return $this->json(['status' => 'created'], 201);
}
#[Route('/api/users/{id}', name: 'api_users_put', methods: ['PUT'])]
public function updateUser(int $id): Response
{
return $this->json(['status' => 'updated']);
}
#[Route('/api/users/{id}', name: 'api_users_delete', methods: ['DELETE'])]
public function deleteUser(int $id): Response
{
return $this->json(['status' => 'deleted']);
}
}
2.2 域名条件 #
php
<?php
#[Route('/api', host: 'api.example.com')]
class ApiController extends AbstractController
{
#[Route('/users', name: 'api_users')]
public function users(): Response
{
return $this->json(['users' => []]);
}
}
#[Route('/admin', host: '{subdomain}.example.com', requirements: ['subdomain' => 'admin|manage'])]
class AdminController extends AbstractController
{
#[Route('/dashboard', name: 'admin_dashboard')]
public function dashboard(string $subdomain): Response
{
return new Response("Admin Dashboard on $subdomain.example.com");
}
}
2.3 协议条件 #
php
<?php
#[Route('/secure', schemes: ['https'])]
class SecureController extends AbstractController
{
#[Route('/payment', name: 'secure_payment')]
public function payment(): Response
{
return new Response('Secure Payment Page');
}
}
2.4 表达式条件 #
php
<?php
use Symfony\Component\ExpressionLanguage\Expression;
class ConditionalController extends AbstractController
{
#[Route(
'/api/internal',
name: 'api_internal',
condition: "request.headers.get('X-API-Key') === 'secret'"
)]
public function internal(): Response
{
return $this->json(['status' => 'ok']);
}
#[Route(
'/admin/impersonate',
name: 'admin_impersonate',
condition: "is_granted('ROLE_ADMIN')"
)]
public function impersonate(): Response
{
return new Response('Impersonate User');
}
#[Route(
'/mobile',
name: 'mobile_home',
condition: "request.headers.get('User-Agent') matches '/mobile/i'"
)]
public function mobile(): Response
{
return new Response('Mobile Home');
}
}
2.5 YAML条件配置 #
yaml
# config/routes.yaml
api_routes:
resource:
path: ../src/Controller/Api/
namespace: App\Controller\Api
type: attribute
prefix: /api
host: api.example.com
schemes: [https]
condition: "request.headers.get('X-API-Key') === 'secret'"
methods: [GET, POST]
三、路由重定向 #
3.1 控制器重定向 #
php
<?php
class RedirectController extends AbstractController
{
#[Route('/old-page', name: 'app_old_page')]
public function oldPage(): Response
{
return $this->redirectToRoute('app_new_page');
}
#[Route('/new-page', name: 'app_new_page')]
public function newPage(): Response
{
return new Response('New Page');
}
#[Route('/redirect-with-params', name: 'app_redirect_params')]
public function redirectWithParams(): Response
{
return $this->redirectToRoute('app_user_show', ['id' => 123]);
}
#[Route('/redirect-permanent', name: 'app_redirect_permanent')]
public function redirectPermanent(): Response
{
return $this->redirectToRoute('app_new_page', [], 301);
}
#[Route('/redirect-external', name: 'app_redirect_external')]
public function redirectExternal(): Response
{
return $this->redirect('https://symfony.com');
}
}
3.2 YAML重定向配置 #
yaml
# config/routes.yaml
# 简单重定向
old_blog:
path: /old-blog
controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
defaults:
path: /blog
permanent: true
# 带参数重定向
old_user_profile:
path: /user/{id}/profile
controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
defaults:
route: app_user_show
parameters:
id: $id
permanent: false
3.3 路由级别重定向 #
php
<?php
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
$routes = new RouteCollection();
$routes->add('old_contact', new Route('/contact-us', [
'_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction',
'path' => '/contact',
'permanent' => true,
]));
$routes->add('contact', new Route('/contact', [
'_controller' => 'App\Controller\ContactController::index',
]));
四、URL匹配 #
4.1 手动匹配URL #
php
<?php
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
class UrlMatcherService
{
public function __construct(
private UrlMatcher $urlMatcher
) {}
public function matchUrl(string $url): array
{
try {
$parameters = $this->urlMatcher->match($url);
return [
'route' => $parameters['_route'],
'controller' => $parameters['_controller'],
'params' => array_filter($parameters, fn($key) => !str_starts_with($key, '_'), ARRAY_FILTER_USE_KEY),
];
} catch (\Exception $e) {
return ['error' => $e->getMessage()];
}
}
}
4.2 命令行测试匹配 #
bash
# 测试URL匹配
php bin/console router:match /user/123
# 输出示例
[OK] Route "app_user_show" matches
+--------------+---------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------+
| Route Name | app_user_show |
| Path | /user/{id} |
| Parameters | id: 123 |
+--------------+---------------------------------------------------------+
五、自定义路由加载器 #
5.1 创建路由加载器 #
php
<?php
namespace App\Routing;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class CustomRouteLoader extends Loader
{
private bool $loaded = false;
public function load(mixed $resource, ?string $type = null): RouteCollection
{
if ($this->loaded) {
throw new \RuntimeException('Do not add this loader twice');
}
$routes = new RouteCollection();
$routes->add('custom_home', new Route('/custom', [
'_controller' => 'App\Controller\CustomController::index',
]));
$routes->add('custom_about', new Route('/custom/about', [
'_controller' => 'App\Controller\CustomController::about',
]));
$this->loaded = true;
return $routes;
}
public function supports(mixed $resource, ?string $type = null): bool
{
return $type === 'custom';
}
}
5.2 注册路由加载器 #
yaml
# config/services.yaml
services:
App\Routing\CustomRouteLoader:
tags: [routing.loader]
5.3 使用自定义加载器 #
yaml
# config/routes.yaml
custom_routes:
resource: .
type: custom
六、路由事件 #
6.1 路由事件监听 #
php
<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class RouteSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
$route = $request->attributes->get('_route');
if ($route === 'app_special') {
$request->attributes->set('custom_param', 'value');
}
}
}
6.2 动态修改路由参数 #
php
<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['setLocale', 20]],
];
}
public function setLocale(RequestEvent $event): void
{
$request = $event->getRequest();
if ($locale = $request->attributes->get('_locale')) {
$request->setLocale($locale);
}
}
}
七、路由性能优化 #
7.1 缓存路由 #
bash
# 生产环境预热缓存
php bin/console cache:warmup --env=prod
# 路由匹配使用缓存,无需额外配置
7.2 路由优化建议 #
text
路由优化建议:
├── 使用静态路由优先
├── 避免过多动态参数
├── 合理使用路由约束
├── 使用路由前缀分组
├── 避免复杂的条件表达式
└── 合理设置路由优先级
八、路由调试 #
8.1 调试命令 #
bash
# 查看所有路由
php bin/console debug:router
# 查看特定路由
php bin/console debug:router app_user_show
# 测试URL匹配
php bin/console router:match /user/123
# 查看路由缓存
php bin/console cache:pool:cache:clear cache.router
8.2 路由信息 #
bash
# 详细路由信息
php bin/console debug:router app_user_show --show-controllers
# 输出示例
+--------------+---------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------+
| Route Name | app_user_show |
| Path | /user/{id} |
| Path Regex | #^/user/(?P<id>\d+)$#sD |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | GET |
| Requirements | id: \d+ |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: App\Controller\UserController::show |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
+--------------+---------------------------------------------------------+
九、总结 #
本章学习了:
- URL生成方法
- 路由条件配置
- 路由重定向
- URL匹配
- 自定义路由加载器
- 路由事件监听
- 路由性能优化
- 路由调试命令
下一章将学习 控制器基础。
最后更新:2026-03-28