Twig render vs include - 何时何地使用其中一个? [英] Twig render vs include - When and where to use one or the other?

查看:15
本文介绍了Twig render vs include - 何时何地使用其中一个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

解决方案

{% render %}{% include %} 有很大的不同.p>

  • {% render %} 标签调用一个动作:当你这样做时,你正在执行一个控制器,在该控制器内创建一个新的上下文并呈现一个将被添加到的视图你目前的看法.

  • {% include %} 标签在当前标签中包含另一个树枝文件:没有调用任何操作,因此包含的文件将使用您当前的上下文(或您提供的上下文参数)来渲染视图.

让我们详细了解一下.

<小时>

一个 {% render %} 示例​​

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

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

Stuff 实体

Stuff 表单

add('stuff', 'text', array('label' => ''));}公共函数 getDefaultOptions(数组 $options){返回数组 ('data_class' =>'FuzHomeBundleEntityStuffData',);}公共函数 getName(){返回东西";}}

routing.yml 文件

# src/Fuz/HomeBundle/Resources/config/routing.ymlfuz_home:图案: /默认值:{ _controller: FuzHomeBundle:Default:index }fuz_add_stuff:模式:/add_stuff默认值:{ _controller: FuzHomeBundle:Default:addStuff }fuz_del_stuff:模式:/del_stuff默认值:{ _controller: FuzHomeBundle:Default:delStuff }fuz_list_stuffs:模式:/list_stuffs默认值:{ _controller: FuzHomeBundle:Default:listStuffs }

控制器

get('session')->has('stuffs')){$this->get('session')->set('stuffs', array());}//创建用于添加东西的表单$form = $this->createForm(new StuffType(), new StuffData());$twigVars = 数组('formAddStuff' =>$form->createView(),);return $this->render('FuzHomeBundle:Default:index.html.twig', $twigVars);}/*** 路线:fuz_add_stuff*/公共函数 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");}/*** 路线:fuz_del_stuff*/公共函数 delStuffAction(){$stuffId = $this->getRequest()->get('stuffId');$stuffs = $this->get('session')->get('stuffs');if (array_key_exists($stuffId, $stuffs)){未设置($stuffs[$stuffId]);$this->get('session')->set('stuffs', array_values($stuffs));}return $this->forward("FuzHomeBundle:Default:listStuffs");}/*** 路线:fuz_list_stuffs*/公共函数 listStuffsAction(){$stuffs = $this->get('session')->get('stuffs');$twigVars = 数组('东西' =>$东西,);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>{# 将异步发布的表单#}<form id="formStuff">{{ form_widget(formAddStuff) }}<input type="button" id="add-stuff" value="添加东西"/></表格><br/><br/>{# 将包含动态表的 div #}<div id="list-stuffs">{% 渲染路径('fuz_list_stuffs') %}</div>{# 当点击 add-stuff 按钮时,我们发布表单 #}<脚本类型="文本/javascript">$('#add-stuff').click(function() {$.post('{{ path('fuz_add_stuff') }}', $('#formStuff').serialize(), function(data) {$('#list-stuffs').html(data);});});</脚本>

listStuffs.html.twig

