一个控制器本质上就是一个PHP方法:从 Request 对象中读取信息,创建并返回一个 Response 对象。响应可以是一个 HTML 页面,JSON,XML,一个文件下载,一个重定向,一个404错误或者其它的东西。控制器用来实现你的应用所需要渲染页面内容的任何逻辑。
如果你还没有创建你的第一个工作页面,可以先看一下我之前写的 Symfony 5 试用,然后再回来继续!
一个简单的控制器
虽然一个控制器可以是任意可以调用的东西(函数,一个对象的方法,或者一个 Closure),一个控制器通常会是存在于一个控制器类中的方法:
1 | // src/Controller/LuckyController.php |
这个控制器就是 number() 方法,存在于控制器类 LuckyController 中。
这个控制器非常简单:
- 第2行:Symfony 利用了PHP的命名空间功能,为整个控制器类命名空间。
- 第4行:Symfony 再次利用PHP的命名空间功能:使用
use关键字引入Response类,这个类是控制器返回数据必须用到的。 - 第7行:这个类在技术上可以命名为任何样式,但是它的后缀依照惯例必须是以
Controller结尾。 - 第12行:动作方法允许有一个
$max参数要幸亏max路由通配符。 - 第16行:控制器创建并返回了一个
Response对象。
将URL映射到控制器
为了 查看 这个控制器的结果,你需要通过路由将URL映射到该控制器上。上面是通过 @Route("/lucky/number/{max}") 路由注释完成的。
要查看你的页面,请在浏览器中转到以下URL:http://localhost:8000/lucky/number/100
有关路由的更多信息,请参见上一篇文章:Symfony 5 基础之路由。
基本控制器类和服务
为了帮助开发,Symfony附带了一个可选的基本控制器类,称为 Symfony\Bundle\FrameworkBundle\Controller\AbstractController。它可以被扩展以访问辅助方法。
将 use 语句添加到你的控制器类的顶部,然后修改 LuckyController 来扩展它:
1 | // src/Controller/LuckyController.php |
仅此而已!现在,你可以访问 $this->render() 之类的方法,以及接下来将要学习的许多其他方法。
生成URL
这个generateUrl() 方法只是一个辅助方法,它为给定的路由生成URL:
1 | $url = $this->generateUrl('app-lucky_number', ['max' => 10]); |
重定向
如果你想把用户重定向到另一个页面,请使用 redirectToRoute() 和 redirect() 方法:
1 | use Symfony\Component\HttpFoundation\RedirectResponse; |
redirect()方法不会以任何方式检查其目的地。如果你重定向到一个终端用户提供的URL,那你的应用程序可能会打开未验证的重定向安全漏洞。
渲染模板
如果要提供HTML服务,你就需要渲染一个模板。这个 render() 方法渲染一个模板,并且把内容放入一个 Response 对象中:
1 | // 渲染 templates/lucky/number.html.twig |
在 创建和使用模板 一文中详细说明了模板和Twig 。
获取服务
Symfony 已经打包了许多有用的类和功能,叫做服务。这些用于渲染模板,发送电子邮件,查询数据库以及你可以想到的任何其他“工作”。
如果你需要使用一个控制器中的服务,请键入带有其类(或接口)名称的参数。Symfony 将自动为你提供所需的服务:
1 | use Psr\Log\LoggerInterface; |
太棒了!
你还可以键入其他哪些服务?要查看它们,使用 debug:autowiringconsole 命令:
1 | > php bin/console debug:autowiring |
如果你需要控制参数的确切值,则可以按名称 绑定 参数:
1 | # config/services.yaml |
1 | <!-- config/services.xml --> |
1 | // config/services.php |
像所有的服务一样,你也可以在控制器中使用常规 构造函数 注入。
有关服务的更多信息,请参见 服务容器 文章。
生成控制器
为了节省时间,你可以安装 Symfony Maker 并告诉 Symfony 生成新的控制器类:
1 | > php bin/console make:controller BrandNewController |
如果你要从Doctrine 实体生成整个CRUD ,请使用:
1 | > php bin/console make:crud Product |
1.2版的新功能:
make:crud命令在MakerBundle 1.2中引入。
管理错误和404页面
如果找不到任何内容,则应返回404响应。为此,需要抛出一种特殊类型的异常:
1 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
createNotFoundException() 方法只是创建特殊Symfony\Component\HttpKernel\Exception\NotFoundHttpException 对象的快捷方式 ,该对象最终会在Symfony中触发404 HTTP响应。
如果你抛出的异常继承自或就是一个 Symfony\Component\HttpKernel\Exception\HttpException 对象,那么Symfony将使用适当的HTTP状态代码。否则,响应将带有500 HTTP状态代码:
1 | // 这个异常最终会生成一个 500 状态错误 |
在每种情况下,都会向最终用户显示一个错误页面,并向开发人员显示一个完整的调试错误页面(即,当你处于“调试”模式时-请参阅 配置环境)。
要自定义显示给用户的错误页面,请参阅 如何自定义错误页面 文章。
请求对象作为控制器参数
如果你需要读取查询参数,获取请求头或访问上传的文件该怎么办?这些信息存储在 Symfony 的 Request 对象中。要想在你控制器中访问它,请将其添加为参数并使用Request类作为它的类型提示:
1 | use Symfony\Component\HttpFoundation\Request; |
继续阅读 有关使用Request对象的更多信息。
管理会话
Symfony 提供了一个会话服务,你可以用它在两次请求之间存储有关用户的信息。会话默认情况下处于启用状态,但只有在你对其进行读写时才会启动。
会话存储和其他配置可以在 config/packages/framework.yaml 文件中 framework.session 配置 下面。
要获取会话,请添加一个参数,并使用 Symfony\Component\HttpFoundation\Session\SessionInterface 作为类型提示:
1 | use Symfony\Component\HttpFoundation\Session\SessionInterface; |
在该用户会话的其余时间内,存储的属性将保留在会话中。
想要获取更多信息,请参见 会话。
Flash消息
你还可以在用户的会话中存储特殊消息,称为“闪烁”消息。按照设计,即时消息应仅使用一次:一旦你检索它们,它们就会自动从会话中消失。此功能使“闪烁”消息特别适合存储用户通知。
例如,假设你正在处理 表单 提交:
1 | use Symfony\Component\HttpFoundation\Request; |
处理完请求后,控制器在会话中设置一条Flash消息,然后进行重定向。消息的键(notice 在此示例中)可以是任何东西:你将使用这个键来检索消息。
在下一页的模板中(甚至更好的是,在你的基本布局模板中),使用 Twig全局应用程序变量 提供的 flashes() 从会话中读取所有Flash消息:
1 | {# templates/base.html.twig #} |
通常使用 notice,warning 和 error 作为不同类型的flash信息的键,但你可以使用符合你的需求的任意键。
你可以使用
peek()方法来检索消息,同时将其保存在包中。
Request和Response对象
如 前面 所述,Symfony将把Request对象传递给任何带有Request类类型提示的控制器参数::
1 | use Symfony\Component\HttpFoundation\Request; |
Request 类具有几个公共属性和方法,这些属性和方法返回有关该请求所需的任何信息。
像 Request 一样,Response 对象有一个公共头属性。该对象属于 Symfony\Component\HttpFoundation\ResponseHeaderBag 类,并提供用于获取和设置响应头的方法。头名称已标准化。作为一个结果,该名称 Content-Type 等同于名称 content-type 或 content_type。
在Symfony中,需要一个控制器来返回一个 Response 对象:
1 | use Symfony\Component\HttpFoundation\Response; |
为方便起见,包含了不同的响应对象以解决不同的响应类型。其中一些会在下面提到。要了解更多有关 Request 和 Response(以及不同的Response类)的信息 ,请参见 HttpFoundation组件文档。
访问配置值
要从控制器获取任何 配置参数 的值,请使用 getParameter() 辅助方法:
1 | // ... |
返回JSON响应
要从控制器返回 JSON 数据,请使用 json() 辅助方法。这将返回一个 JsonResponse 对象,该对象会自动对数据进行编码:
1 | // ... |
如果在你的应用程序中启用了 序列化程序服务,它将用于将数据序列化为JSON。否则,将使用 json_encode 实现该功能。
流文件响应
你可以使用 file() 辅助方法从控制器内部提供一个文件:
1 | public function download() |
file() 辅助方法提供了一些参数来配置它的行为:
1 | use Symfony\Component\HttpFoundation\File\File; |
最后的思考
在Symfony中,控制器通常是一个类方法,用于接受请求并返回Response对象。当使用URL映射时,一个控制器将变得可访问并且可以查看其响应。
为了促进控制器的开发,Symfony提供了一个 AbstractController。它可用于扩展控制器类,从而允许访问一些常用的实用程序,例如 render() 和 redirectToRoute()。AbstractController 还提供了 createNotFoundException() 用于返回未找到响应的网页工具。
在其他文章中,你将学习如何在控制器内部使用特定的服务,这些服务将帮助你持久化数据库中的对象并从中获取对象,处理表单提交,处理缓存等等。
继续!
接下来,了解有关 使用Twig渲染模板 的所有信息。