<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Symfony中文教程 &#187; 控制器</title>
	<atom:link href="http://www.newlifeclan.com/symfony/archives/category/cookbook/cookbook-2-6/controller/feed" rel="self" type="application/rss+xml" />
	<link>http://www.newlifeclan.com/symfony</link>
	<description>站在巨人肩膀上的phpweb框架</description>
	<lastBuildDate>Fri, 12 Dec 2025 00:58:27 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.0.38</generator>
	<item>
		<title>(控制器)如何自定义错误页面</title>
		<link>http://www.newlifeclan.com/symfony/archives/87</link>
		<comments>http://www.newlifeclan.com/symfony/archives/87#comments</comments>
		<pubDate>Sat, 11 Oct 2014 06:15:06 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[Cook 2.6]]></category>
		<category><![CDATA[Cookbook]]></category>
		<category><![CDATA[控制器]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=87</guid>
		<description><![CDATA[<p>当symfony出现异常时，都会被Kernel类所捕获并最终转发到一个特殊的控制器TwigBundle:Exc [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/87">(控制器)如何自定义错误页面</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>当symfony出现异常时，都会被Kernel类所捕获并最终转发到一个特殊的控制器TwigBundle:Exception:show来处理。这个控制器在核心的TwigBundle里，他来确定显示哪些错误模板，并且给相关异常设定状态码。<br />
<span id="more-87"></span><br />
错误页面可以定义为两种不同的形式，这取决与你要更改的灵活度：<br />
1.自定义不同错误页面的模板<br />
2.替换默认的异常控制器 twig.controller.exception:showAction</p>
<h2>默认ExceptionController</h2>
<p>默认ExceptionController是否显示一个异常或错误页面，取决于是否这是kernel.debug。虽然异常页面会给我们排查问题提供很多有用信息，但是最终给用户显示的应该是错误页面，而不是异常页面。</p>
<blockquote><p>在开发过程中测试错误页面<br />
在开发过程中你要看到你的错误页面，你就不能设置kernel.debug为false。这是因为它会阻止symfony重新编译twig模板等，看不到异常页面。<br />
这个第三方WebfactoryExceptionsBundle提供了一个特殊的测试控制器，它能够在kernel.debug设置为true的情况下，允许你显示任意的http状态的自定义错误页面。</p></blockquote>
<h2>重写错误模板</h2>
<p>所有的错误模板都写在TwigBundle下。去重写这个模板，只需要遵守这个bundle的基本方法就可以了。更多方法请看 <span style="color: #ff0000"><a style="color: #ff0000" href="http://symfony.com/doc/current/book/templating.html#overriding-bundle-templates">重写bundle模板</a></span>。<br />
举例,我们现在就去重写一个默认的错误模板，那么需要在此路径下新建一个模板<br />
app/Resources/TwigBundle/views/Exception/error.html.twig</p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
    &lt;title&gt;An Error Occurred: {{ status_text }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Oops! An Error Occurred&lt;/h1&gt;
    &lt;h2&gt;The server returned a "{{ status_code }} {{ status_text }}".&lt;/h2&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p></p>
<blockquote><p>你一定不能在你的错误页面使用is_granted（或者layout使用你的错误页面），因为路由运行在防火墙之前。如果路由器抛出异常（例如，当路由不匹配时）你使用is_granted将引发有一个异常。或者你能够通过这种方式{% if app.user and is_granted(&#8216;&#8230;&#8217;) %}来使用is_granted。</p></blockquote>
<blockquote><p>如果你不熟悉Twig，不用担心。Twig是symfony中非常简单，强大和可选择的模板引擎。更多信息请查看  book文档（<a href="http://symfony.com/doc/current/book/templating.html" target="_blank">创建和使用模板</a>）。</p></blockquote>
<p>除了标准的html页面，symfony还提供很多其他格式的错误页面，例如JSON（error.json.twig）,XML（error.xml.twig）甚至还有JavaScript(error.js.twig)。只需要在这个app/Resources/TwigBundle/views/Exception目录下创建同名文件就可以重写这些模板了。上面是用标准的方法重写这些在bundle里的模板。</p>
<p>&nbsp;</p>
<h2>自定义404页面和其他错误页面</h2>
<p>你可以根据http的状态定制特定的模板。例如创建一个app/Resources/TwigBundle/views/Exception/error404.html.twig模板去显示一个不存在的404错误页。</p>
<p>symfony使用下面的算法去决定使用哪个模板：</p>
<ul>
<li>首次，判断给定的格式和状态码，并寻找一个模板（像：error404.json.twig）;</li>
<li>如果error404.json.twig不存在，他会去寻找给定的格式模板（例如：error.json.twig）</li>
<li>如果error.json.twig也不存在，他会返回html模板（例如：error.html.twig）</li>
</ul>
<blockquote><p>要是去看所有的额默认错误模板，在TwigBundle的Resources/views/Exception目录下。在symfony标准版里就可以找到TwigBundle在vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle。有一个简单的方法，我们可以从TwigBundle里拷贝页面到app/Resources/TwigBundle/views/Exception目录下并修改它，让他成为一个自定义的错误页。</p></blockquote>
<blockquote><p>同样开发人员可以自定义这些友好的异常页面，例如可以创建模板exception.html.twig是为了标准的HTML页面异常显示和exception.json.twig是JOSN异常页面显示。</p></blockquote>
<p>&nbsp;</p>
<h2>替换默认的异常控制器</h2>
<p>如果你需要更多的灵活性，那只修改模板文件是不够的（例如你可能需要传入一些自己的变量到你的模板），那么你可以重写你的控制器去渲染自己的模板。</p>
<p>默认的异常控制器是注册为一个服务的</p>
<p>—— 实际的类是Symfony\Bundle\TwigBundle\Controller\ExceptionController</p>
<p>为此，创建一个新的控制器并且让他继承默认的symfony类</p>
<p>Symfony\Bundle\TwigBundle\Controller\ExceptionController</p>
<p>你可以有几种方法，把自定义的不同部分在错误页面里呈现，例如你可以覆盖整个showAction或者只是findTemplate方法让自己的模板渲染。</p>
<p>为了让symfony能够使用自己的异常控制器而不是默认的，设置app/config/config.yml的twig.exception_controller选项。</p>
<blockquote><p>自定义的异常处理实际上比上面写的更强大。一个内部事件Kernel.exception是能够完全控制所有抛出的异常。详细内容可查看，<span style="color: #ff0000"><a style="color: #ff0000" title=" kernel.exception Event" href="http://symfony.com/doc/current/book/internals.html#kernel-kernel-exception" target="_blank">kernel.exception Event</a></span></p></blockquote>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/87">(控制器)如何自定义错误页面</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/87/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>(控制器)怎样去定义一个控制器为服务</title>
		<link>http://www.newlifeclan.com/symfony/archives/66</link>
		<comments>http://www.newlifeclan.com/symfony/archives/66#comments</comments>
		<pubDate>Thu, 09 Oct 2014 07:47:35 +0000</pubDate>
		<dc:creator><![CDATA[napoleon]]></dc:creator>
				<category><![CDATA[Cook 2.6]]></category>
		<category><![CDATA[Cookbook]]></category>
		<category><![CDATA[控制器]]></category>

		<guid isPermaLink="false">http://www.newlifeclan.com/symfony/?p=66</guid>
		<description><![CDATA[<p>在book文档里，你已经学习了如何让你的一个Controller去继承基类Controller。这个工作方式很 [&#8230;]</p>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/66">(控制器)怎样去定义一个控制器为服务</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>在book文档里，你已经学习了如何让你的一个Controller去继承基类Controller。这个工作方式很好，但是还有别的方式例如把Controller指定为一个服务。<br />
<span id="more-66"></span></p>
<blockquote><p>指定一个控制器作为服务需要做一点工作。这样做的主要优势是全部的Controller和任何服务都能通过Controller使用，只需要修改服务容器配置。开发一个开源的软件包或给不同的项目使用时，他非常方便。<br />
第二个优势，通过观察构造函数参数,很容易看出他使用什么类型的东西，也知道这个控制器能做或不能做的事情。而且很明显（也就是说，如果你有很多的构造参数时）由于每个依赖都需要手动注入，控制器已经变得过于庞大，你就可以分割成多个控制器。<br />
所以，即使你没有指定控制器为一个服务，你也会从一些开源的symfony的程序中看到。很重要的是你要了解这两种方式的优劣性。</p></blockquote>
<h2>定义这个控制器为一个服务</h2>
<p>一个控制器可以和其他类一样被定义成一个服务。例如，你有以下简单的控制器：</p><pre class="crayon-plain-tag">// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class HelloController
{
    public function indexAction($name)
    {
        return new Response('&lt;html&gt;&lt;body&gt;Hello '.$name.'!&lt;/body&gt;&lt;/html&gt;');
    }
}</pre><p>然后你可以定义它为如下服务：</p><pre class="crayon-plain-tag"># src/Acme/HelloBundle/Resources/config/services.yml
parameters:
    # ...
    acme.controller.hello.class: Acme\HelloBundle\Controller\HelloController

services:
    acme.hello.controller:
        class: "%acme.controller.hello.class%"</pre><p>&nbsp;</p>
<h2>涉及到该服务</h2>
<p>去使用一个定义为服务的控制器时，要采用冒号（:）。例如，如何转发到上面定义的 acme.hello.controller的indexAction()方法:</p><pre class="crayon-plain-tag">$this-&gt;forward('acme.hello.controller:indexAction', array('name' =&gt; $name));</pre><p></p>
<blockquote><p>注：当你使用这个语法时，不能够舍弃indexAction方法名的Action部分。</p></blockquote>
<p>当定义路由_controller的值时，你可以用路由指定服务同样也使用冒号（:）等相同符号：</p><pre class="crayon-plain-tag"># app/config/routing.yml
hello:
    path:     /hello
    defaults: { _controller: acme.hello.controller:indexAction }</pre><p></p>
<blockquote><p>你还可以采用注释的方式配置路由，来使用一个定义为服务的控制器。请查看<a href="http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html" target="_blank"> FrameworkExtraBundle documentation</a>。</p></blockquote>
<p>&nbsp;</p>
<h2>替代继承的基础Controller方法</h2>
<p>当使用的控制器作为服务时，他可能不会用Controller类。也不依赖于它的快捷方式方法，你会直接与你所需要的服务进行交互。幸运的是，通常我们会很容易的和基础的Controller（一个伟大的代码）来执行许多常见任务。<br />
举个例子，如果你想呈现一个模板，而不是直接创建Response对象，如果你继承了基础的Controller，那么你原来的代码应该这样写：</p><pre class="crayon-plain-tag">// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class HelloController extends Controller
{
    public function indexAction($name)
    {
        return $this-&gt;render(
            'AcmeHelloBundle:Hello:index.html.twig',
            array('name' =&gt; $name)
        );
    }
}</pre><p>如果你看一下基础Controller在symfony中render函数的源代码，你会发现这个方法实际使用的是templating服务。</p><pre class="crayon-plain-tag">public function render($view, array $parameters = array(), Response $response = null)
{
    return $this-&gt;container-&gt;get('templating')-&gt;renderResponse($view, $parameters, $response);
}</pre><p>在一个作为服务的控制器中，您可以直接注入模板服务并使用它：</p><pre class="crayon-plain-tag">// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;

class HelloController
{
    private $templating;

    public function __construct(EngineInterface $templating)
    {
        $this-&gt;templating = $templating;
    }

    public function indexAction($name)
    {
        return $this-&gt;templating-&gt;renderResponse(
            'AcmeHelloBundle:Hello:index.html.twig',
            array('name' =&gt; $name)
        );
    }
}</pre><p>服务定义也需要修改指定构造函数参数：</p><pre class="crayon-plain-tag"># src/Acme/HelloBundle/Resources/config/services.yml
parameters:
    # ...
    acme.controller.hello.class: Acme\HelloBundle\Controller\HelloController

services:
    acme.hello.controller:
        class:     "%acme.controller.hello.class%"
        arguments: ["@templating"]</pre><p>不是从容器获取<tt class="docutils literal"><code>templating服务，而是你能够精确的注入需要的服务到你的Controller里。</code></tt></p>
<p>&nbsp;</p>
<blockquote><p>这并不意味着你不能从自己的基础控制器扩展这些控制器。之所以从标准的基本控制器中剥离，是因为控制器的一些方法，使用前提是“有控制器可以使用”但如果控制器“被定义成服务”，此时控制器就不可用。把它从基本的控制器中剥离可能是一个好主意，提取通用的代码到一个服务里,代码再注入到一个基本控制器扩展。这两种方法都是有效的,主要看你想要如何整理你的可重用代码。</p></blockquote>
<p><a rel="nofollow" href="http://www.newlifeclan.com/symfony/archives/66">(控制器)怎样去定义一个控制器为服务</a>，首发于<a rel="nofollow" href="http://www.newlifeclan.com/symfony">Symfony中文教程</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.newlifeclan.com/symfony/archives/66/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
