第一个应用 #
一、创建控制器 #
1.1 使用Maker Bundle #
bash
# 创建控制器
php bin/console make:controller HomeController
# 输出
created: src/Controller/HomeController.php
created: templates/home/index.html.twig
1.2 控制器代码 #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
#[Route('/home', name: 'app_home')]
public function index(): Response
{
return $this->render('home/index.html.twig', [
'controller_name' => 'HomeController',
]);
}
}
1.3 控制器解析 #
text
┌─────────────────────────────────────────────────────┐
│ 控制器结构解析 │
├─────────────────────────────────────────────────────┤
│ │
│ #[Route('/home', name: 'app_home')] │
│ │ │ │
│ │ └── 路由名称 │
│ └── URL路径 │
│ │
│ public function index(): Response │
│ │ │ │
│ │ └── 返回类型 │
│ └── 动作方法名 │
│ │
│ return $this->render(...) │
│ │ │ │
│ │ └── 模板变量 │
│ └── 渲染模板 │
│ │
└─────────────────────────────────────────────────────┘
二、路由配置 #
2.1 注解路由 #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController
{
#[Route('/', name: 'app_home')]
public function index(): Response
{
return $this->render('home/index.html.twig');
}
#[Route('/about', name: 'app_about')]
public function about(): Response
{
return new Response('About Page');
}
#[Route('/contact', name: 'app_contact', methods: ['GET', 'POST'])]
public function contact(): Response
{
return new Response('Contact Page');
}
}
2.2 动态路由参数 #
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class UserController extends AbstractController
{
#[Route('/user/{id}', name: 'app_user_show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{
return new Response("User ID: $id");
}
#[Route('/blog/{slug}', name: 'app_blog_show')]
public function blogShow(string $slug): Response
{
return new Response("Blog Slug: $slug");
}
#[Route('/category/{category}/post/{post}', name: 'app_post_show')]
public function postShow(string $category, string $post): Response
{
return new Response("Category: $category, Post: $post");
}
}
2.3 路由默认值 #
php
<?php
#[Route('/page/{page}', name: 'app_page', defaults: ['page' => 1])]
public function page(int $page): Response
{
return new Response("Page: $page");
}
#[Route('/article/{id}/{slug}', name: 'app_article', defaults: ['slug' => null])]
public function article(int $id, ?string $slug): Response
{
return new Response("Article ID: $id, Slug: $slug");
}
2.4 路由条件 #
php
<?php
use Symfony\Component\ExpressionLanguage\Expression;
#[Route(
'/admin',
name: 'app_admin',
condition: "request.headers.get('X-Admin') === 'true'"
)]
public function admin(): Response
{
return new Response('Admin Page');
}
#[Route(
'/api/{version}',
name: 'app_api',
requirements: ['version' => 'v1|v2']
)]
public function api(string $version): Response
{
return new Response("API Version: $version");
}
三、创建模板 #
3.1 基础模板 #
twig
{# templates/base.html.twig #}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Symfony App{% endblock %}</title>
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
{% block stylesheets %}{% endblock %}
</head>
<body>
<nav class="navbar">
<a href="{{ path('app_home') }}">首页</a>
<a href="{{ path('app_about') }}">关于</a>
<a href="{{ path('app_contact') }}">联系</a>
</nav>
<main class="container">
{% block body %}{% endblock %}
</main>
<footer>
<p>© {{ "now"|date("Y") }} Symfony App</p>
</footer>
<script src="{{ asset('js/app.js') }}"></script>
{% block javascripts %}{% endblock %}
</body>
</html>
3.2 继承模板 #
twig
{# templates/home/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}首页 - {{ parent() }}{% endblock %}
{% block body %}
<div class="hero">
<h1>欢迎来到 Symfony</h1>
<p>这是一个强大的 PHP 企业级框架</p>
</div>
<div class="features">
<h2>核心特性</h2>
<ul>
<li>高性能</li>
<li>模块化</li>
<li>可扩展</li>
<li>企业级</li>
</ul>
</div>
{% endblock %}
3.3 模板变量 #
php
<?php
#[Route('/user/profile', name: 'app_user_profile')]
public function profile(): Response
{
$user = [
'name' => '张三',
'email' => 'zhangsan@example.com',
'age' => 25,
'skills' => ['PHP', 'Symfony', 'MySQL'],
'active' => true,
];
return $this->render('user/profile.html.twig', [
'user' => $user,
'title' => '用户资料',
]);
}
twig
{# templates/user/profile.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}{{ title }} - {{ parent() }}{% endblock %}
{% block body %}
<h1>{{ title }}</h1>
<div class="user-profile">
<p>姓名: {{ user.name }}</p>
<p>邮箱: {{ user.email }}</p>
<p>年龄: {{ user.age }}</p>
<h3>技能</h3>
<ul>
{% for skill in user.skills %}
<li>{{ skill }}</li>
{% endfor %}
</ul>
<p>状态: {{ user.active ? '活跃' : '禁用' }}</p>
</div>
{% endblock %}
四、请求与响应 #
4.1 获取请求参数 #
php
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
#[Route('/search', name: 'app_search')]
public function search(Request $request): Response
{
$keyword = $request->query->get('keyword', '');
$page = $request->query->getInt('page', 1);
return new Response("搜索: $keyword, 页码: $page");
}
#[Route('/user/create', name: 'app_user_create', methods: ['POST'])]
public function create(Request $request): Response
{
$name = $request->request->get('name');
$email = $request->request->get('email');
return new Response("创建用户: $name, $email");
}
4.2 获取路由参数 #
php
<?php
#[Route('/product/{id}/review/{reviewId}', name: 'app_product_review')]
public function review(int $id, int $reviewId): Response
{
return new Response("产品ID: $id, 评论ID: $reviewId");
}
#[Route('/article/{id}', name: 'app_article_show')]
public function articleShow(Request $request, int $id): Response
{
$routeName = $request->attributes->get('_route');
$routeParams = $request->attributes->get('_route_params');
return new Response("文章ID: $id, 路由: $routeName");
}
4.3 JSON响应 #
php
<?php
use Symfony\Component\HttpFoundation\JsonResponse;
#[Route('/api/users', name: 'api_users')]
public function users(): JsonResponse
{
$users = [
['id' => 1, 'name' => '张三'],
['id' => 2, 'name' => '李四'],
['id' => 3, 'name' => '王五'],
];
return $this->json($users);
}
#[Route('/api/user/{id}', name: 'api_user_show')]
public function userShow(int $id): JsonResponse
{
return $this->json([
'id' => $id,
'name' => '用户' . $id,
'status' => 'success',
], 200, ['X-Custom-Header' => 'value']);
}
4.4 重定向 #
php
<?php
#[Route('/redirect-home', name: 'app_redirect_home')]
public function redirectHome(): Response
{
return $this->redirectToRoute('app_home');
}
#[Route('/redirect-user/{id}', name: 'app_redirect_user')]
public function redirectUser(int $id): Response
{
return $this->redirectToRoute('app_user_show', ['id' => $id]);
}
#[Route('/redirect-external', name: 'app_redirect_external')]
public function redirectExternal(): Response
{
return $this->redirect('https://symfony.com');
}
五、调试工具 #
5.1 调试工具栏 #
Symfony提供了强大的调试工具栏:
text
┌─────────────────────────────────────────────────────┐
│ [Symfony] [200 OK] [Time: 45ms] [Memory: 12MB] │
│ [Request] [Security] [Forms] [Doctrine] [Twig] │
│ [Logs] [Events] [Router] [Cache] [Profiler] │
└─────────────────────────────────────────────────────┘
5.2 Dump调试 #
php
<?php
use Symfony\Component\VarDumper\VarDumper;
#[Route('/debug', name: 'app_debug')]
public function debug(): Response
{
$data = ['name' => '张三', 'age' => 25];
dump($data);
dd($data);
return new Response('Debug');
}
5.3 查看路由 #
bash
# 查看所有路由
php bin/console debug:router
# 查看特定路由
php bin/console debug:router app_home
# 输出示例
+--------------+-----------+------------+-----------------------------+
| Name | Method | Scheme | Path |
+--------------+-----------+------------+-----------------------------+
| app_home | ANY | ANY | / |
| app_about | ANY | ANY | /about |
| app_user_show| ANY | ANY | /user/{id} |
+--------------+-----------+------------+-----------------------------+
5.4 查看服务 #
bash
# 查看所有服务
php bin/console debug:container
# 查看特定服务
php bin/console debug:container twig
# 查看自动装配
php bin/console debug:autowiring
六、完整示例 #
6.1 创建博客列表页面 #
控制器:
php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class BlogController extends AbstractController
{
private array $posts = [
1 => ['id' => 1, 'title' => 'Symfony入门', 'content' => '学习Symfony基础'],
2 => ['id' => 2, 'title' => 'Doctrine ORM', 'content' => '数据库操作'],
3 => ['id' => 3, 'title' => 'Twig模板', 'content' => '模板引擎使用'],
];
#[Route('/blog', name: 'app_blog_index')]
public function index(): Response
{
return $this->render('blog/index.html.twig', [
'posts' => $this->posts,
]);
}
#[Route('/blog/{id}', name: 'app_blog_show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{
if (!isset($this->posts[$id])) {
throw $this->createNotFoundException('文章不存在');
}
return $this->render('blog/show.html.twig', [
'post' => $this->posts[$id],
]);
}
}
列表模板:
twig
{# templates/blog/index.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}博客列表{% endblock %}
{% block body %}
<h1>博客文章</h1>
<div class="post-list">
{% for post in posts %}
<article class="post">
<h2>
<a href="{{ path('app_blog_show', {id: post.id}) }}">
{{ post.title }}
</a>
</h2>
<p>{{ post.content }}</p>
</article>
{% else %}
<p>暂无文章</p>
{% endfor %}
</div>
{% endblock %}
详情模板:
twig
{# templates/blog/show.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}{{ post.title }}{% endblock %}
{% block body %}
<article class="post-detail">
<h1>{{ post.title }}</h1>
<div class="content">
{{ post.content }}
</div>
<a href="{{ path('app_blog_index') }}">返回列表</a>
</article>
{% endblock %}
七、运行测试 #
7.1 创建测试 #
php
<?php
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class BlogControllerTest extends WebTestCase
{
public function testIndex(): void
{
$client = static::createClient();
$crawler = $client->request('GET', '/blog');
$this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('h1', '博客文章');
}
public function testShow(): void
{
$client = static::createClient();
$crawler = $client->request('GET', '/blog/1');
$this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('h1', 'Symfony入门');
}
}
7.2 运行测试 #
bash
# 运行所有测试
php bin/phpunit
# 运行特定测试文件
php bin/phpunit tests/Controller/BlogControllerTest.php
# 运行特定测试方法
php bin/phpunit --filter testIndex
八、总结 #
本章学习了:
- 创建控制器
- 配置路由
- 创建Twig模板
- 请求参数获取
- 响应类型
- 重定向操作
- 调试工具使用
- 完整博客示例
下一章将学习 路由基础。
最后更新:2026-03-28