原文出处:2-the-view-layer.md
原文作者:FriendsOfSymfony
授权许可:创作共用协议
翻译人员:FireHare
校对人员:
适用版本:FOSRestBundle 0.12.0
文章状态:草译阶段
Introduction(介绍)
The view layer makes it possible to write format
(html, json, xml, etc) agnostic controllers, by placing a layer between the Controller and the generation of the final output via the templating or a serializer.
通过在控制器和最终输出(由模板和序列化器生成)之间放置视图层,可以使编写格式(如html、json或xml等)与控制器无关。
The Bundle works with both the Symfony2 core serializer:http://symfony.com/doc/2.0/components/serializer.html
本功能包可以基于Symfony2核心序列化器:http://symfony.com/doc/2.0/components/serializer.html上工作。
But also with the more sophisticated serializer by Johannes Schmitt:https://github.com/schmittjoh/serializerhttps://github.com/schmittjoh/JMSSerializerBundle
但也可以基于Johannes Schmitt所编写的更复杂的序列化器:https://github.com/schmittjoh/serializerhttps://github.com/schmittjoh/JMSSerializerBundle上工作。
In your controller action you will then need to create a View
instance that is then passed to the fos_rest.view_handler
service for processing. The View
is somewhat modeled after the Response
class, but as just stated it simply works as a container for all the data/configuration for the ViewHandler
class for this particular action. So the View
instance must always be processed by a ViewHandler
(see the below section on the"view response listener" for how to get this processing applied automatically)
在您控制器的Action中,您需要创建一个发送给“fos_rest.view_handler”服务处理的View实例。这个View有点仿照Response类,但正如刚才所提,对于这个特定Action的ViewHandler类的所有的数据/配置来言,它仅是一个容器。因此View实例始终需要ViewHandler来处理。(参见下章节中的“视图响应监听器”,以了解如何自动进行上述处理。)
FOSRestBundle ships with a controller extending the default Symfony controller,which adds several convenience methods:
FOSRestBundle相对缺省的Symfony控制器而言,只是扩展了一些便捷方式的控制器:
<?php use FOS\RestBundle\Controller\FOSRestController; class UsersController extends FOSRestController { public function getUsersAction() { $data = // get data, in this case list of users. $view = $this->view($data, 200) ->setTemplate("MyBundle:Users:getUsers.html.twig") ->setTemplateVar('users') ; return $this->handleView($view); } public function redirectAction() { $view = $this->redirectView($this->generateUrl('some_route'), 301); // or $view = $this->routeRedirectView('some_route', array(), 301); return $this->handleView($view); } }
To simplify this even more: If you rely on the ViewResponseListener
in combination withSensioFrameworkExtraBundle you can even omit the calls to $this->handleView($view)
and directly return the view objects. See chapter 3 on listeners for more detailson the View Response Listener.
为了更简化:如果您依赖ViewResponseListener
并结合SensioFrameworkExtraBundle功能包,您甚至可以忽略$this->handleView($view)
的调用,而直接返回视图对象。更多细节请参见第3章节关于视图响应监听器的部分。
As the purpose is to create a format-agnostic controller, data assigned to the View
instance should ideally be an object graph, though any data type is acceptable. Note that when rendering templating formats, the ViewHandler
will wrap data types other than associative arrays in an associative array witha single key (default 'data'
), which will become the variable name of the object in the respective template. You can change this variable by callingthe setTemplateVar()
method on the view object.
因为目标是创建与格式无关的控制器,所以指定给View实例的数据最好是一个对象图,虽然任何数据类型都可以被接受。注意,当渲染模板格式时,ViewHandler将数据类型以外的关联数组都包装在单个键(缺省是‘data’)的关联数组中,它将成为各自模板中的对象名。您可以通过调用view对象的setTemplateVar()方法来改变这个变量。
There are also two specialized View
classes for handling redirects, one for redirecting to an URL called RedirectView
and one to redirect to a route called RouteRedirectView
. Note that whether these classes actually cause a redirector not is determined by the force_redirects
configuration option,which is only enabled for html
by default (see below).
这里也有两个指定的View类来处理重定向,一个是通过调用 RedirectView 来重定向到 URL,另一个是调用 RouteReirectView 来重定向到路由。注意这些类是否引发重定向是由配置选项force_redirects来决定的,该选项在缺省状态下仅对html生效。
There are several more methods on the View
class, here is a list of all the important ones for configuring the view:
View类还有其它一些方法,在这里列出所有对配置View比较重要的方法:
setData($data)
- Set the object graph or list of objects to serialize.setData($data)
- 设置要序列化的对象图或对象列表setHeader($name, $value)
- Set a header to put on the HTTP response.setHeader($name, $value)
- 设置HTTP响应头setHeaders(array $headers)
- Set multiple headers to put on the HTTP response.setHeaders(array $headers)
- 设置多个HTTP响应头
setSerializationContext($context)
- 设置序列化上下文以便使用setTemplate($name)
- Name of the template to use in case of HTML rendering.setTemplate($name)
- 在HTML渲染时使用的模板名
setTemplateVar($name)
- Name of the variable the data is in, when passed to HTML template. Defaults to'data'
.setTemplateVar($name)
- 设置发送给HTML模板的数据变量名,缺省是'data'
。setEngine($name)
- Name of the engine to render HTML template. Can be autodetected.setEngine($name)
- 渲染HTML模板引擎名,可自动匹配setFormat($format)
- The format the response is supposed to be rendered in. Can be autodetected using HTTP semantics.setFormat($format)
- 渲染响应时的格式,可以通过HTML语义自动匹配setLocation($location)
- The location to redirect to with a response.setLocation($location)
- 响应中重定向的位置setRoute($route)
- The route to redirect to with a response.setRoute($route)
- 响应中重定向的路由setResponse(Response $response)
- The response instance that is populated by theViewHandler
.setResponse(Response $response)
- 由ViewHandler填充的响应实例。
See the following example code for more details:https://github.com/liip/LiipHelloBundle/blob/master/Controller/HelloController.php
更多细节详见下列示例:https://github.com/liip/LiipHelloBundle/blob/master/Controller/HelloController.php
Forms and Views(表单和视图)
Symfony Forms have special handling inside the view layer. Whenever you
Symfony 表单在视图层内部有一些特定的处理,当您:
return a Form from the controller
从控制器返回一个Form
Set the form as only data of the view
只为视图数据设置表单
return an array with a 'form' key, containing a form
返回的数组有'form'键,并包含一个表单
Then:
那么:
If the form is bound and no status code is set explicitly, an invalid form leads to a "validation failed" response.
如果表单被绑定并且没有显式设置状态码,那么一个无效表单将导致“验证失败”响应
In a rendered template, the form is passed as 'form' and
createView()
is called automatically.在被渲染的模板中,表单将作为'form‘发送并自动调用createView()
$form->getData()
is passed into the view as template as'data'
if the form is the only view data.如果表单只是视图数据的话,那么$form->getData()将作为模板,作为 'data'发送到视图。
Configuration(配置)
The formats
and templating_formats
settings determine which formats are respectively supported by the serializer and by the template layer. In otherwords any format listed in templating_formats
will require a template for rendering using the templating
service, while any format listed in formats
will use the serializer for rendering. For both settings avalue of false
means that the given format is disabled.
formats和templating_formats设置项确定了哪些格式分别被序列器和模板层支持。也就是说一些列在templating_formats中的格式将要求正在使用模板服务渲染的模板,而列在formats中的格式将使用序列器来渲染。上述两个设置值为false,则意味着禁用格式。
When using RouteRedirectView::create()
the default behavior of forcing a redirect to the route for html is enabled,but needs to be enabled for other formats if needed.
当使用RouteRedirectView::create()
时,对于html格式而言,将缺省启用强行重定向到路由的功能,但如果需要,其它格式缺省也将启用该功能。
Finally the HTTP response status code for failed validation defaults to 400
. Note when changing the default you can use name constants of FOS\Rest\Util\Codes
class or an integer status code.
最终对应验证失败的缺省HTTP响应状态码为400.注意:当改变缺省值时您可以使用FOS\Rest\Util\Codes类中命名的常量,也可以使用整数状态码。
You can also set the default templating engine to something different than the default of twig
:
您也可以设置与缺省的twig模板引擎不同的缺省模板引擎:
# app/config/config.yml fos_rest: view: formats: rss: true xml: false templating_formats: html: true force_redirects: html: true failed_validation: HTTP_BAD_REQUEST default_engine: twig
See the following example configuration for more details:https://github.com/liip-forks/symfony-standard/blob/techtalk/app/config/config.yml
更多细节请参见下列配置示例:https://github.com/liip-forks/symfony-standard/blob/techtalk/app/config/config.yml
Custom handler(自定义处理器)
While many things should be possible via the serializer in some cases it might not be enough. For example you might need some custom logic to be executed in the ViewHandler
. For these cases one might want to register a custom handler for a specific format. The custom handler can either be registered by defining a custom service, via a compiler pass or it can even be registered from inside the controller action.
虽然许多事情应该可以通过序列化来解决,但在某些情况下它可能是不够的。举个例子,您可能需要在ViewHandler中执行一些自定义的逻辑。在这种情况下,您可能想要注册一个自定义处理器以处理一个特定的格式。自定义处理器可以通过自定义一个服务来注册,通过编译器发送。甚至还可以从控制器中的Action内部注册。
The callable will receive 3 parameters:
调用将接受3个参数:
the instance of the
ViewHandler
ViewHandler实例
the instance of the
View
View实例
the instance of the
Request
Request实例
Note there are several public methods on the ViewHandler
which can be helpful:
注意在ViewHandler中有几个公共方法是有帮助的:
isFormatTemplating()
createResponse()
createRedirectResponse()
renderTemplate()
There is an example inside LiipHelloBundle to show how to register a custom handler:https://github.com/liip/LiipHelloBundle/blob/master/View/RSSViewHandler.php
https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml
这是在LiipHelloBundle功能包内部的示例,用于展示如何注册自定义处理器:https://github.com/liip/LiipHelloBundle/blob/master/View/RSSViewHandler.php
https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml
There is another example in Resources\doc\examples
:https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/examples/RssHandler.php
这是在Resources\doc\examples
目录中的另一个示例:https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/examples/RssHandler.php
Here is an example using a closure registered inside a Controller action:
下面的示例是在控制器Action中的注册:
<?php use Symfony\Bundle\FrameworkBundle\Controller\Controller; use FOS\RestBundle\View\View; class UsersController extends Controller { public function getUsersAction() { $view = View::create(); ... $handler = $this->get('fos_rest.view_handler'); if (!$handler->isFormatTemplating($view->getFormat())) { $templatingHandler = function($handler, $view, $request) { // if a template is set, render it using the 'params' and place the content into the data if ($view->getTemplate()) { $data = $view->getData(); if (empty($data['params'])) { $params = array(); } else { $params = $data['params']; unset($data['params']); } $view->setData($params); $data['html'] = $handler->renderTemplate($view, 'html'); $view->setData($data); } return $handler->createResponse($view, $request, $format); }; $handler->registerHandler($view->getFormat(), $templatingHandler); } return $handler->handle($view); } }
That was it!
Return to the index or continue reading about Listener support.