Skip to content
Snippets Groups Projects

Issue #3216184: Add HTML comments when Twig debugging is enabled

3 files
+ 165
0
Compare changes
  • Side-by-side
  • Inline
Files
3
+ 138
0
<?php
namespace Drupal\components\Template;
use Twig\Environment;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Node\TextNode;
use Twig\NodeVisitor\NodeVisitorInterface;
/**
* A Twig node visitor that adds debug information around components.
*/
class DebugNodeVisitor implements NodeVisitorInterface {
/**
* The components registry service.
*
* @var \Drupal\components\Template\ComponentsRegistry
*/
protected $componentsRegistry;
/**
* Constructs a new DebugNodeVisitor object.
*
* @param \Drupal\components\Template\ComponentsRegistry $componentsRegistry
* The components registry service.
*/
public function __construct(
ComponentsRegistry $componentsRegistry
) {
$this->componentsRegistry = $componentsRegistry;
}
/**
* {@inheritdoc}
*/
public function enterNode(Node $node, Environment $env): Node {
if (!$env->isDebug()) {
return $node;
}
if (!$node instanceof ModuleNode) {
return $node;
}
if (!$source = $node->getSourceContext()) {
return $node;
}
$name = $source->getName();
$path = $this->getComponentPath($name);
if ($path === NULL) {
return $node;
}
if ($this->isNodeEmpty($node->getNode('body'))) {
// This node is empty.
return $node;
}
$startNodes = [
new TextNode('<!-- THEME DEBUG -->', 0),
new TextNode(sprintf('<!-- COMPONENT: %s -->', $name), 0),
];
if ($name !== $path) {
$startNodes[] = new TextNode(sprintf("<!-- BEGIN OUTPUT from '%s' -->", $path), 0);
}
$node->getNode('display_start')
->setNode('_components_debug', new Node($startNodes));
$endNodes = [
new TextNode(sprintf("<!-- END OUTPUT from '%s' -->", $path), 0),
];
$node->getNode('display_end')
->setNode('_components_debug', new Node($endNodes));
return $node;
}
/**
* {@inheritdoc}
*/
public function leaveNode(Node $node, Environment $env): ?Node {
return $node;
}
/**
* {@inheritdoc}
*/
public function getPriority(): int {
return 0;
}
/**
* Checks whether a template is a component and if so,
* returns the path to the component.
*/
protected function getComponentPath(string $templateName): ?string {
if ($templateName[0] !== '@') {
return NULL;
}
if (strpos(substr($templateName, 2), '/') === FALSE) {
return NULL;
}
$extension = substr($templateName, strrpos($templateName, '.', -1));
if ($extension !== '.twig' && $extension !== '.html' && $extension !== '.svg') {
return NULL;
}
return $this->componentsRegistry->getTemplate($templateName);
}
/**
* Checks whether a node - or one of its subnodes - actually contain something.
*/
protected function isNodeEmpty(Node $node): bool {
$subNodes = iterator_to_array($node);
if (count($subNodes) > 1) {
return FALSE;
}
foreach ($subNodes as $subNode) {
if (!$this->isNodeEmpty($subNode)) {
return FALSE;
}
}
return TRUE;
}
}
Loading