Twig 渲染与包含 - 何时何地使用其中一个?

Posted

技术标签:

【中文标题】Twig 渲染与包含 - 何时何地使用其中一个?【英文标题】:Twig render vs include - When and where to use one or the other? 【发布时间】:2013-04-24 05:25:12 【问题描述】:

我已经阅读了Twig: render vs include,但这不是我想要的。我不确定应该在何时何地使用渲染,何时应该使用包含,因为这些表达式的行为似乎与我非常相似。

这两种表达方式的根本区别是什么?

【问题讨论】:

您是指控制器中的return $this->render('MyBundle::index.html.twig'); 和模板中的% include MyBundle::index.html.twig % @SirDerpington 我的意思是 % render %% include % 都在树枝模板中 【参考方案1】:

% render %% include % 之间存在重大差异。

% render % 标记调用一个动作:当您这样做时,您正在执行一个控制器,在该控制器内创建一个新上下文并呈现一个将添加到您当前视图的视图。

% include % 标签在当前标签中包含另一个 twig 文件:没有调用任何操作,因此包含的文件将使用您当前的上下文(或您作为参数提供的上下文)来呈现视图。

让我们详细了解一下。


一个 % render % 示例​​

Render 是一个标签,它调用动作的方式与您使用路由调用它的方式非常相似,但在内部,没有 HTTP 事务。就个人而言,当我的视图中包含的内容需要使用 ajax 刷新时,我使用 % render %。这样,当我的页面内有交互时,我就可以使用标准路由调用相同的操作。

考虑一个简单的页面,它有一个 ajax 表单,可以帮助您添加内容,以及一个动态刷新的内容表。

Stuff 实体

<?php

// src/Fuz/HomeBundle/Entity/StuffData.php

namespace Fuz\HomeBundle\Entity;

class StuffData


    private $stuff;

    public function getStuff()
    
        return $this->stuff;
    

    public function setStuff($stuff)
    
        $this->stuff = $stuff;
        return $this;
    


Stuff 表单

<?php

// src/Fuz/HomeBundle/Form/StuffType.php

namespace Fuz\HomeBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class StuffType extends AbstractType


    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder->add('stuff', 'text', array('label' => ''));
    

    public function getDefaultOptions(array $options)
    
        return array (
                'data_class' => 'Fuz\HomeBundle\Entity\StuffData',
        );
    

    public function getName()
    
        return "Stuff";
    


routing.yml 文件

# src/Fuz/HomeBundle/Resources/config/routing.yml

fuz_home:
    pattern:  /
    defaults:  _controller: FuzHomeBundle:Default:index 

fuz_add_stuff:
    pattern:  /add_stuff
    defaults:  _controller: FuzHomeBundle:Default:addStuff 

fuz_del_stuff:
    pattern:  /del_stuff
    defaults:  _controller: FuzHomeBundle:Default:delStuff 

fuz_list_stuffs:
    pattern:  /list_stuffs
    defaults:  _controller: FuzHomeBundle:Default:listStuffs 

控制器

<?php

namespace Fuz\HomeBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Fuz\HomeBundle\Entity\StuffData;
use Fuz\HomeBundle\Form\StuffType;

class DefaultController extends Controller


    /**
     * Route : fuz_home
     */
    public function indexAction()
    
        // Initialize some stuffs, stored in the session instead of in a table for simplicity
        if (!$this->get('session')->has('stuffs'))
        
            $this->get('session')->set('stuffs', array());
        

        // Create the form used to add a stuff
        $form = $this->createForm(new StuffType(), new StuffData());

        $twigVars = array(
                'formAddStuff' => $form->createView(),
        );

        return $this->render('FuzHomeBundle:Default:index.html.twig', $twigVars);
    

    /**
     * Route : fuz_add_stuff
     */
    public function addStuffAction()
    
        $data = new StuffData();
        $form = $this->createForm(new StuffType(), $data);
        $form->bindRequest($this->getRequest());
        if ($form->isValid())
        
            $stuffs = $this->get('session')->get('stuffs');
            $stuffs[] = $data->getStuff();
            $this->get('session')->set('stuffs', $stuffs);
        
        return $this->forward("FuzHomeBundle:Default:listStuffs");
    

    /**
     * Route : fuz_del_stuff
     */
    public function delStuffAction()
    
        $stuffId = $this->getRequest()->get('stuffId');
        $stuffs = $this->get('session')->get('stuffs');
        if (array_key_exists($stuffId, $stuffs))
        
            unset($stuffs[$stuffId]);
            $this->get('session')->set('stuffs', array_values($stuffs));
        
        return $this->forward("FuzHomeBundle:Default:listStuffs");
    

    /**
     * Route : fuz_list_stuffs
     */
    public function listStuffsAction()
    
        $stuffs = $this->get('session')->get('stuffs');
        $twigVars = array(
                'stuffs' => $stuffs,
        );
        return $this->render('FuzHomeBundle:Default:listStuffs.html.twig', $twigVars);
    

index.html.twig

# src/Fuz/HomeBundle/Resources/views/Default/index.html.twig #

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

# The form that will be posted asynchronously #
<form id="formStuff">
     form_widget(formAddStuff) 
    <input type="button" id="add-stuff" value="Add stuff" />
</form>

<br/><br/>

# The div that will contain the dynamic table #
<div id="list-stuffs">
    % render path('fuz_list_stuffs') %
</div>

