天天看點

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,如需轉載請自行聯系原作者