Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twig: render vs include

Tags:

twig

symfony

I am creating an online store. I have a performance problem if I use the twig function "render" instead of "include".

Here is the code that displays a product catalog:

catalog controller:

<?php
// src/Acme/StoreBundle/Controller/Product/Catalog.php

namespace Acme\StoreBundle\Controller\Product;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class CatalogController extends Controller
{
    /**
     * @Template()
     */
    public function productAction(\Acme\StoreBundle\Entity\Product\Category $category)
    {
        $qb = $this->getDoctrine()
            ->getRepository('StoreBundle:Product')
            ->createQueryBuilder('product')
            ->select('partial product.{id, token, name}')
            ->innerJoin('product.categoryRelation', 'categoryRelation')
            ->where('categoryRelation.category = :category_id');

        $qb->setParameters(array(
            'category_id'  => $category->getId(),
        ));

        $products = $qb->getQuery()
            ->getResult();

        return $this->render('StoreBundle:Product\Catalog:product.html.twig', array(
            'category' => $category,
            'products' => $products,
        ));
    }
}

... template for catalog controller:

{# src/Acme/StoreBundle/Resources/views/Product/Catalog/product.html.twig #}
{% extends 'AcmeDemoBundle::layout.html.twig' %}

{% block content %}
    <h1>{{ category.name }}</h1>

    <ul>
    {% for product in products %}
        <li>
            {#% render "StoreBundle:Product:show" with { product: product } %#}
            {% include "StoreBundle:Product:show.html.twig" with { product: product } %}
        </li>
    {% endfor %}
    </ul>

{% endblock %}

... product controller:

<?php
// src/Acme/StoreBundle/Controller/Product.php

namespace Acme\Enter\StoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Enter\StoreBundle\Entity\Product;

class ProductController extends Controller
{
    /**
     * @Template()
     */
    public function showAction(Product $product)
    {
        return array('product' => $product);
    }
}

... simple (but more complex in future) template for product controller:

{# src/Acme/StoreBundle/Resources/views/Product/show.html.twig #}
{{ product.name }}

So if I use:

{% include "StoreBundle:Product:show.html.twig" with { product: product } %}

...all ok: 147ms and 4608Kb memory.

But when I need a controller to display the product:

{% render "StoreBundle:Product:show" with { product: product } %#}

...my script consumes too much time and memory: 3639ms and 17664Kb memory!

How to increase speed and reduce memory consumption by using the controller?

like image 939
George Avatar asked Jan 31 '12 09:01

George


People also ask

Why do we need the only keyword for include or embed?

Based on the differences, Include should be used only when you need to split a template into many functional sub-templates and reuse the wrapped code elsewhere. While Embed is used when you need to customise the reusable templates.

Is Twig a Symfony?

It's an open source product licensed under a BSD License and maintained by Fabien Potencier. The initial version was created by Armin Ronacher. Symfony PHP framework comes with a bundled support for Twig as its default template engine since version 2.

What is raw in Twig?

raw. By default, everything in Twig gets escaped when automatic escaping is enabled. If you don't want to escape a variable you'll have to explicitly mark it as safe which you can do by using the raw filter. This only works if the raw filter is the last filter that is applied to the filter.

Which features are provided by Twig?

Fast: Twig compiles templates down to plain optimized PHP code. The overhead compared to regular PHP code was reduced to the very minimum. Secure: Twig has a sandbox mode to evaluate untrusted template code. This allows Twig to be used as a template language for applications where users may modify the template design.


2 Answers

Each render call spawns a new request, with the performance degradation issue that you are describing. I don't think there is much you can do about that but using esi caching, so that single fragments coming from render calls can be cached. Otherwise you could try to revise your logic to reduce the usage of render calls.

like image 83
Aldo Stracquadanio Avatar answered Oct 13 '22 16:10

Aldo Stracquadanio


Correct me if I am wrong, but the basic idea is that include basically "copy-pastes" its content instead of the command.

Whereas render command must create the controller first, initialize it, run the corresponding function etc. So who knows what heavy artillery is hidden inside this controller's or parent's classes, constructors and so on?

Also remember, that even included templates are rendered. So you even might get recursions or something similar when rendering from twig. Personally I try avoiding rendering anything outside of controller's return.

Plus as mentioned by Louis-Philippe Huberdeau in comments, dev environment can drastically differ from prod mode because of different options and logging.

As for advices - try avoiding putting logic in your templates, or try using static objects that are often used in templates to reuse them instead of creating new ones over and over. And render stuff from controllers only

like image 1
GodlyHedgehog Avatar answered Oct 13 '22 18:10

GodlyHedgehog