# When a click is made on the add-stuff button, we post the form #
<script type="text/javascript">
    $('#add-stuff').click(function() 
        $.post(' path('fuz_add_stuff') ',  $('#formStuff').serialize(), function(data) 
            $('#list-stuffs').html(data);
         );
     );
</script>

listStuffs.html.twig

#listStuf

fs.html.twig #

% if stuffs | length == 0 %

    No stuff to display !

% else %

    <table style="width: 50%">

        % for stuffId, stuff in stuffs %
            <tr>
                <td> stuff </td>
                <td><a data-stuff-id=" stuffId " class="delete-stuff">Delete</a></td>
            </tr>
        % endfor %

    </table>

<script type="text/javascript">
    $('.delete-stuff').click(function() 
        $.post(' path('fuz_del_stuff') ', 'stuffId': $(this).data('stuff-id'), function(data) 
            $('#list-stuffs').html(data);
         );
     );
</script>

% endif %

这会给你一些看起来像这样的丑陋形式:

重点是:如果您刷新页面或添加/删除内容,将调用相同的控制器。无需创建一些复杂的逻辑或复制代码。


% include % 示例​​

[% include % 标签让您可以包含一些树枝代码,其方式与 PHP 中的 include 指令的工作方式大致相同。这基本上意味着:% include % 为您提供了一种在应用程序中随处重用一些通用代码的方法。

我们继续使用我们的 stuffs 示例:保留 StuffEntity 和 StuffData 但替换以下内容:

路由:

fuz_home:
    pattern:  /
    defaults:  _controller: FuzHomeBundle:Default:index 

fuz_add_stuff:
    pattern:  /add_stuff
    defaults:  _controller: FuzHomeBundle:Default:addStuff 

fuz_del_stuff:
    pattern:  /del_stuff
    defaults:  _controller: FuzHomeBundle:Default:delStuff 

控制器:

public function indexAction()

    // Initialize some stuffs, stored in the session instead of in a table for simplicity
    if (!$this->get('session')->has('stuffs'))
    
        $this->get('session')->set('stuffs', array());
    

    // Create the form used to add a stuff
    $form = $this->createForm(new StuffType(), new StuffData());
    $stuffs = $this->get('session')->get('stuffs');

    $twigVars = array(
            'formAddStuff' => $form->createView(),
            'stuffs' => $stuffs,
    );

    return $this->render('FuzHomeBundle:Default:index.html.twig', $twigVars);


/**
 * Route : fuz_add_stuff
 */
public function addStuffAction()

    $data = new StuffData();
    $form = $this->createForm(new StuffType(), $data);
    $form->bindRequest($this->getRequest());
    if ($form->isValid())
    
        $stuffs = $this->get('session')->get('stuffs');
        $stuffs[] = $data->getStuff();
        $this->get('session')->set('stuffs', $stuffs);
    
    return $this->forward("FuzHomeBundle:Default:index");


/**
 * Route : fuz_del_stuff
 */
public function delStuffAction()

    $stuffId = $this->getRequest()->get('id');
    $stuffs = $this->get('session')->get('stuffs');
    if (array_key_exists($stuffId, $stuffs))
    
        unset($stuffs[$stuffId]);
        $this->get('session')->set('stuffs', array_values($stuffs));
    
    return $this->forward("FuzHomeBundle:Default:index");

index.html.twig:

# src/Fuz/HomeBundle/Resources/views/Default/index.html.twig #

<form action=" path('fuz_add_stuff') " method="post">
     form_widget(formAddStuff) 
    <input type="submit" value="Add stuff" />
</form>

<br/><br/>

# Here we include our "generic" table with the stuff table as parameter #
%
    include 'FuzHomeBundle:Default:genericTable.html.twig'
    with 
        'route': 'fuz_del_stuff',
        'data' : stuffs,
    
%

通用表:

# src/Fuz/HomeBundle/Resources/views/Default/genericTable.html.twig #

% if data | length == 0 %

    No data to display !

% else %

    <table style="width: 50%">

        % for id, elem in data %
            <tr>
                <td> elem </td>
                <td><a href=" path(route, 'id': id) ">Delete</a></td>
            </tr>
        % endfor %

    </table>

% endif %

正如您在此处看到的,只有一个控制器可以初始化页面的整个元素(表单和表格),因此无法进行异步事务。但是,您可以在应用程序的任何位置包含此 genericTable.html.twig 文件。


结论

当要插入的视图可以使用标准路由刷新或要插入的视图完全独立于当前上下文时,您将使用% render %

当您需要在应用程序中多次使用一段 twig 代码时,您将使用 % include %,但您需要在与父 twig 文件相同的操作中初始化包含的视图所需的上下文。

【讨论】:

谢谢我没想到阿贾克斯,你的回答很适合我的需要! 我不知道 twig 中的 % render % 标签。你能指点我一个文档条目或一些样本吗?看起来真的很有趣 嗯,它看起来没有很多文档,看看旧的Symfony2 doc,然后搜索Embedding Controllers 谢谢!确实没有太多关于它的记录。但我认为这可能会在某个时候出现。 +1:D 希望我能不止一次地支持这样一个很好的例子!

以上是关于Twig 渲染与包含 - 何时何地使用其中一个?的主要内容,如果未能解决你的问题,请参考以下文章

朋友模板定义。何时何地包含 <T>?

_DEBUG 何时何地定义?

将twig渲染为html文件,避免重复代码添加变量

NHibernate ISession Flush:何时何地使用它,为啥?

BaseHTTPServer和SimpleHTTPServer有什么区别?何时何地使用它们?

核心数据:何时何地首先加载实体?