LanderTaker
LanderTaker

Reputation: 55

Adding debug traces to Symfony 3.4 twig templates during/after render

I am looking for a seamless way to do this.

With Symfony 3.4, I need a way to, having a rendered page, know, for any element/text, which twig template it comes from.

NOTE: I have checked Twig - display template names if debug mode is enabled, but that thread is about using Twig but no Symfony. I have been following the examples there but without results.

I would like to not just add tracing data in every template, but to have the minimum possible invasive code needed to, for example, add to the starting point of a twig file and at the end of the file.

As there are blocks as well, the same but something like <trace twig="…" block="…"/>, etc, to each one of those blocks.

(Of course style=“display:none” in those marks)

-------------- attempts

I have put the other quoted question template at templates/DebugTemplate.php, app/templates/debugTemplate.php, and src/AppBundle/Twig/DebugTemplate.php

I went to app/config/config.yml and added twig->base_template_class, but I do not know how to correctly make this configuration work.

I have understood that you just have to write the template name directly like:

# Twig Configuration
twig:
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    base_template_class: DebugTemplate

But it crashes with Unexpected characters (}) at line 116 (near "base_template_class: {'DebugTemplate'}")

Same with

base_template_class: Twig\DebugTemplate
base_template_class: 'Twig\DebugTemplate'
base_template_class: {'Twig\DebugTemplate'}
base_template_class: 'DebugTemplate'
base_template_class: "%kernel.root_dir%/templates/DebugTemplate"
base_template_class: "%kernel.root_dir%\\templates\\DebugTemplate"  
base_template_class: templates\\DebugTemplate

Checking config via console: php bin/console debug:config twig

Current configuration for extension with alias "twig"
=====================================================
twig:
    debug: true
    strict_variables: true
    base_template_class: DebugTemplate
    exception_controller: 'twig.controller.exception:showAction'
    form_themes:
        - form_div_layout.html.twig
    globals: {  }
    autoescape: name
    autoescape_service: null
    autoescape_service_method: null
    cache: /NFS/code/nabc/abc_frontal_service/var/cache/dev/twig
    charset: UTF-8
    default_path: /NFS/code/nabc/abc_frontal_service/templates
    paths: {  }
    date:
        format: 'F j, Y H:i'
        interval_format: '%d days'
        timezone: null
    number_format:
        decimals: 0
        decimal_point: .
        thousands_separator: ','

Using the next config example (others do not generate the cache file): base_template_class: templates\DebugTemplate

It is generated, in cache, a class that tryes to extend the configurated template:

class __TwigTemplate_f3b8c130edb93e6c111c9714c114a4cede8e75482f6253fab3adbfd0ccca6c5e extends \templates\\DebugTemplate

This class is not always renewed when I change the config, so I suppose that what I typed in the config was not considered valid.

So I have two problems:

Upvotes: 1

Views: 814

Answers (2)

Łukasz Zaroda
Łukasz Zaroda

Reputation: 767

base_template_class no longer works with Twig 3, but similar could be achieved in the following way.

src/Twig/DebugExtension.php

<?php

namespace App\Twig;

use Twig\Extension\AbstractExtension;

class DebugExtension extends AbstractExtension {

    public function getNodeVisitors()
    {
        return [new DebugCommenterNodeVisitor()];
    }

}

src/Twig/DebugCommenterNodeVisitor.php

<?php

namespace App\Twig;

use Twig\Environment;
use Twig\Node\BlockNode;
use Twig\Node\BodyNode;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\TextNode;
use Twig\NodeVisitor\AbstractNodeVisitor;

class DebugCommenterNodeVisitor extends AbstractNodeVisitor {

    protected function doEnterNode(Node $node, Environment $env)
    {
        if ($node instanceof ModuleNode) {
            $templateName = $node->getTemplateName();
            $extension = pathinfo($templateName, PATHINFO_EXTENSION);

            $node->setNode('body', new BodyNode([
                new TextNode($this->createComment('BEGIN MODULE TEMPLATE: ' . $templateName, $extension), 0),
                $node->getNode('body'),
                new TextNode($this->createComment('END MODULE TEMPLATE: ' . $templateName, $extension), 0),
            ]));
        }
        elseif ($node instanceof BlockNode) {
            // Bonus helper for form templates and such.
            $name = $node->getAttribute('name');
            $sourceContext = $node->getSourceContext();
            if ($sourceContext) {
                $sourceContextName = $sourceContext->getName();
                // Note that we are skipping anything related to attributes, as we cannot put comments inside the html tags.
                if (!str_contains($name, 'attributes')) {
                    $node->setNode('body', new BodyNode([
                        new TextNode($this->createComment("BEGIN BLOCK TEMPLATE: $name, SOURCE CONTEXT: $sourceContextName"), 0),
                        $node->getNode('body'),
                        new TextNode($this->createComment("END BLOCK TEMPLATE: $name, SOURCE CONTEXT: $sourceContextName"), 0),
                    ]));
                }
            }
        }

        return $node;
    }

    protected function doLeaveNode(Node $node, Environment $env)
    {
        return $node;
    }

    public function getPriority(): int
    {
        return 0;
    }

    private function createComment(string $comment, string $extension = 'html'): string
    {
        return match ($extension) {
            'css', 'js' => '/* ' . $comment . ' */',
            default => '<!-- ' . $comment . ' -->',
        };
    }
}

In the case of not using autowiring, DebugExtension needs to be a service tagged with the twig.extension tag.

Upvotes: 1

LanderTaker
LanderTaker

Reputation: 55

How to do this in Symfony 3.4 (I do not know about other versions), based on Twig - display template names if debug mode is enabled and @DarkBee helping hands!

Steps:

  • Create your template class. Example: src/YourCompany/Application/TWIG/Helper/DebugTemplate.php

     namespace YourCompany\Application\TWIG\Helper;
     use Twig_Template;
    
     abstract class DebugTemplate extends Twig_Template {
         public function display(array $context, array $blocks = array())
         {
             // workaround - only add the html comment when the partial is loaded with @
             if(substr($this->getTemplateName(),0,1) == '@') {
                 echo 'getTemplateName() . ' -->';
             }
    
             $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
    
             if(substr($this->getTemplateName(),0,1) == '@') {
                 echo 'getTemplateName() . ' -->';
             }
    
         }
     }
     
  • go to config.yml. In my project its path is app/config/config.yml. Add the base_template_class setting under the twig section using our new namespace\className as the value. Example:

     ...
    
     # Twig Configuration
     twig:
         debug: '%kernel.debug%'
         strict_variables: '%kernel.debug%'
         base_template_class: YourCompany\Application\TWIG\Helper\DebugTemplate
    
     

Upvotes: 0

Related Questions