{#listStuf

fs.html.twig #}{% 如果东西 |长度 == 0 %}没有东西可以展示!{% 别的 %}<表格样式="宽度:50%">{% for stuffId, stuff in stuffs %}<tr><td>{{ 东西 }}</td><td><a data-stuff-id="{{ stuffId }}" class="delete-stuff">删除</a></td></tr>{% endfor %}</表><脚本类型="文本/javascript">$('.delete-stuff').click(function() {$.post('{{ path('fuz_del_stuff') }}', {'stuffId': $(this).data('stuff-id')}, function(data) {$('#list-stuffs').html(data);});});</脚本>{% 万一 %}

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

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

<小时>

{% include %} 示例​​

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

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

路由:

fuz_home:图案: /默认值:{ _controller: FuzHomeBundle:Default:index }fuz_add_stuff:模式:/add_stuff默认值:{ _controller: FuzHomeBundle:Default:addStuff }fuz_del_stuff:模式:/del_stuff默认值:{ _controller: FuzHomeBundle:Default:delStuff }

控制器:

公共函数 indexAction(){//初始化一些东西,为了简单起见,存储在会话中而不是表中if (!$this->get('session')->has('stuffs')){$this->get('session')->set('stuffs', array());}//创建用于添加东西的表单$form = $this->createForm(new StuffType(), new StuffData());$stuffs = $this->get('session')->get('stuffs');$twigVars = 数组('formAddStuff' =>$form->createView(),'东西' =>$东西,);return $this->render('FuzHomeBundle:Default:index.html.twig', $twigVars);}/*** 路线:fuz_add_stuff*/公共函数 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");}/*** 路线:fuz_del_stuff*/公共函数 delStuffAction(){$stuffId = $this->getRequest()->get('id');$stuffs = $this->get('session')->get('stuffs');if (array_key_exists($stuffId, $stuffs)){未设置($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="添加内容"/></表格><br/><br/>{# 这里我们包含我们的通用"表,其中的 stuff 表作为参数 #}{%包括'FuzHomeBundle:默认:genericTable.html.twig'和 {'路线':'fuz_del_stuff','数据':东西,}%}

通用表:

{# src/Fuz/HomeBundle/Resources/views/Default/genericTable.html.twig #}{% 如果数据 |长度 == 0 %}没有数据显示 !{% 别的 %}<表格样式="宽度:50%">{% for id, elem in data %}<tr><td>{{ elem }}</td><td><a href="{{ path(route, {'id': id}) }}">删除</a></td></tr>{% endfor %}</表>{% 万一 %}

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

<小时>

结论

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

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

I've read Twig: render vs include but it isn't what I'm looking for. I am not sure where and when should I use render, and when should I use include, as the behavior of these expressions seems very similar to me.

What is the fundamental differences between these two expressions ?

解决方案

There are major differences between {% render %} and {% include %}.

  • {% render %} tag calls an action : when you do that, you are executing a controller, creating a new context inside that controller and renders a view that will be added to your current view.

  • {% include %} tag includes another twig file in the current one : there are no action called, so the included file will use your current context (or the context you give as parameter) to render the view.

Let's see that in details.


A {% render %} example

Render is a tag that calls an action the very same way as if you were calling it using a route, but internally, without HTTP transactions. Personally, I am using {% render %} when the content included to my view need to be refreshed using ajax. In that way, I'm able to call the same action using the standard routing when there is interactions inside my page.

Consider a simple page with an ajax form that helps you to add stuffs, and a dynamically refreshed table of stuffs.

The Stuff entity

<?php

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

namespace FuzHomeBundleEntity;

class StuffData
{

    private $stuff;

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

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

}

The Stuff form

<?php

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

namespace FuzHomeBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;

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' => 'FuzHomeBundleEntityStuffData',
        );
    }

    public function getName()
    {
        return "Stuff";
    }

}

The routing.yml file

# 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 }

The controllers

<?php

namespace FuzHomeBundleController;

use SymfonyBundleFrameworkBundleControllerController;
use FuzHomeBundleEntityStuffData;
use FuzHomeBundleFormStuffType;

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);
    }

The 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>

The 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 %}

This will give you some ugly form looking like this :

The point is : if you refresh your page or if you add/delete stuffs, the same controller will be called. No need to create some complex logic or to duplicate code.


An {% include %} example

The [% include %} tag let you include some piece of twig code about the same way as the include instruction works in PHP. This mean basically : {% include %} gives you a way to reuse some generic piece of code everywhere in your application.

We stay with our stuffs example : keep StuffEntity and StuffData but replace the following :

Routing :

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 }

Controllers :

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,
    }
%}

genericTable :

{# 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 %}

As you can see here, there is only one controller that initialize the whole elements of the page (the form and the table), so that's not possible to do asynchronous transactions. But, you can include this genericTable.html.twig file anywhere in your application.


Conclusion

You will use {% render %} when the view to insert may be refreshed using a standard route or when the view to insert is totally independant from the current context.

You will use {% include %} when you need to use a piece of twig code several times in your application, but you will need to initialize the included view's required context in the same action as the parent twig file.

这篇关于Twig render vs include - 何时何地使用其中一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