天天看点

FOSRestBundle功能包:视图层Step 2: The view layer

The view layer makes it possible to write <code>format</code> (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等)与控制器无关。

In your controller action you will then need to create a <code>View</code> instance that is then passed to the <code>fos_rest.view_handler</code>service for processing. The  <code>View</code> is somewhat modeled after the <code>Response</code> class, but as just stated  it simply works as a container for all the data/configuration for the<code> ViewHandler</code> class for this particular action.  So the <code>View</code> instance must always be processed by a <code>ViewHandler</code> (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控制器而言,只是扩展了一些便捷方式的控制器:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<code>&lt;?php</code>

<code>use</code> <code>FOS\RestBundle\Controller\FOSRestController;</code>

<code>class</code> <code>UsersController </code><code>extends</code> <code>FOSRestController</code>

<code>{</code>

<code>    </code><code>public</code> <code>function</code> <code>getUsersAction()</code>

<code>    </code><code>{</code>

<code>        </code><code>$data</code> <code>= </code><code>// get data, in this case list of users.</code>

<code>        </code><code>$view</code> <code>= </code><code>$this</code><code>-&gt;view(</code><code>$data</code><code>, 200)</code>

<code>            </code><code>-&gt;setTemplate(</code><code>"MyBundle:Users:getUsers.html.twig"</code><code>)</code>

<code>            </code><code>-&gt;setTemplateVar(</code><code>'users'</code><code>)</code>

<code>        </code><code>;</code>

<code>        </code><code>return</code> <code>$this</code><code>-&gt;handleView(</code><code>$view</code><code>);</code>

<code>    </code><code>}</code>

<code>    </code><code>public</code> <code>function</code> <code>redirectAction()</code>

<code>        </code><code>$view</code> <code>= </code><code>$this</code><code>-&gt;redirectView(</code><code>$this</code><code>-&gt;generateUrl(</code><code>'some_route'</code><code>), 301);</code>

<code>        </code><code>// or</code>

<code>        </code><code>$view</code> <code>= </code><code>$this</code><code>-&gt;routeRedirectView(</code><code>'some_route'</code><code>, </code><code>array</code><code>(), 301);</code>

<code>}</code>

To simplify this even more: If you rely on the <code>ViewResponseListener</code> in combination withSensioFrameworkExtraBundle you can even omit the calls to <code>$this-&gt;handleView($view)</code>and directly return the view objects. See chapter 3 on listeners for more detailson the View Response Listener.

为了更简化:如果您依赖<code>ViewResponseListener</code>并结合SensioFrameworkExtraBundle功能包,您甚至可以忽略<code>$this-&gt;handleView($view)</code>的调用,而直接返回视图对象。更多细节请参见第3章节关于视图响应监听器的部分。

As the purpose is to create a format-agnostic controller, data assigned to the<code> View</code> instance should ideally be an object graph, though any data type is acceptable. Note that when rendering templating formats, the <code>ViewHandler</code> will wrap data types other than associative arrays in an associative array witha single key (default  <code>'data'</code>), which will become the variable name of the object in the respective template. You can change this variable by callingthe <code>setTemplateVar()</code>method on the view object.

因为目标是创建与格式无关的控制器,所以指定给View实例的数据最好是一个对象图,虽然任何数据类型都可以被接受。注意,当渲染模板格式时,ViewHandler将数据类型以外的关联数组都包装在单个键(缺省是‘data’)的关联数组中,它将成为各自模板中的对象名。您可以通过调用view对象的setTemplateVar()方法来改变这个变量。

There are also two specialized <code>View</code> classes for handling redirects, one for redirecting to an URL called <code>RedirectView</code>and one to redirect to a route called <code>RouteRedirectView</code>.  Note that whether these classes actually cause a redirector not is determined by the <code>force_redirects</code> configuration option,which is only enabled for <code>html</code> by default (see below).

这里也有两个指定的View类来处理重定向,一个是通过调用 RedirectView 来重定向到 URL,另一个是调用 RouteReirectView 来重定向到路由。注意这些类是否引发重定向是由配置选项force_redirects来决定的,该选项在缺省状态下仅对html生效。

There are several more methods on the <code>View</code> class, here is a list of all the important ones for configuring the view:

View类还有其它一些方法,在这里列出所有对配置View比较重要的方法:

<code>setData($data)</code> - Set the object graph or list of objects to serialize.

<code>setData($data)</code> - 设置要序列化的对象图或对象列表

<code>setHeader($name, $value)</code> - Set a header to put on the HTTP response.

<code>setHeader($name, $value)</code> - 设置HTTP响应头

<code>setHeaders(array $headers)</code> - Set multiple headers to put on the HTTP response.

<code>setHeaders(array $headers)</code> - 设置多个HTTP响应头

<code>setSerializationContext($context)</code> - 设置序列化上下文以便使用

<code>setTemplate($name)</code> - Name of the template to use in case of HTML rendering.

<code>setTemplate($name)</code> - 在HTML渲染时使用的模板名

<code>setTemplateVar($name)</code> - Name of the variable the data is in, when passed to HTML template. Defaults to <code>'data'</code>.

<code>setTemplateVar($name)</code> - 设置发送给HTML模板的数据变量名,缺省是<code>'data'</code>。

<code>setEngine($name)</code> - Name of the engine to render HTML template. Can be autodetected.

<code>setEngine($name)</code> - 渲染HTML模板引擎名,可自动匹配

<code>setFormat($format)</code> - The format the response is supposed to be rendered in. Can be autodetected using HTTP semantics.

<code>setFormat($format)</code> - 渲染响应时的格式,可以通过HTML语义自动匹配

<code>setLocation($location)</code> - The location to redirect to with a response.

<code>setLocation($location)</code> - 响应中重定向的位置

<code>setRoute($route)</code> - The route to redirect to with a response.

<code>setRoute($route)</code> - 响应中重定向的路由

<code>setResponse(Response $response)</code> - The response instance that is populated by the <code>ViewHandler</code>.

<code>setResponse(Response $response)</code> - 由ViewHandler填充的响应实例。

<a href="https://github.com/liip/LiipHelloBundle/blob/master/Controller/HelloController.php"></a>

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 <code>createView()</code> is called automatically.

在被渲染的模板中,表单将作为'form‘发送并自动调用createView()

<code>$form-&gt;getData()</code> is passed into the view as template as <code>'data'</code> if the form is the only view data.

如果表单只是视图数据的话,那么$form-&gt;getData()将作为模板,作为 'data'发送到视图。

The <code>formats</code> and <code>templating_formats</code> settings determine which formats are respectively supported by the serializer and by the template layer. In otherwords any format listed in <code>templating_formats</code> will require a template for rendering using the <code>templating</code> service, while any format listed in<code> formats</code> will use the serializer for rendering.  For both settings avalue of <code>false</code> means that the given format is disabled.

formats和templating_formats设置项确定了哪些格式分别被序列器和模板层支持。也就是说一些列在templating_formats中的格式将要求正在使用模板服务渲染的模板,而列在formats中的格式将使用序列器来渲染。上述两个设置值为false,则意味着禁用格式。

When using <code>RouteRedirectView::create()</code> the default behavior of forcing a redirect to the route for html is enabled,but needs to be enabled for other formats if needed.

当使用<code>RouteRedirectView::create()</code>时,对于html格式而言,将缺省启用强行重定向到路由的功能,但如果需要,其它格式缺省也将启用该功能。

Finally the HTTP response status code for failed validation defaults to <code>400</code>. Note when changing the default you can use name constants of<code> FOS\Rest\Util\Codes</code> class or an integer status code.

最终对应验证失败的缺省HTTP响应状态码为400.注意:当改变缺省值时您可以使用<code>FOS\Rest\Util\Codes类中命名的常量,也可以使用整数状态码。</code>

You can also set the default templating engine to something different than the default of <code>twig</code>:

您也可以设置与缺省的twig模板引擎不同的缺省模板引擎:

<code># app/config/config.yml</code>

<code>fos_rest:</code>

<code>    </code><code>view:</code>

<code>        </code><code>formats:</code>

<code>            </code><code>rss: </code><code>true</code>

<code>            </code><code>xml: </code><code>false</code>

<code>        </code><code>templating_formats:</code>

<code>            </code><code>html: </code><code>true</code>

<code>        </code><code>force_redirects:</code>

<code>        </code><code>failed_validation: HTTP_BAD_REQUEST</code>

<code>        </code><code>default_engine: twig</code>

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 <code>ViewHandler</code>. 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 <code>ViewHandler</code>

<code>ViewHandler实例</code>

the instance of the <code>View</code>

<code>View实例</code>

the instance of the <code>Request</code>

<code>Request实例</code>

Note there are several public methods on the <code>ViewHandler</code> which can be helpful:

注意在ViewHandler中有几个公共方法是有帮助的:

<code>isFormatTemplating()</code>

<code>createResponse()</code>

<code>createRedirectResponse()</code>

<code>renderTemplate()</code>

<a href="https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml">https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml</a>

Here is an example using a closure registered inside a Controller action:

下面的示例是在控制器Action中的注册:

22

23

24

25

26

27

28

29

30

31

32

<code>use</code> <code>Symfony\Bundle\FrameworkBundle\Controller\Controller;</code>

<code>use</code> <code>FOS\RestBundle\View\View;</code>

<code>class</code> <code>UsersController </code><code>extends</code> <code>Controller</code>

<code>        </code><code>$view</code> <code>= View::create();</code>

<code>        </code><code>...</code>

<code>        </code><code>$handler</code> <code>= </code><code>$this</code><code>-&gt;get(</code><code>'fos_rest.view_handler'</code><code>);</code>

<code>        </code><code>if</code> <code>(!</code><code>$handler</code><code>-&gt;isFormatTemplating(</code><code>$view</code><code>-&gt;getFormat())) {</code>

<code>            </code><code>$templatingHandler</code> <code>= </code><code>function</code><code>(</code><code>$handler</code><code>, </code><code>$view</code><code>, </code><code>$request</code><code>) {</code>

<code>                </code><code>// if a template is set, render it using the 'params' and place the content into the data</code>

<code>                </code><code>if</code> <code>(</code><code>$view</code><code>-&gt;getTemplate()) {</code>

<code>                    </code><code>$data</code> <code>= </code><code>$view</code><code>-&gt;getData();</code>

<code>                    </code><code>if</code> <code>(</code><code>empty</code><code>(</code><code>$data</code><code>[</code><code>'params'</code><code>])) {</code>

<code>                        </code><code>$params</code> <code>= </code><code>array</code><code>();</code>

<code>                    </code><code>} </code><code>else</code> <code>{</code>

<code>                        </code><code>$params</code> <code>= </code><code>$data</code><code>[</code><code>'params'</code><code>];</code>

<code>                        </code><code>unset(</code><code>$data</code><code>[</code><code>'params'</code><code>]);</code>

<code>                    </code><code>}</code>

<code>                    </code><code>$view</code><code>-&gt;setData(</code><code>$params</code><code>);</code>

<code>                    </code><code>$data</code><code>[</code><code>'html'</code><code>] = </code><code>$handler</code><code>-&gt;renderTemplate(</code><code>$view</code><code>, </code><code>'html'</code><code>);</code>

<code>                    </code><code>$view</code><code>-&gt;setData(</code><code>$data</code><code>);</code>

<code>                </code><code>}</code>

<code>                </code><code>return</code> <code>$handler</code><code>-&gt;createResponse(</code><code>$view</code><code>, </code><code>$request</code><code>, </code><code>$format</code><code>);</code>

<code>            </code><code>};</code>

<code>            </code><code>$handler</code><code>-&gt;registerHandler(</code><code>$view</code><code>-&gt;getFormat(), </code><code>$templatingHandler</code><code>);</code>

<code>        </code><code>}</code>

<code>        </code><code>return</code> <code>$handler</code><code>-&gt;handle(</code><code>$view</code><code>);</code>

本文转自 firehare 51CTO博客,原文链接:http://blog.51cto.com/firehare/1250006,如需转载请自行联系原作者