Reputation: 113
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?
Upvotes: 10
Views: 41434
Reputation: 86
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
Upvotes: 1
Reputation: 6237
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.
Upvotes: 5