Twig render vs include - 何时何地使用其中一个?

时间:2022-07-12 14:13:48

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.

我读过Twig:render vs include但它不是我想要的。我不知道我应该在何时何地使用渲染,何时应该使用include,因为这些表达式的行为看起来与我非常相似。

What is the fundamental differences between these two expressions ?

这两个表达式之间的根本区别是什么?

1 个解决方案

#1


45  

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

{%render%}和{%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.

    {%render%}标记调用操作:执行此操作时,您正在执行控制器,在该控制器内创建新上下文并呈现将添加到当前视图的视图。

  • {% 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.

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

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.

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

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

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

Twig render vs include  - 何时何地使用其中一个?

The Stuff entity

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

}

The Stuff form

东西形式

<?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";
    }

}

The routing.yml file

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 }

The controllers

控制器

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

The index.html.twig

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

listStuffs.html.twig

{# listStuf

{#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 :

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

Twig render vs include  - 何时何地使用其中一个?

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.

[%include%}标记允许您包含一些twig代码,其方式与include指令在PHP中的工作方式相同。这基本上意味着:{%include%}为您提供了一种在应用程序中的任何地方重用一些通用代码的方法。

Twig render vs include  - 何时何地使用其中一个?

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

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

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 :

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 :

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.

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


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.

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

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代码时,将使用{%include%},但是您需要在与父twig文件相同的操作中初始化包含的视图所需的上下文。

#1


45  

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

{%render%}和{%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.

    {%render%}标记调用操作:执行此操作时,您正在执行控制器,在该控制器内创建新上下文并呈现将添加到当前视图的视图。

  • {% 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.

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

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.

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

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

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

Twig render vs include  - 何时何地使用其中一个?

The Stuff entity

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

}

The Stuff form

东西形式

<?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";
    }

}

The routing.yml file

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 }

The controllers

控制器

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

The index.html.twig

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

listStuffs.html.twig

{# listStuf

{#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 :

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

Twig render vs include  - 何时何地使用其中一个?

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.

[%include%}标记允许您包含一些twig代码,其方式与include指令在PHP中的工作方式相同。这基本上意味着:{%include%}为您提供了一种在应用程序中的任何地方重用一些通用代码的方法。

Twig render vs include  - 何时何地使用其中一个?

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

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

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 :

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 :

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.

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


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.

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

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代码时,将使用{%include%},但是您需要在与父twig文件相同的操作中初始化包含的视图所需的上下文。