Symfony2 学习笔记之模板使用

Symfony2 -- Bundle创建与使用 Bundle相当于其他软件里的插件。关键的区别就是在Symfony里所有的东西都是bundle,包括核心框架的功能和你应用程序编写的代码。这让您灵活地使用预构建的功能打包在第三方包或分发自己的包。选择哪些特性使它容易在应用程序中启用,你所希望的方式来优化。 在如何了解如何创建Bundle之前先来看看Bundle的目录结构是怎样的。   Bundle目录结构(Bundle Di 阅读详情
我们知道,controller负责处理每一个进入Symfony2应用程序的请求。实际上,controller把大部分的繁重工作都委托给了其它地方,以使代码能够被测试和重用。当一个controller需要生成HTML,CSS或者其他内容时,它把这些工作给了一个模板化引擎。

模板:
  一个模板仅仅是一个文本文件,它能生成任意的文本格式(HTML,XML,CSV,LaTex...)。最著名的模板类型就是PHP模板了,可以被PHP解析的文本文件,它混合了文本和PHP代码。

复制代码
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1><?php echo $page_title ?></h1>

        <ul id="navigation">
            <?php foreach ($navigation as $item): ?>
                <li>
                    <a href="<?php echo $item->getHref() ?>">
                        <?php echo $item->getCaption() ?>
                    </a>
                </li>
            <?php endforeach; ?>
        </ul>
    </body>
</html>
复制代码

  但是Symfony2包中拥有一种更加强大的模板化语言叫Twig。 它允许你写简洁,可读法模板语言。对页面设计师更友好,在许多方面比PHP模板更加强大。

复制代码
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1>{{ page_title }}</h1>

        <ul id="navigation">
            {% for item in navigation %}
                <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
            {% endfor %}
        </ul>
    </body>
</html>
复制代码

在这个Twig文件中,定义了三个类型的特别语法

{{...}} : "说某些事“, 打印一个变量或者一个表达式的值到模板。
{%...%} : "做某些事”,控制模板逻辑的标签,它用于执行比如for循环语句等。
{# 这是一个注释 #}, "注释“。

Twig也包含filters,在渲染之前修改内容。下面的语句显示把title变量全部渲染为大型。

{{ title|upper }}

Twig默认情况下有一大群的标签(tags)和过滤器(filters)可以使用。当然你也可以根据需要添加扩展。注册一个Twig扩展非常容易,创建一个新服务并把它标记为Twig.extension 标签。就跟你看到的一样,Twig也支持功能和新功能的添加。比如,下面使用一个标准的for标签和cycle功能函数来打印10个div 标签,用odd,even 类代替。

{% for i in 0..10 %}
<div alss="{{ cycle(['odd','even'],i) }}">
<!--一些其它HTML -->
</div>
{% emdfor %}

 

Twig模板缓存
  Twig很快。 每个Twig模板被编译到原生的PHP类,它将在运行时被渲染。编译过的类被保存在app/cache/{environment}/twig 目录下并在某些情况下,对整个调试非常有用。当debug模式可用时,一个twig模板如果发生改变将会被自动重新编译。这就意味着你可以在开发过程中随意的修改模板,而不必担心需要去清除内存了。当debug模式被关闭时,你必须手动的清除Twig缓存目录,以便能够重新生成Twig模板。

 

模板继承和布局
  大多数的时候,模板在项目中用来共享通用的元素,比如header,footer,sidebar等等。在Symfony2中,我们将采用不同的思考角度来对待这个问题。一个模板可以被另外的模板装饰。这个的工作原理跟PHP类非常像,模板继承让你可以创建一个基础”layout"模板,它包含你的站点的所有通用元素并被定义成blocks。这里的block可以类比为PHP基类的方法。 一个字模板可以继承基础layout模板并重写它任何一个block。

现在首先创建一个base layout文件:
Twig:

复制代码
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>{% block title %}Test Application{% endblock %}</title>
    </head>
    <body>
        <div id="sidebar">
            {% block sidebar %}
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog">Blog</a></li>
            </ul>
            {% endblock %}
        </div>

        <div id="content">
            {% block body %}{% endblock %}
        </div>
    </body>
</html>
复制代码

PHP代码格式:

复制代码
<!-- app/Resources/views/base.html.php -->
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title><?php $view['slots']->output('title', 'Test Application') ?></title>
    </head>
    <body>
        <div id="sidebar">
            <?php if ($view['slots']->has('sidebar')): ?>
                <?php $view['slots']->output('sidebar') ?>
            <?php else: ?>
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/blog">Blog</a></li>
                </ul>
            <?php endif; ?>
        </div>

        <div id="content">
            <?php $view['slots']->output('body') ?>
        </div>
    </body>
</html>
复制代码

这个模板定义了基本的HTML初始文档是一个简单的两列式页面。在这个页面中有三处{% block %}定义,分别定义了title,sidebar和body。每个block都可以被继承它的子模板重写或者保留它现在的默认实现。该模板也能被直接渲染,只不过只是显示基础模板的定义内容。

下面定义一个子模板:
Twig格式:

复制代码
{# src/Acme/BlogBundle/Resources/views/Blog/index.html.twig #}
{% extends '::base.html.twig' %}

{% block title %}My cool blog posts{% endblock %}

{% block body %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
{% endblock %}
复制代码

PHP代码格式:

复制代码
<!-- src/Acme/BlogBundle/Resources/views/Blog/index.html.php -->
<?php $view->extend('::base.html.php') ?>

<?php $view['slots']->set('title', 'My cool blog posts') ?>

<?php $view['slots']->start('body') ?>
    <?php foreach ($blog_entries as $entry): ?>
        <h2><?php echo $entry->getTitle() ?></h2>
        <p><?php echo $entry->getBody() ?></p>
    <?php endforeach; ?>
<?php $view['slots']->stop() ?>
复制代码

父模板被一个特殊的字符串语法表示 ::base.html.twig ,它表示该模板在项目的 app/Resources/views 目录下。

  模板继承的关键字 {% extends %}标签。 该标签告诉模板化引擎首先评估父模板,它会设置布局和定义多个blocks。然后是子模板,上例中父模板中定义的title和body 两个blocks将会被子模板中的定义所取代。依靠blog_entries的值,输出的内容如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>My cool blog posts</title>
    </head>
    <body>
        <div id="sidebar">
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog">Blog</a></li>
            </ul>
        </div>

        <div id="content">
            <h2>My first post</h2>
            <p>The body of the first post.</p>

            <h2>Another post</h2>
            <p>The body of the second post.</p>
        </div>
    </body>
</html>
复制代码

  在此我们注意到,因为子模板中没有定义sidebar这个block,所以来自父模板的内容被显示出来,而没有被子模板替代。位于父模板中的{% block %}标签是默认值,如果没有被子模板重写覆盖,它将作为默认值使用。

  你可以根据你的需要进行多层继承。 Symfony2项目中一般使用一种三层继承模式来组织模板和页面。当我们使用模板继承时,需要注意:

  如果在模板中使用{% extends %},那么它必须是模板的第一个标签。
  你基础模板中{% block %}越多越好,记住,子模板不必等一父模板中所有的block。你父模板中block定义的越多,你的布局就越灵活。
  如果你发现在多个模板中有重复的内容,这可能就意味着你需要为该内容在父模板中定义一个{% block %}。有些时候更好的解决方案可能是把这些内容放到一个新模板中,然后在该模板中include它。

  如果你需要从父模板中获取一个block的内容,你可以使用{{ parent() }}函数。

{% block sidebar %}
    <h3>Table of Contents</h3>
    ...
    {{ parent() }}
{% endblock %}

 

模板的命名和存储位置
  默认情况下,模板可以被保存到两个位置:
    app/Resources/views 目录下,可以存放整个应用程序级的基础模板以及那些重写bundle模板的模板。
    path/to/bundle/Resources/views 目录下,每个bundle自己的模板。

  Symfony2使用bundle:controller:template 字符串语法表示模板。这可以表示许多不同类型的模板,每种都存放在特定的路径下:
    AcmeBlogBundle:Blog:index.html.twig 用于指定一个特定页面的模板。
    AcmeBlogBundle 表示bundle,说明模板位于AcmeBlogBundle,比如src/Acme/BlogBundle。
  Blog 表示BlogController,指定模板位于Resourcs/views的Blog子目录中,index.html.twig为模板名字。

  假设AcmeBlogBundle位于src/Acme/BlogBundle, 最终的路径将是:src/Acme/BlogBundle/Resources/views/Blog/index.html.twig

  AcmeBlogBundle::layout.html.twig 该表示法指向AcmeBlogBundle的基模板。没有controller部分,所以模板应该位于AcmeBlogBundle的Resources/views/layout.html.twig

  ::base.html.twig 表示一个应用程序级的基模板或者布局文件。注意,该语句两个冒号开头,意味着没有bundle和controller部分,这说明该文件不在某个bundle中,而是位于根目录下 app/Resources/views


  在重写Bundle模板一节,你将发现位于AcmeBlogBundle的模板是如何被位于app/Resources/AcmeBlogBundle/views/目录下的所有模板同名重写的,
这种方式给了我们一个有力的途径来重写供应商提供的bundle的模板。


模板后缀(suffix)
  bundle:controller:template 句法说明了每个模板文件的存放位置。每个模板名字也有两个扩展名来指定格式和模板引擎。
    AcmeBlogBundle:Blog:index.html.twig HTML格式,Twig引擎
    AcmeBlogBundle:Blog:index.html.php HTML格式,PHP引擎
    AcmeBlogBundle:Blog:index.css.twig CSS格式,Twig引擎
  默认情况下,Symfony2的任何模板都可以被写成Twig或者PHP引擎的,它由后缀决定。其中后缀的前一部分(.html,.css)表示最终生成的格式。


标签和助手类
  你已经基本了解了模板,它们如何命名如何使用模板继承等。最难理解的部分已经过去。接下来我们将了解大量的可用工具来帮助我们执行最通用的模板任务比如包含另外一个模板,链接一个页面或者包含一个图片等。

  Symfony2 中包含了血多序列化的Twig标签和功能函数来帮助设计者更容易的完成工作。在PHP中,模板系统提供了一个可扩展的helper系统,它可以在模板上下文中提供许多有用的内容。我们已经看过一些内建的Twig标签,比如{% block %}{% extends %}等,还有PHP 助手$view['slots']。

包含其它模板:
  你可能经常想在多个不同的页面中包含同一个模板或者代码片段。比如一个应用程序中有“新闻文章”,模板代码在显示一片文章时可能用到文章详细页面,一个现实最流行文章的页面,或者一个最新文章的列表页面等。

  当你需要重用一些PHP代码,你通常都是把这些代码放到一个PHP类或者函数中。同样在模板中你也可以这么做。通过把可重用的代码放到一个它自己的模板中,然后把这个模板包含到其他模板中。比如我们创建一个可重用模板如下:
Twig格式:

复制代码
{# src/Acme/ArticleBundle/Resources/views/Article/articleDetails.html.twig #}
<h2>{{ article.title }}</h2>
<h3 class="byline">by {{ article.authorName }}</h3>

<p>
    {{ article.body }}
</p>
复制代码

PHP代码格式:

复制代码
<!-- src/Acme/ArticleBundle/Resources/views/Article/articleDetails.html.php -->
<h2><?php echo $article->getTitle() ?></h2>
<h3 class="byline">by <?php echo $article->getAuthorName() ?></h3>

<p>
    <?php echo $article->getBody() ?>
</p>
复制代码

然后我们把它包含到其它模板定义中:

Twig格式:

复制代码
{# src/Acme/ArticleBundle/Resources/Article/list.html.twig #}
{% extends 'AcmeArticleBundle::layout.html.twig' %}

{% block body %}
    <h1>Recent Articles<h1>

    {% for article in articles %}
        {% include 'AcmeArticleBundle:Article:articleDetails.html.twig' with {'article': article} %}
    {% endfor %}
{% endblock %}
复制代码

PHP代码格式:

复制代码
<!-- src/Acme/ArticleBundle/Resources/Article/list.html.php -->
<?php $view->extend('AcmeArticleBundle::layout.html.php') ?>

<?php $view['slots']->start('body') ?>
    <h1>Recent Articles</h1>

    <?php foreach ($articles as $article): ?>
        <?php echo $view->render('AcmeArticleBundle:Article:articleDetails.html.php', array('article' => $article)) ?>
    <?php endforeach; ?>
<?php $view['slots']->stop() ?>
复制代码

模板的包含使用{% include %}标签。模板的名称要使用通用方式。在articleDetails.html.twig模板中使用article变量,这里通过在list.html.twig模板中使用with命令传入。{'article':article}语法是标准Twig哈希映射的写法。如果我们需要传递多个元素,可以写成{'foo': foo, 'bar': bar}。


嵌入Controllers
  有些情况下,你需要比包含简单模板做到更多。假设你有一个菜单栏sidebar在你的布局文件中来显示最新的文章。获取三篇最新文章可能需要查询数据库或者执行其它包含很多逻辑的操作,这样就不能在一个模板中进行了。这种情况的解决方案是简答键入一个完整的controller到你的模板。首先创建一个controller来渲染特定数量的最近文章:

复制代码
//src/Acme/ArticleBundle/Controller/ArticleController.php
class ArticleController extends Controller
{
      public function recentArticlesAction($max = 3)
      {
            //生成一个数据库调用或者其它逻辑来获取$max个最新文章的代码
           $articles = ...;
           return $this->render('AcmeArticleBundle:Article:recentList.html.twig',array('articles'=>articles));
      }
}
复制代码

而recentList模板则相当简单:

Twig格式:

{# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #}
{% for article in articles %}
      <a href="/article/{{ article.slug }}">
           {{ article.title }}
      </a>
{% endfor %}

PHP代码格式:

<!-- src/Acme/ArticleBundle/Resources/views/Article/recentList.html.php -->
<?php foreach ($articles as $article): ?>
    <a href="/article/<?php echo $article->getSlug() ?>">
        <?php echo $article->getTitle() ?>
    </a>
<?php endforeach; ?>

为了能包含controller,你需要使用一个标准的字符语法来表示controller,格式类似bundle:controller:action

Twig格式:

{# app/Resources/views/base.html.twig #}
...

<div id="sidebar">
    {% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>

PHP代码格式:

<!-- app/Resources/views/base.html.php -->
...

<div id="sidebar">
    <?php echo $view['actions']->render('AcmeArticleBundle:Article:recentArticles', array('max' => 3)) ?>
</div>

  无论什么时候,你需要一个变量或者一些列信息时,你不必在模板中访问,而是考虑渲染一个controller。因为Controller能够更快的执行并且很好的提高了代码的组织和重用。


链接到页面:
  在你的应用程序中创建一个链接到其它页面对于一个模板来说是再普通不过的事情了。我们采用path Twig函数基于路由配置来生成URL而非在模板中硬编码URL。以后如果你想修改一个特定页面的URL,你只需要改变路由配置即可,模板将自动生成新的URL。比如我们打算链接到"_welcome"页面,首先定义其路由配置:
YAML格式:

_welcome:
    pattern:  /
    defaults: { _controller: AcmeDemoBundle:Welcome:index }

XML格式:

<route id="_welcome" pattern="/">
    <default key="_controller">AcmeDemoBundle:Welcome:index</default>
</route>

PHP代码格式:

$collection = new RouteCollection();
$collection->add('_welcome', new Route('/', array(
    '_controller' => 'AcmeDemoBundle:Welcome:index',
)));

return $collection;

我们可以在模板中使用Twig函数 path来引用这个路由链接该页面。

Twig格式:

<a href="{{ path('_welcome') }}">Home</a>

PHP代码格式:

<a href="<?php echo $view['router']->generate('_welcome') ?>">Home</a>

上面的内容会生成一个URL /

  我们看另一个复杂一些的路由定义:
YAML格式:

article_show:
    pattern:  /article/{slug}
    defaults: { _controller: AcmeArticleBundle:Article:show }

XML格式:

<route id="article_show" pattern="/article/{slug}">
    <default key="_controller">AcmeArticleBundle:Article:show</default>
</route>

PHP代码格式:

$collection = new RouteCollection();
$collection->add('article_show', new Route('/article/{slug}', array(
    '_controller' => 'AcmeArticleBundle:Article:show',
)));

return $collection;

  这种情况下你需要指定路由名称(article_show)还要一个参数值{slug}。现在让我们再来看上面的recentList模板 ,我们修改以前的硬编码而使用path来链接正确的文章。

Twig格式:

{# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #}
{% for article in articles %}
    <a href="{{ path('article_show', { 'slug': article.slug }) }}">
        {{ article.title }}
    </a>
{% endfor %}

PHP代码格式:

<!-- src/Acme/ArticleBundle/Resources/views/Article/recentList.html.php -->
<?php foreach ($articles in $article): ?>
    <a href="<?php echo $view['router']->generate('article_show', array('slug' => $article->getSlug()) ?>">
        <?php echo $article->getTitle() ?>
    </a>
<?php endforeach; ?>

你也可以通过url Twig函数来生成一个绝对路径的URL:

<a href="{{ url('_welcome') }}">Home</a>

在PHP代码模板中,你需要给generate()方法传入第三个参数true 来实现生成绝对路径URL

<a href="<?php echo $view['router']->generate('_welcome', array(), true) ?>">Home</a>

 


链接到资源
  模板通常也需要一些图片,Javascript,样式文件和其它资产。当然你可以硬编码它们的路径。比如/images/logo.png。 但是Symfony2 提供了一个更加动态的Twig函数 asset()。
Twig格式:

<img src="{{ asset('images/logo.png') }}" alt="Symfony!" />
<link href="{{ asset('css/blog.css') }}" rel="stylesheet" type="text/css" />

PHP代码格式:

<img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" alt="Symfony!" />
<link href="<?php echo $view['assets']->getUrl('css/blog.css') ?>" rel="stylesheet" type="text/css" />

  asset函数的主要墨笔是让你的应用程序更加轻便。如果你的应用程序在你的主机根目录下(比如:http://example.com),那么它会渲染出的路径为 /images/logo.png 。但是如果你的应用程序位于一个子目录中(比如:http://example.com/my_app),这时它会为你渲染出的路径变为 /my_app/images/logo.png 。asset函数能够根据你的应用程序来生成正确的路径。

  另外,如果你使用asset函数,symfony可以自动追加一个查询字符串到你的资产,以保证被更新的静态资源不会在部署时被缓存。比如:/images/logo.png 可能看起来是 /images/logo.png?v2 。

 

包含样式表和Javascript文件到Twig模板:
  每个网站中都不可能缺少了样式表和javascript文件。在Symfony中,这些内容可以通过模板继承很好的进行包含处理。Symfony打包了另外一个类库叫做Assetic, 它允许你对这些资源做更多的有趣操作。首先在你的基模板中添加两个blocks来保存你的资源,一个叫stylesheets,放在head标签里,另一个叫javascript,放在body结束标签上面一行。这些blocks将包含你整个站点所需要的所有stylesheets和javascripts。

复制代码
{# 'app/Resources/views/base.html.twig' #}
<html>
    <head>
        {# ... #}

        {% block stylesheets %}
            <link href="{{ asset('/css/main.css') }}" type="text/css" rel="stylesheet" />
        {% endblock %}
    </head>
    <body>
        {# ... #}

        {% block javascripts %}
            <script src="{{ asset('/js/main.js') }}" type="text/javascript"></script>
        {% endblock %}
    </body>
</html>
复制代码

  这太简单了!但如果你想从子模板中包含一个额外的stylesheet或者javascript怎么办呢?比如假设你有一个联系页面需要包含一个contact.css样式表只用于该页面。在你的contact页面模板内部,你可以这样实现:

复制代码
{# src/Acme/DemoBundle/Resources/views/Contact/contact.html.twig #}
{% extends '::base.html.twig' %}

{% block stylesheets %}
    {{ parent() }}

    <link href="{{ asset('/css/contact.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}

{# ... #}
复制代码

  在子模板中你只需要重写stylesheets block并把你新的样式表标签放到该块里。当然因为你想添加到父模板该块内容中,而不是替代它们所以你需要在此之前

先使用parent()函数来获取父模板中的所有stylesheets。你也可以包含资源位置到你的bundle的Resources/public 文件夹。你需要执行如下命令行:

$php app/console assets:install target [--symlink]

它会把文件移动到正确的位置,默认情况下的目标位置是web文件夹。

<link href="{{ asset('bundles/acmedemo/css/contact.css') }}" type="text/css" rel="stylesheet" />

上面代码最终结果是页面会包含main.css和contact.css样式表。


全局模板变量
  在每个请求中,Symfony2 将会在Twig引擎和PHP引擎默认设置一个全局模板变量app。该app变量是一个GlobalVariables实例,它将让你自动访问到应用程序一些特定能够的变量。比如:
  app.security 安全上下文
  app.user 当前用户对象
  app.request 当前Request对象
  app.session Session对象
  app.environment 当前应用程序的环境(dev,prod等)
  app.debug 如果是true说明是调试模式,false则不是。
  当然,你也可以向其添加你自己的全局模板变量。其应用示例:

Twig格式:

<p>Username: {{ app.user.username }}</p>
{% if app.debug %}
    <p>Request method: {{ app.request.method }}</p>
    <p>Application Environment: {{ app.environment }}</p>
{% endif %}

PHP代码格式:

<p>Username: <?php echo $app->getUser()->getUsername() ?></p>
<?php if ($app->getDebug()): ?>
    <p>Request method: <?php echo $app->getRequest()->getMethod() ?></p>
    <p>Application Environment: <?php echo $app->getEnvironment() ?></p>
<?php endif; ?>

 

配置和使用templating 服务
Symfony2模板系统的核心是模板化引擎。这个特殊的对象负责渲染模板并返回他们正确的内容。当你在controller中渲染一个模板时,其实你是使用了模板化引擎服务,比如:

return $this->render('AcmeArticleBundle:Article:index.html.twig');

其实相当于:

$engine = $this->container->get('templating'); 
$content = $engine->render('AcmeArticleBundle:Article:index.html.twig');
return $response = new Response($content);

  该模板化引擎服务在Symfony2内部是预先配置好自动工作的。当然它也可以在应用程序的配置文件中进行配置。比如:

YAML格式:

# app/config/config.yml
framework:
    # ...
    templating: { engines: ['twig'] }

XML格式:

<!-- app/config/config.xml -->
<framework:templating>
    <framework:engine id="twig" />
</framework:templating>

PHP代码格式:

复制代码
// app/config/config.php
$container->loadFromExtension('framework', array(
    // ...
    'templating'      => array(
        'engines' => array('twig'),
    ),
));
复制代码

 


重写Bundle模板:
Symfony2社群现在正为他们创建和维护了很多不同内容的高质量的Bundle而感到骄傲,一旦你使用第三方的bundle你可能想重写或者个性化它们的一个或者多个模板。假设你已经包含了开源AcmeBlogBundle到你的项目中,比如目录是src/Acme/BlogBundle,你想重写blog列表(list)页面来按照你自己的应用程序风格个性化它。我们打开AcmeBlogBundle的Blog controller,可以发现如下内容:

public function indexAction()
{
    $blogs = // some logic to retrieve the blogs

    $this->render('AcmeBlogBundle:Blog:index.html.twig', array('blogs' => $blogs));
}

当AcmeBlogBundle:Blog:index.html.twig被渲染时,Symfony2 会查找两个位置来定位模板:

  1. app/Resources/AcmeBlogBundle/views/Blog/index.html.twig
  2. src/Acme/BlogBundle/Resources/views/Blog/index.html.twig

要重写该bundle的模板,仅仅从bundle中拷贝index.html.twig 模板到app/Resources/AcmeBlogBundle/views/Blog/index.html.twig。
注意,如果app/Resources/AcmeBlogBundle目录不存在,可以手工建立。之后你就可以随心所欲的个性化处理该模板了。

  该逻辑同样适用于基bundle模板,假设AcmeBlogBundle中每个模板都是继承于基模板AcmeBlogBundle::layout.html.twig。Symfony2 将从下面两个地方寻找模板:
  1.app/Resources/AcmeBlogBundle/vews/layout.html.twig
  2.src/Acme/BlogBundle/Resources/views/layout.html.twig
同样的,如果要重写该模板,你仅仅需要从bundle中拷贝到app/Resources/AcmeBlogBundle/views/layout.html.twig 就可以轻松个性化它了。你也可以通过bundle继承来从bundle内部重写模版。


重写核心模板:
  因为Symfony2 框架本身就是一个bundle,所以其核心模板也可以按照同样的方式进行重写。比如,核心模板TwigBundle包含很多不同”execption"和“error" 的模板,你可以通过从Resources/views/Exception 目录下每一项到app/Resources/TwigBundle/Views/Exception 目录下 。


三级继承:
  Symfony2中一般采用三级继承来完成模板创建。它使用三种不同类型的模板:
  首先,创建一个app/Resources/views/base.html.twig 文件,它包含你应用程序主要的布局,该模板被调用时写成 ::base.html.twig。
  然后,为你站点的每个部分section创建一个模板。比如一个AcmeBlogBundle, 它有自己的一个模板AcmeBlogBundle::layout.html.twig。该模板只包含特定的元素,比如body。

复制代码
{# src/Acme/BlogBundle/Resources/views/layout.html.twig #}
{% extends '::base.html.twig' %}

{% block body %}
    <h1>Blog Application</h1>

    {% block content %}{% endblock %}
{% endblock %}
复制代码

  最后,是为每个页面创建一个单独的模板并继承合适的section模板。比如,为index页创建的模板 AcmeBlogBundle:Blog:index.html.twig 用来列出所有的blog。

复制代码
{# src/Acme/BlogBundle/Resources/views/Blog/index.html.twig #}
{% extends 'AcmeBlogBundle::layout.html.twig' %}

{% block content %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
{% endblock %}
复制代码

  注意该模板是继承了section模板(AcmeBlogBundle:layout.html.twig),而section模板又继承了应用程序基模板(::base.html.twig)。这就是通常说的三级继承模式。

  在你创建你的应用程序时,你可以选择这种模式,也可以为每个页面创建模板时直接继承应用程序的基模板(比如: {% extends '::base.html.twig' %} 。
三模板模式对于一个bundle开发商来说是最好的方法,因为这样bundle使用者可以很容易的重写bundle的基模板来适合自己应用程序的基本布局。


安全输出转换:
  当我们从模板中生成HTML时,总会有风险存在,比如一些模板变量可能输出一些意外的HTML或者危险的客户端代码。结果这些动态内容会打破结果页面的HTML或者允许一些恶意的访问者执行一些页面攻击。举个例子:
Twig格式:

Hello {{ name }}

PHP代码格式:

Hello <?php echo $name ?>

想象一下用户输入下面的代码作为他们的name时,结果会是什么?

<script>alert('hello!')</script>

没有任何的输出安全转义,结果模板会触发JavaScript弹出框:

Hello <script>alert('hello!')</script>

  这种情况看上去,没多大害处,如果一个用户知道这一步,它完全有能力写一个javascript在我们未知的安全区域来执行一些恶意行为。这个问题的解决办法是输出安全转义。 如果添加了输出安全转义,同样的模板会渲染出无害的内容,script标签会作为普通文本输出到屏幕上。

Hello &lt;script&gt;alert(&#39;helloe&#39;)&lt;/script&gt;

  PHP和Twig模板化系统采用了不同的方式来解决这个问题。如果你使用Twig,默认情况下是输出安全转义的,你的输出是受到保护的。如果是PHP,则输出安全转义不是自动的,需要你手工的进行处理。

 

Twig中的安全输出
  如果你使用Twig模板,那么输出安全是默认的。你不需要对用户提交的输出内容进行手动保护。在某些情况下,你需要关闭输出安全保护,当你渲染某个可信变量或者包含某个标签时。假设管理员用户可以编写一些代码有HTML标签的文章。默认情况下,Twig将转义文章体。为了渲染正常,需要添加一个raw 过滤器:

{{article.body | raw }}

你也可以在{% block %}区域或者整个模板中关闭安全保护。


PHP中的安全输出保护:
  在PHP中安全输出保护不是自动完成的,这就意味着除非你显示的选择来对某个输出变量进行保护,否则输出都是不安全的。我们使用view的方法escape()来对输出变量进行安全输出保护:

Hello <?php echo $view->escape($name) ?>

  默认情况下,escape()方法默认情况下假设变量是被渲染在一个HTML上下文中的。也就是说只针对HTML安全。 它的第二个参数让你能够改变它针对的上下文。

比如需要在javascript上下文中输出某些东西,就是用 js 上下文。

var myMsg = 'Hello <?php echo $view->escape($name, 'js') ?>';

 


模板调试
  当使用php代码时,我们可以使用var_dump()来快速的查看一个值的变量传递。同样在Twig中,我们可以使用debug扩展来达到相同的效果,只是需要预先在配置文件中开启。
YAML 格式:

# app/config/config.yml
services:
    acme_hello.twig.extension.debug:
        class:        Twig_Extension_Debug
        tags:
             - { name: 'twig.extension' }

XML格式:

<!-- app/config/config.xml -->
<services>
    <service id="acme_hello.twig.extension.debug" class="Twig_Extension_Debug">
        <tag name="twig.extension" />
    </service>
</services>

PHP代码格式:

// app/config/config.php
use Symfony\Component\DependencyInjection\Definition;

$definition = new Definition('Twig_Extension_Debug');
$definition->addTag('twig.extension');
$container->setDefinition('acme_hello.twig.extension.debug', $definition);

这时候,我们就可以使用dump函数来查看模板参数了:

复制代码
{# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #}

{{ dump(articles) }}

{% for article in articles %}
    <a href="/article/{{ article.slug }}">
        {{ article.title }}
    </a>
{% endfor %}
复制代码

 


模板格式:
  模板是一个渲染任何格式内容的通用的方式。大多数情况下,我们使用模板来渲染HTML内容。模板同样也能渲染想javascript,CSS,XML以及你能想象到的其它格式内容。比如,同一个资源resource经常被渲染为不同的格式。把文章目录页渲染为XML,你需要在模板的名称中包含相应的格式即可。

  XML 模板名: AcmeArticleBundle:Article:index.xml.twig
  XML 模板文件名:index.xml.twig

  事实上,这里只是命名上有了变化,而模板并没有真正的基于不同的格式渲染不同。在大多数情况下,你可能想让单一的controller根据请求的格式不同渲染多个不同的格式。下面是一个通常的写法:

public function indexAction()
{
    $format = $this->getRequest()->getRequestFormat();

    return $this->render('AcmeBlogBundle:Blog:index.'.$format.'.twig');
}

  Request对象的getRequestFormat()方法默认返回值为html, request的格式通常是在路由时决定的。比如/contact 设置的请求格式是html,而 /contact.xml 设置的请求格式则是 XML。创建一个包含请求格式的链接,只需要在参数哈希表中包含 _format键值即可。

Twig格式:

<a href="{{ path('article_show', {'id': 123, '_format': 'pdf'}) }}">
    PDF Version
</a>

PHP代码格式:

<a href="<?php echo $view['router']->generate('article_show', array('id' => 123, '_format' => 'pdf')) ?>">
    PDF Version
</a>

 

总结思考:
  Symfony2中的模板引擎是一个强大的工具,你可以用它来根据需要生成包括HTML,XML以及其它任何格式的内容。尽管模板时controller生成内容的通常方式,但是不是必须的。controller返回的Response对象可以使用模板也可以没有模板。

// 使用模板生成Response对象
$response = $this->render('AcmeArticleBundle:Article:index.html.twig');

// 使用简单文本内容生成Response对象
$response = new Response('response content');

  Symfony2的模板引起非诚灵活,默认情况下支持传统的PHP模板和圆滑强大的Twig模板,他们都拥有非常丰富的帮助函数来执行一些常见任务,Symfony2推荐使用Twig模板,因为它更加简洁,高效,能更好的处理继承等。

【Qt】Window环境下搭建Qt6、MSVC2022开发环境(无需提前安装Visual Studio) 本文介绍 Windows 环境下无需安装 Visual Studio,搭建 Qt6 与 MSVC2022 开发环境的方法,以节省磁盘空间。核心步骤包括:用中科大镜像提速 Qt6 在线安装,需勾选 Qt Creator 17.0.1、MSVC 2022 x64 等组件;配置环境变量,添加 mingw_64、msvc2022_64 及 Qt Creator 的二进制目录;安装 MSVC 2022 编译器与 Windows 10 SDK 并记录版本;配置 Qt Creator 构建套件,可选设置 vcvarsal 阅读详情

相关推荐

【算法实战】Keystone变换:从原理到MATLAB实现的距离走动校正

本文深入解析Keystone变换在雷达信号处理中的距离走动校正应用,从原理到MATLAB实现全面讲解。通过三种实现方法(DFT+IFFT、Sinc插值、Chirp-Z变换)的对比分析,结合实战案例展示如何有效解决高速目标导致的距离单元跨越问题,提升多普勒频谱聚焦质量。

weixin_29055699的博客 294

MAC更新和使用composer

最近有新项目需要搭建,发现composer安装项目有报错信息。错误解决,又可以和composer一起玩耍了。确定了当前版本,就可以升级下版本看结果了。初步排查,composer库不是新的了。查看当前composer版本和基本信息。最后看下升级完成后的版本。

qq_33665793的博客 2764

6.5 构网型储能系统的协同控制策略

本文系统阐述了构网型储能系统的协同控制策略,重点分析了多机组群协同运行面临的功率分配不均、动态响应失配等挑战。研究提出了改进型下垂控制与虚拟阻抗法、基于一致性算法的分布式协同控制等解决方案,探讨了构网型储能与同步发电机在惯性响应、一次调频等方面的协同机制,以及与跟网型电源在电压支撑、阻抗重塑等方面的互补作用。文章构建了分层控制架构,为实现多类型电源的全局优化运行提供了技术路径,对提升高比例新能源电力系统的稳定性具有重要意义。

技术工作者 1004

解决php deprecated 的问题

解决php deprecated 的问题

qq_38472535的博客 2380

【深度学习-番外1】Win10系统搭建VSCode+Anaconda+Pytorch+CUDA深度学习环境和框架全过程

本文将介绍在Windows 10系统下搭建深度学习环境的完整过程,包括安装Anaconda、CUDA、NVIDIA显卡驱动以及Pytorch框架。后续本专栏的Python语言下的深度学习环境都以本篇搭建的为准。

fengzhuqiaoqiu的博客 4002

用LangFuse+LangChain打造可观测的AI应用:从埋点到成本监控实战

本文详细介绍了如何将开源可观测性平台LangFuse深度集成到基于LangChain构建的AI应用中,特别是电商客服机器人场景。通过从基础SDK集成、提示词管理到成本监控的完整实战,帮助开发者实现对LLM应用内部工作流的清晰追踪、问题排查与费用分析,从而打造稳定、可控的生产级AI应用。

dapp9builder的博客 711

控制台输入避免中文乱码的小技巧

这是从lumen框架里面找出来的 ## Symfony\Component\Console\Helper\QuestionHelper $ret = ''; $cp = setIOCodepage(); while (false !== ($char = fgetc($multiLineStreamReader))) { if (\PHP_EOL === "{$ret}{$char}") { break; } $ret .= $char; } resetI

了缺的专栏 567

kettle信息发送钉钉

由于其他的作业比较多,想要在job中加入一个转化发送消息到钉钉,其他的配置说明直接获取系统的信息。这样也避免直接修改其他的转换和大量的工作量。 步骤: 1、新建一个转换 拉取获取系统信息、获取变量、JavaScript代码、获取access_token组件。 2、获取系统信息设置 拿到需要的信息,比如作业的读写更新删除行数,job的日志内容 这个日志内容同在作业执行页面下输出的日志,所以可以在执行作业时选择是详细日志、基本日志还是错误日志。 3、获取变量 获取变量主要是想要去拿到job的名称,文件名。按

Deng_7788的博客 1448

解决composer安装laravel 5.2.23时报错:Script php artisan clear-compiled handling the post-update-cmd event

由于 Laravel 5.2 已经是一个相当老的版本,建议您升级到 Laravel 的最新版本或至少升级到一个较新的版本(如 Laravel 5.7 或更高版本)。这个错误是因为您尝试安装的 Laravel 版本(5.2.23)使用了 Symfony 组件的一个较旧版本,该版本的组件中有一个方法的返回类型声明与 PHP 7.1 及更高版本的期望不符。然而,在 Symfony 的旧版本中,这个方法可能没有显式地声明返回类型,或者返回类型声明不匹配。的返回类型一致,即返回布尔值。方法的返回类型应该与。

学亮编程手记 1065

从零开始:在Unity中使用Dynamic Bone实现角色骨骼自然抖动(以女性角色胸部为例)

本文详细介绍了在Unity中使用Dynamic Bone插件实现角色骨骼自然抖动的完整流程,特别以女性角色胸部为例。从插件导入、骨骼系统基础到Dynamic Bone组件配置和参数调优,提供了全面的技术指导。文章还包含性能优化技巧和常见问题解决方案,帮助开发者快速掌握这一物理效果实现方法。

weixin_28728495的博客 454

手把手教你学PCIE(5.1)--pcie固件初始化的硬件初始化

PCIe 固件初始化的硬件初始化是一个复杂但至关重要的过程。通过正确配置 PCIe 控制器和相关硬件,可以确保系统的稳定性和性能。以上步骤和示例代码提供了一个基本的框架,实际开发中可能需要根据具体的硬件和需求进行调整和优化。

MHD0815的博客 1689

php模板 gt用法,Symfony2学习笔记之模板用法详解

本文实例讲述了Symfony2学习笔记之模板用法。分享给大家供大家参考,具体如下:我们知道,controller负责处理每一个进入Symfony2应用程序的请求。实际上,controller把大部分的繁重工作都委托给了其它地方,以使代码能够被测试和重用。当一个controller需要生成HTML,CSS或者其他内容时,它把这些工作给了一个模板化引擎。模板:一个模板仅仅是一个文本文件,它能生成任意的...

weixin_39731916的博客 479

【ZYNQ】OV5640 图像采集与显示

OV5640 是豪威(OmniVision)半导体公司推出的高性能的 CMOS 数字图像传感器,支持最高 500 万像素图像采集,支持 RAW RGB、RGB565、YCbCr422 等图像格式输出,可应用于手机、平板等电子设备。本文主要介绍如何使用 Zynq 驱动 OV5640 摄像头进行图像采集,并通过 HDMI 实时显示。

洋洋Young的博客 1433

Symfony2模板

  我们知道,controller负责处理每一个进入Symfony2应用程序的请求。实际上,controller把大部分的繁重工作都委托给了其它地方,以使代码能够被测试和重用。当一个controller需要生成HTML,CSS或者其他内容时,它把这些工作给了一个模板化引擎。 模板:  一个模板仅仅是一个文本文件,它能生成任意的文本格式(HTML,XML,CSV,LaTex...)。...

DELL851314的博客 209

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Symfony 2 Eclipse 插件使用教程

Symfony 2 Eclipse 插件使用教程 项目介绍 Symfony 2 Eclipse 插件是一个为 Eclipse IDE 设计的插件,旨在提高开发者在 Eclipse 中使用 Symfony 2 框架的效率。该插件提供了代码自动完成、语法高亮、调试支持等功能,帮助开发者更高效地进行 Symfony 2 项目的开发。 项目快速启动 安装插件 打开 Eclipse IDE。 进入 Hel...

gitblog_00862的博客 1018

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

symfony入门学习资料之十三:symfony框架Twig模板语言的使用

symfony入门学习资料之十三:symfony框架Twig模板语言的使用 php的Twig模板语言:类似python的jinja2,语法什么的都是类似python 一、模板继承 模板路径:app/Resources/views/ 母版:base.html.twig <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-e...

jyl_sh的专栏 1112

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Symfony2学习笔记之表单

对于一个Web开发者来说,处理HTML表单是一个最为普通又具挑战的任务。Symfony2集成了一个Form组件,让处理表单变的容易起来。在这一节里,我们将从基础开始创建一个复杂的表单,学习表单类库中最重要的内容。 Symfony2 的Form组件是一个独立的类库,你可以在Symfony2项目之外使用它。 创建一个简单的表单:假设你要创建一个应用程序的todo列表,需要显示一些任务。因为你的用户...

huidaoli 1664

Symfony2 AdmingeneratorGeneratorBundle 使用教程

Symfony2 AdmingeneratorGeneratorBundle 使用教程 1. 项目目录结构及介绍 Symfony2 AdmingeneratorGeneratorBundle 是一个基于 Symfony2 框架的 Admin 生成器,它通过 YAML 配置文件和 Twig 模板生成管理界面。以下是该项目的目录结构及其介绍: AdmingeneratorGeneratorBundle...

gitblog_00937的博客 989

symfony入门学习资料之七:创建和使用模板

symfony入门学习资料之七:创建和使用模板 如同前面几章介绍所述,控制器(controller)负责处理每一个进入symfony程序的请求,通常以输出模板来生成响应内容作为结束。现实中,控制器把大部分的繁重工作都委托给了其他地方,以令代码能够被测试和复用。当一个controller需要生成HTML、CSS或者其他内容时,它把这些工作给了一个模板引擎。在本文中,将学习如何编写功能强大的模板,用于把内容返回给用户、填充email,等等。还将介绍快捷方法,用简单明了的方式来扩展模板,以及如何复...

jyl_sh的专栏 1241

Symfony2Project 使用教程

Symfony2Project 使用教程 1. 项目介绍 Symfony2Project 是一个用于生成 Symfony 2 项目初始结构的工具。它提供了一系列命令行选项,帮助开发者快速搭建 Symfony 2 项目的初始结构,包括控制器、ORM、模板引擎等组件的配置。该项目旨在简化 Symfony 2 项目的初始化过程,使开发者能够更专注于业务逻辑的开发。 2. 项目快速启动 安装 首先,确保你...

gitblog_00519的博客 762

Symfony2 学习笔记之系统路由

mfony2 学习笔记之系统路由 漂亮的URL绝对是一个严肃的web应用程序必须做到的,这种方式使index.php?article_id=57这类的丑陋URL被隐藏,由更受欢迎的像 /read/intro-to-symfony 来替代。 拥有灵活性更为重要,如果你要改变一个页面的URL,比如从/blog 到 /new 怎么办?有多少链接需要你找出来并更新呢? 如果你使用Symfony的r...

huidaoli 1666

如何运行php2twig,如何在Symfony 2和3中的模板上使用Twig执行原则查询

本文概述有时由于复杂的设计模式, 或者由于对数据库的查询知识掌握的技能不足, 你不得不在视图中进行查询。直到Symfony 2成为问题为止, 因为你可以使用php从视图访问实体管理器, 但是随着Symfony 2中引入Twig的实现, 这变得越来越难。请记住, 这不是一个好习惯, 因为它不能与MVC工作流程一起完成。但是, 如果你很着急, 这将为你解决问题:创建一个包含树枝扩展名的类。写扩展名。在...

weixin_39598472的博客 189

symfony 2_使用FOSUserBundle的Symfony2中的基本用户管理

symfony 2Symfony has a very powerful authentication and authorization system, which can cater to a lot of our needs out of the box. FOSUserBundle is a library built on top of Symfony’s security syste...

culh2177的博客 426

Symfony2 Admin Generator:为Symfony2打造的强大后台生成器

Symfony2 Admin Generator:为Symfony2打造的强大后台生成器 项目介绍 Symfony2 Admin Generator 是一个基于YAML配置和Twig模板引擎的Symfony2后台生成器。它能够通过简单的命令生成模型对应的视图和控制器,极大地简化了后台管理系统的开发流程。该项目受到了 fzaninotto/Doctrine2ActiveRecord 的启发,旨在为S...

gitblog_00056的博客 510
上一篇: PHP json_encode中文乱码解决方法--json乱码处理
下一篇: apache虚拟主机配置
HackProgramer
博客等级 码龄12年 255粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值