控制器
控制器是一个你创建的php函数,它能够获取http请求信息并构建和返回一个http响应(作为Symfony的Response对象),Response可能是一个html页面、xml文档、一个序列化的json数组、图像、重定向、404错误或者一些其他你能够想像的。控制器包含了你应用程序需要渲染页面的任何逻辑。
看一下symfony简单的控制器。下面控制器将输出 hello word
:hello word
:
use Symfony\Component\HttpFoundation\Response; public function helloAction(){ return new Response('Hello world!');}
控制器的目标都是相同的:创建并返回一个Response
对象。在这个过程中,它可能会从请求中读取信息,加载数据库资源,发送邮件,在用户session中设置信息。但是所有情况下,控制器将最终返回 Response
对象给客户端。
没有什么神奇的不用担心还有别的要求!下面是一些常见的例子:
控制器A准备了一个首页上的
Response
对象。-控制器B从请求中读取
{slug}
参数,从数据库中载入一条博文,并创建一个显示该博文的Response
对象。如果{slug}
不能被数据库中检索到,那么控制器将创建并返回一个带404状态码的Response
对象。控制器C处理关于联系人的表单提交。它从请求中读取表单信息,将联系人信息存入数据库并发送包含联系人信息的电子邮件给网站管理员。最后,它创建一个
Response
对象将用户的浏览器重定向到联系人表单的“感谢”页面。
请求、控制器、响应的生命周期 ¶
symfony处理的每一个请求都会有相同的生命周期。框架会负责把很多重复的任务用一个控制器最终执行,控制器执行你自定义的应用代码:
每个请求都被单个前端控制器(如
app.php
生产环境 或app_dev.php
开发环境)文件处理,前端控制器负责引导框架;前端控制器的唯一工作是去初始化Symfony引擎(调用
Kernel
)并传入一个Request
// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController{ public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); }}
控制器的目标都是相同的:创建并返回一个Response
对象。在这个过程中,它可能会从请求中读取信息,加载数据库资源,发送邮件,在用户session中设置信息。但是所有情况下,控制器将最终返回Response
对象给客户端。- 没有什么神奇的不用担心还有别的要求!下面是一些常见的例子:
- 控制器B从请求中读取
- 控制器C处理关于联系人的表单提交。它从请求中读取表单信息,将联系人信息存入数据库并发送包含联系人信息的电子邮件给网站管理员。最后,它创建一个
请求、控制器、响应的生命周期 ¶
symfony处理的每一个请求都会有相同的生命周期。框架会负责把很多重复的任务用一个控制器最终执行,控制器执行你自定义的应用代码:第2行:Symfony利用php命名空间函数去命名整个控制器类
第4行:Symfony充分利用了PHP5.3的名称空间的功能:
use
关键字导入Response
类,是我们控制器必须返回的;第6行:类名是一个串联的控制器类名称(例如
hello
)加上Controller
关键字。这是一个约定,为控制器提供一致性,并允许它们引用控制器名称(例如hello
)作为路由配置。第8行:在控制器类中的每个action都有着后缀
Action
,并且这个action名(index
)被引用到路由配置文件中。在下一节中,我们将使用路由映射一个URI到该action,并展示如何将路由占位符({name}
)变成action的参数($name
);第10行:控制器创建并返回一个
Response
- 🎜第2行:Symfony利用php命名空间函数去命名整个控制器类🎜🎜
- 🎜第4行:Symfony充分利用了PHP5.3的名称空间的功能:
use
关键字导入Response
类,是我们控制器必须返回的;🎜🎜 - 🎜第6行:类名是一个串联的控制器类名称(例如
hello
)加上Controller
关键字。这是一个约定,为控制器提供一致性,并允许它们引用控制器名称(例如hello
)作为路由配置。🎜🎜 - 🎜第8行:在控制器类中的每个action都有着后缀
Action
,并且这个action名(index
)被引用到路由配置文件中。在下一节中,我们将使用路由映射一个URI到该action,并展示如何将路由占位符({name}
)变成action的参数($name
);🎜🎜 - 🎜第10行:控制器创建并返回一个
Response
对象。🎜🎜🎜🎜将URI映射到控制器 🎜¶🎜🎜🎜我们的新控制器返回一个简单的HTML页。为了能够在指定的URI中渲染该控制器,我们需要为它创建一个路由。 我们将在路由章节中讨论路由组件的细节,但现在我们为我们的控制器创建一个简单路由:🎜🎜XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <route id="hello" path="/hello/{name}"> <!-- uses a special syntax to point to the controller - see note below --> <default key="_controller">AppBundle:Hello:index</default> </route></routes>
🎜PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{name}', array( // uses a special syntax to point to the controller - see note below '_controller' => 'AppBundle:Hello:index',))); return $collection;
// src/AppBundle/Controller/HelloController.php// ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; /** * @Route("/hello/{name}", name="hello") */public function indexAction($name){ // ...}
Annotations:// src/AppBundle/Controller/HelloController.php// ... use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{ /** * @Route("/hello/{firstName}/{lastName}", name="hello") */ public function indexAction($firstName, $lastName) { // ... }}
现在,你来到
/hello/ryan
(例如,如果你使用内置的web服务http://localhost:8000/hello/ryan
),那么它就会执行HelloController::indexAction()
控制器,并且将ryan
赋给$name
变量。创建这样一个页面就能够让路由跟控制器做简单的关联。/hello/ryan
(例如,如果你使用内置的web服务http://localhost:8000/hello/ryan
),那么它就会执行HelloController::indexAction()
控制器,并且将ryan
赋给$name
变量。创建这样一个页面就能够让路由跟控制器做简单的关联。简单吧?
把路由参数传入控制器 ¶
我们现在已经知道路由指向AppBundle中的
HelloController::indexAction()
方法。还有更有趣的就是控制器方法的参数传递:YAML:# app/config/routing.ymlhello: path: /hello/{firstName}/{lastName} defaults: { _controller: AppBundle:Hello:index }
控制器有个参数
$name
,对应所匹配路由的{name}
参数(如果你访问/hello/ryan
, 在本例中是ryan
)。实际上当执行你的控制器时,Symfony在所匹配路由中匹配带参数控制器中的每个参数。所以这个{name}
值被传入到$name
。只需要确保占位符的名称和参数名称一样就行。以下是更有趣的例子,这里的控制器有两个参数:
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> <route id="hello" path="/hello/{firstName}/{lastName}"> <default key="_controller">AppBundle:Hello:index</default> </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{firstName}/{lastName}', array( '_controller' => 'AppBundle:Hello:index',))); return $collection;
public function indexAction($lastName, $firstName){ // ...}
public function indexAction($firstName, $lastName, $foo){ // ...}
将路由参数映射到控制器参数是十分容易和灵活的。在你开发时请遵循以下思路:
1. 控制器参数的顺序无关紧要Symfony可以根据路由参数名匹配控制器方法参数。换句话说,它可以实现
last_name
参数与$last_name
参数的匹配。控制器可以在随意排列参数的情况下正常工作。public function indexAction($firstName, $lastName, $foo = 'bar'){ // ...}
2.控制器所需参数必须匹配路由参数
下面会抛出一个运行时异常(
RuntimeException
),因为在路由定义中没有foo
参数:public function indexAction($firstName){ // ...}
如果参数是可选的,那该多好。下面的例子不会抛出异常:
// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller{ // ...}
3.不是所有的路由参数都需要在控制器上有响应参数的
如果,举个例子,
简单吧?last_name
Response
对象。-{slug}
参数,从数据库中载入一条博文,并创建一个显示该博文的Response
对象。如果{slug}
不能被数据库中检索到,那么控制器将创建并返回一个带404状态码的Response
对象。Response
对象将用户的浏览器重定向到联系人表单的“感谢”页面。每个请求都被单个前端控制器(如app.php
生产环境 或app_dev.php
开发环境)文件处理,前端控制器负责引导框架;
Kernel
)并传入一个Request
对象来让它处理。🎜🎜🎜🎜Symfony核心要求路由器去检查这个请求;🎜🎜🎜🎜路由查看并匹配请求信息,并将其指向一个特定的路由,该路由决定调用哪个控制器;🎜🎜🎜🎜执行控制器,控制器中的代码将创建并返回一个Response对象;🎜🎜🎜🎜HTTP头和Response对象的内容将发回客户端。🎜🎜🎜🎜创建控制器与创建页面一样方便,同时映射一个URI到该控制器。🎜🎜🎜🎜虽然名称相似,但前端控制器与我们在本章节所说的控制器是不同的,前端控制器是你web/
目录中的一个PHP小文件,所有的请求都直接经过它。一个典型的应用程序将有一个用于生产的前端控制器(如app.php
)和一个用于开发的前端控制器(如app_dev.php
)。你可以永远不需要去对前端控制器编辑、查看或者有所担心。本章的“控制器类”用一种方便的方法组织各自的“controllers”,也被称为actions,它们都在一个类里(如,updateAction()
, deleteAction()
, 等)。所以,在控制器类里一个控制器就是一个方法。它们会持有你创建的代码,并返回Response
响应对象。web/
目录中的一个PHP小文件,所有的请求都直接经过它。一个典型的应用程序将有一个用于生产的前端控制器(如app.php
)和一个用于开发的前端控制器(如app_dev.php
)。你可以永远不需要去对前端控制器编辑、查看或者有所担心。本章的“控制器类”用一种方便的方法组织各自的“controllers”,也被称为actions,它们都在一个类里(如,updateAction()
, deleteAction()
, 等)。所以,在控制器类里一个控制器就是一个方法。它们会持有你创建的代码,并返回Response
响应对象。
一个简单的控制器 ¶
虽然一个控制器可以是任何的可被调用的PHP(函数、对象的方法或Closure
),在Symfony,控制器通常是在控制器类中的一个方法,控制器也常被称为action:
Annotations:// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{ /** * @Route("/hello/{name}", name="hello") */ public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); }}
这里面的控制器是indexAction
方法,它隶属于一个控制器类HelloController
。
这个控制器非常的简单:
虽然一个控制器可以是任何的可被调用的PHP(函数、对象的方法或Closure
),在Symfony,控制器通常是在控制器类中的一个方法,控制器也常被称为action:
YAML:# app/config/routing.ymlhello: path: /hello/{name} # uses a special syntax to point to the controller - see note below defaults: { _controller: AppBundle:Hello:index }.
这里面的控制器是indexAction
方法,它隶属于一个控制器类HelloController
。